Skip to content

Commit 8c3e89a

Browse files
committed
Check capability for backtrack.
1 parent 1e01f4b commit 8c3e89a

File tree

16 files changed

+398
-343
lines changed

16 files changed

+398
-343
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ The branch [srs](https://github.com/ossrs/state-threads/tree/srs) was patched an
116116
- [x] AppleM1: Support Apple Silicon M1(aarch64), [#30](https://github.com/ossrs/state-threads/issues/30).
117117
- [x] IDE: Support CLion for debugging and learning.
118118
- [x] Define and use a new jmpbuf, because the structure is different.
119+
- [x] Check capability for backtrack.
119120
- [ ] System: Support sendmmsg for UDP, [#12](https://github.com/ossrs/state-threads/issues/12).
120121

121122
## GDB Tools

ide/st_clion/CMakeLists.txt

+58
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ IF (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
4848
list(APPEND SOURCE_FILES ${ST_DIR}/md_darwin.S)
4949
ELSE ()
5050
list(APPEND SOURCE_FILES ${ST_DIR}/md_linux.S)
51+
list(APPEND SOURCE_FILES ${ST_DIR}/md_linux2.S)
5152
ENDIF ()
5253

5354
ADD_DEFINITIONS("-g -O0")
@@ -66,6 +67,63 @@ TARGET_LINK_LIBRARIES(st_utest dl)
6667
TARGET_LINK_LIBRARIES(st_utest ${DEPS_LIBS})
6768
TARGET_LINK_LIBRARIES(st_utest -ldl -pthread)
6869

70+
###########################################################
71+
# Setup tools/backtrace project
72+
set(ST_BACKTRACE_SOURCE_FILES ${SOURCE_FILES})
73+
AUX_SOURCE_DIRECTORY(${ST_DIR}/tools/backtrace ST_BACKTRACE_SOURCE_FILES)
74+
75+
ADD_EXECUTABLE(st_backtrace ${ST_BACKTRACE_SOURCE_FILES})
76+
TARGET_LINK_LIBRARIES(st_backtrace ${DEPS_LIBS})
77+
TARGET_LINK_LIBRARIES(st_backtrace -ldl)
78+
79+
###########################################################
80+
# Setup tools/helloworld project
81+
set(ST_HELLOWORLD_SOURCE_FILES ${SOURCE_FILES})
82+
AUX_SOURCE_DIRECTORY(${ST_DIR}/tools/helloworld ST_HELLOWORLD_SOURCE_FILES)
83+
84+
ADD_EXECUTABLE(st_helloworld ${ST_HELLOWORLD_SOURCE_FILES})
85+
TARGET_LINK_LIBRARIES(st_helloworld ${DEPS_LIBS})
86+
87+
###########################################################
88+
# Setup tools/jmpbuf project
89+
set(ST_JMPBUF_SOURCE_FILES ${SOURCE_FILES})
90+
AUX_SOURCE_DIRECTORY(${ST_DIR}/tools/jmpbuf ST_JMPBUF_SOURCE_FILES)
91+
92+
ADD_EXECUTABLE(st_jmpbuf ${ST_JMPBUF_SOURCE_FILES})
93+
TARGET_LINK_LIBRARIES(st_jmpbuf ${DEPS_LIBS})
94+
95+
###########################################################
96+
# Setup tools/pcs project
97+
set(ST_PCS_SOURCE_FILES ${SOURCE_FILES})
98+
AUX_SOURCE_DIRECTORY(${ST_DIR}/tools/pcs ST_PCS_SOURCE_FILES)
99+
100+
ADD_EXECUTABLE(st_pcs ${ST_PCS_SOURCE_FILES})
101+
TARGET_LINK_LIBRARIES(st_pcs ${DEPS_LIBS})
102+
103+
###########################################################
104+
# Setup tools/porting project
105+
set(ST_PORTING_SOURCE_FILES ${SOURCE_FILES})
106+
AUX_SOURCE_DIRECTORY(${ST_DIR}/tools/porting ST_PORTING_SOURCE_FILES)
107+
108+
ADD_EXECUTABLE(st_porting ${ST_PORTING_SOURCE_FILES})
109+
TARGET_LINK_LIBRARIES(st_porting ${DEPS_LIBS})
110+
111+
###########################################################
112+
# Setup tools/stack project
113+
set(ST_STACK_SOURCE_FILES ${SOURCE_FILES})
114+
AUX_SOURCE_DIRECTORY(${ST_DIR}/tools/stack ST_STACK_SOURCE_FILES)
115+
116+
ADD_EXECUTABLE(st_stack ${ST_STACK_SOURCE_FILES})
117+
TARGET_LINK_LIBRARIES(st_stack ${DEPS_LIBS})
118+
119+
###########################################################
120+
# Setup tools/verify project
121+
set(ST_VERIFY_SOURCE_FILES ${SOURCE_FILES})
122+
AUX_SOURCE_DIRECTORY(${ST_DIR}/tools/verify ST_VERIFY_SOURCE_FILES)
123+
124+
ADD_EXECUTABLE(st_verify ${ST_VERIFY_SOURCE_FILES})
125+
TARGET_LINK_LIBRARIES(st_verify ${DEPS_LIBS})
126+
69127
###########################################################
70128
# Done
71129
MESSAGE(STATUS "@see https://github.com/ossrs/state-threads#usage")

tools/backtrace/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
backtrace

tools/backtrace/Makefile

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
.PHONY: default clean
2+
3+
LDLIBS=../../obj/libst.a -ldl
4+
CFLAGS=-g -O0 -rdynamic -I../../obj
5+
6+
OS_NAME = $(shell uname -s)
7+
ST_TARGET = linux-debug
8+
ifeq ($(OS_NAME), Darwin)
9+
ST_TARGET = darwin-debug
10+
CPU_ARCHS = $(shell g++ -dM -E - </dev/null |grep -q '__x86_64' && echo x86_64)
11+
CPU_ARCHS += $(shell g++ -dM -E - </dev/null |grep -q '__aarch64' && echo arm64)
12+
CFLAGS += -arch $(CPU_ARCHS)
13+
endif
14+
15+
./backtrace: backtrace.c $(LDLIBS)
16+
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -Wall -o $@ $^ $(LDLIBS)
17+
18+
clean:
19+
cd ../.. && make clean
20+
rm -rf backtrace backtrace.dSYM
21+
22+
$(LDLIBS):
23+
cd ../.. && make $(ST_TARGET)
24+

tools/backtrace/backtrace.c

+228
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
/* SPDX-License-Identifier: MIT */
2+
/* Copyright (c) 2013-2022 Winlin */
3+
4+
#ifdef __linux__
5+
#define _GNU_SOURCE
6+
#endif
7+
8+
#include <execinfo.h>
9+
#include <stdio.h>
10+
#include <stdlib.h>
11+
12+
#include <st.h>
13+
14+
#ifdef __linux__
15+
#include <dlfcn.h>
16+
#include <stdio.h>
17+
#include <string.h>
18+
19+
void* parse_symbol_offset(char* frame)
20+
{
21+
char* p = NULL;
22+
char* p_symbol = NULL;
23+
int nn_symbol = 0;
24+
char* p_offset = NULL;
25+
int nn_offset = 0;
26+
27+
// Read symbol and offset, for example:
28+
// /tools/backtrace(foo+0x1820) [0x555555555820]
29+
for (p = frame; *p; p++) {
30+
if (*p == '(') {
31+
p_symbol = p + 1;
32+
} else if (*p == '+') {
33+
if (p_symbol) nn_symbol = p - p_symbol;
34+
p_offset = p + 1;
35+
} else if (*p == ')') {
36+
if (p_offset) nn_offset = p - p_offset;
37+
}
38+
}
39+
if (!nn_symbol && !nn_offset) {
40+
return NULL;
41+
}
42+
43+
// Convert offset(0x1820) to pointer, such as 0x1820.
44+
char tmp[128];
45+
if (!nn_offset || nn_offset >= sizeof(tmp)) {
46+
return NULL;
47+
}
48+
49+
int r0 = EOF;
50+
void* offset = NULL;
51+
tmp[nn_offset] = 0;
52+
if ((r0 = sscanf(strncpy(tmp, p_offset, nn_offset), "%p", &offset)) == EOF) {
53+
return NULL;
54+
}
55+
56+
// Covert symbol(foo) to offset, such as 0x2fba.
57+
if (!nn_symbol || nn_symbol >= sizeof(tmp)) {
58+
return offset;
59+
}
60+
61+
void* object_file;
62+
if ((object_file = dlopen(NULL, RTLD_LAZY)) == NULL) {
63+
return offset;
64+
}
65+
66+
void* address;
67+
tmp[nn_symbol] = 0;
68+
if ((address = dlsym(object_file, strncpy(tmp, p_symbol, nn_symbol))) == NULL) {
69+
dlclose(object_file);
70+
return offset;
71+
}
72+
73+
Dl_info symbol_info;
74+
if ((r0 = dladdr(address, &symbol_info)) == 0) {
75+
dlclose(object_file);
76+
return offset;
77+
}
78+
79+
dlclose(object_file);
80+
return symbol_info.dli_saddr - symbol_info.dli_fbase + offset;
81+
}
82+
83+
char* addr2line_format(void* addr, char* symbol, char* buffer, int nn_buffer)
84+
{
85+
char cmd[512] = {0};
86+
int r0 = snprintf(cmd, sizeof(cmd), "addr2line -C -p -s -f -a -e %s %p", "backtrace", addr - 1);
87+
if (r0 < 0 || r0 >= sizeof(cmd)) return symbol;
88+
89+
FILE* fp = popen(cmd, "r");
90+
if (!fp) return symbol;
91+
92+
char* p = fgets(buffer, nn_buffer, fp);
93+
pclose(fp);
94+
95+
if (p == NULL) return symbol;
96+
if ((r0 = strlen(p)) == 0) return symbol;
97+
98+
// Trait the last newline if exists.
99+
if (p[r0 - 1] == '\n') p[r0 - 1] = '\0';
100+
101+
// Find symbol not match by addr2line, like
102+
// 0x0000000000021c87: ?? ??:0
103+
// 0x0000000000002ffa: _start at ??:?
104+
for (p = buffer; p < buffer + r0 - 1; p++) {
105+
if (p[0] == '?' && p[1] == '?') return symbol;
106+
}
107+
108+
return buffer;
109+
}
110+
#endif
111+
112+
#ifdef __linux__
113+
void bar2()
114+
{
115+
void* addresses[64];
116+
int nn_addresses = backtrace(addresses, sizeof(addresses) / sizeof(void*));
117+
printf("\naddresses:\n");
118+
for (int i = 0; i < nn_addresses; i++) {
119+
printf("%p\n", addresses[i]);
120+
}
121+
122+
char** symbols = backtrace_symbols(addresses, nn_addresses);
123+
printf("\nsymbols:\n");
124+
for (int i = 0; i < nn_addresses; i++) {
125+
printf("%s\n", symbols[i]);
126+
}
127+
128+
char buffer[128];
129+
printf("\nframes:\n");
130+
for (int i = 0; i < nn_addresses; i++) {
131+
void* frame = parse_symbol_offset(symbols[i]);
132+
char* fmt = addr2line_format(frame, symbols[i], buffer, sizeof(buffer));
133+
int parsed = (fmt == buffer);
134+
printf("%p %d %s\n", frame, parsed, fmt);
135+
}
136+
137+
free(symbols);
138+
139+
printf("bar2 OK\n");
140+
return;
141+
}
142+
#endif
143+
144+
int always_use_builtin = 0;
145+
146+
#pragma GCC diagnostic push
147+
#pragma GCC diagnostic ignored "-Wframe-address"
148+
void bar() {
149+
// Each item in the array pointed to by buffer is of type void *, and is the return address from the corresponding
150+
// stack frame.
151+
void* addresses[64];
152+
int nn_addresses = backtrace(addresses, sizeof(addresses) / sizeof(void*));
153+
154+
if (!nn_addresses || always_use_builtin) {
155+
printf("Try to get return addresses by __builtin_return_address\n");
156+
void* p = NULL; nn_addresses = 0;
157+
if ((p = __builtin_return_address(0)) != NULL) {
158+
addresses[nn_addresses++] = p;
159+
if ((p = __builtin_return_address(1)) != NULL) {
160+
addresses[nn_addresses++] = p;
161+
if ((p = __builtin_return_address(2)) != NULL) {
162+
addresses[nn_addresses++] = p;
163+
if ((p = __builtin_return_address(3)) != NULL) {
164+
addresses[nn_addresses++] = p;
165+
if ((p = __builtin_return_address(4)) != NULL) {
166+
addresses[nn_addresses++] = p;
167+
if ((p = __builtin_return_address(5)) != NULL) {
168+
addresses[nn_addresses++] = p;
169+
}
170+
}
171+
}
172+
}
173+
}
174+
}
175+
}
176+
177+
char** symbols = backtrace_symbols(addresses, nn_addresses);
178+
printf("nn_addresses=%d, symbols=%p, symbols[0]=%p\n", nn_addresses, symbols, symbols[0]);
179+
180+
printf("\naddresses:\n");
181+
for (int i = 0; i < nn_addresses; i++) {
182+
printf("%p\n", addresses[i]);
183+
}
184+
185+
printf("\nsymbols:\n");
186+
for (int i = 0; i < nn_addresses; i++) {
187+
printf("%s\n", symbols[i]);
188+
}
189+
free(symbols);
190+
191+
printf("bar OK\n");
192+
return;
193+
}
194+
#pragma GCC diagnostic pop
195+
196+
void foo() {
197+
bar();
198+
#ifdef __linux__
199+
bar2();
200+
#endif
201+
202+
printf("foo OK\n");
203+
return;
204+
}
205+
206+
void* start(void* arg)
207+
{
208+
foo();
209+
210+
printf("coroutine OK\n");
211+
return NULL;
212+
}
213+
214+
int main(int argc, char** argv)
215+
{
216+
if (argc > 1) {
217+
always_use_builtin = 1;
218+
}
219+
220+
st_init();
221+
222+
st_thread_create(start, NULL, 0, 0);
223+
st_thread_exit(NULL);
224+
225+
printf("main done\n");
226+
return 0;
227+
}
228+

tools/helloworld/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ CFLAGS += -arch $(CPU_ARCHS)
1313
endif
1414

1515
./helloworld: helloworld.c $(LDLIBS)
16-
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -Wall -o helloworld helloworld.c $(LDLIBS)
16+
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -Wall -o $@ $^ $(LDLIBS)
1717

1818
clean:
1919
cd ../.. && make clean

tools/helloworld/helloworld.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* SPDX-License-Identifier: MIT */
2-
/* Copyright (c) 2021 Winlin */
2+
/* Copyright (c) 2013-2022 Winlin */
33

44
#include <stdio.h>
55

tools/jmpbuf/.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
jmpbuf
2-
jmpbuf.E.c
2+
jmpbuf.E.txt
33

tools/jmpbuf/Makefile

+4-4
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ CPU_ARCHS += $(shell g++ -dM -E - </dev/null |grep -q '__aarch64' && echo arm64
1212
CFLAGS += -arch $(CPU_ARCHS)
1313
endif
1414

15-
default: ./jmpbuf ./jmpbuf.E.c
15+
default: ./jmpbuf ./jmpbuf.E.txt
1616

1717
./jmpbuf: jmpbuf.c $(LDLIBS)
1818
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -Wall -o $@ $^ $(LDLIBS)
1919

20-
./jmpbuf.E.c: jmpbuf.c
21-
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -Wall -E -o jmpbuf.E.c $^ $(LDLIBS)
20+
./jmpbuf.E.txt: jmpbuf.c
21+
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -Wall -E -o jmpbuf.E.txt $^ $(LDLIBS)
2222

2323
clean:
24-
rm -rf jmpbuf jmpbuf.E.c jmpbuf.dSYM
24+
rm -rf jmpbuf jmpbuf.E.txt jmpbuf.dSYM
2525

0 commit comments

Comments
 (0)