diff --git a/cmake/addr2line_CMakeLists.txt.in b/cmake/addr2line_CMakeLists.txt.in new file mode 100644 index 0000000000..e514764af8 --- /dev/null +++ b/cmake/addr2line_CMakeLists.txt.in @@ -0,0 +1,12 @@ + +# addr2line +ExternalProject_Add(addr2line + GIT_REPOSITORY https://github.com/davea42/libdwarf-addr2line.git + GIT_TAG master + SOURCE_DIR "${TD_CONTRIB_DIR}/addr2line" + BINARY_DIR "${TD_CONTRIB_DIR}/addr2line" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" + ) diff --git a/cmake/cmake.options b/cmake/cmake.options index f32c5acdd1..a60f5c7282 100644 --- a/cmake/cmake.options +++ b/cmake/cmake.options @@ -48,6 +48,12 @@ IF(${TD_WINDOWS}) ENDIF () +option( + BUILD_ADDR2LINE + "If build addr2line" + OFF + ) + option( BUILD_TEST "If build unit tests using googletest" diff --git a/cmake/libdwarf_CMakeLists.txt.in b/cmake/libdwarf_CMakeLists.txt.in new file mode 100644 index 0000000000..7de34cfbaa --- /dev/null +++ b/cmake/libdwarf_CMakeLists.txt.in @@ -0,0 +1,12 @@ + +# libdwarf +ExternalProject_Add(libdwarf + GIT_REPOSITORY https://github.com/davea42/libdwarf-code.git + GIT_TAG libdwarf-0.3.1 + SOURCE_DIR "${TD_CONTRIB_DIR}/libdwarf" + BINARY_DIR "${TD_CONTRIB_DIR}/libdwarf" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" + ) diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt index df69eb8aa1..926fbc8957 100644 --- a/contrib/CMakeLists.txt +++ b/contrib/CMakeLists.txt @@ -98,6 +98,12 @@ if(${BUILD_WITH_NURAFT}) cat("${TD_SUPPORT_DIR}/nuraft_CMakeLists.txt.in" ${CONTRIB_TMP_FILE}) endif(${BUILD_WITH_NURAFT}) +# addr2line +if(${BUILD_ADDR2LINE}) + cat("${TD_SUPPORT_DIR}/libdwarf_CMakeLists.txt.in" ${CONTRIB_TMP_FILE}) + cat("${TD_SUPPORT_DIR}/addr2line_CMakeLists.txt.in" ${CONTRIB_TMP_FILE}) +endif(${BUILD_ADDR2LINE}) + # download dependencies configure_file(${CONTRIB_TMP_FILE} "${TD_CONTRIB_DIR}/deps-download/CMakeLists.txt") execute_process(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" . @@ -327,7 +333,48 @@ if(${BUILD_WITH_SQLITE}) endif(NOT TD_WINDOWS) endif(${BUILD_WITH_SQLITE}) -# pthread +# addr2line +if(${BUILD_ADDR2LINE}) + check_include_file( "sys/types.h" HAVE_SYS_TYPES_H) + check_include_file( "sys/stat.h" HAVE_SYS_STAT_H ) + check_include_file( "inttypes.h" HAVE_INTTYPES_H ) + check_include_file( "stddef.h" HAVE_STDDEF_H ) + check_include_file( "stdlib.h" HAVE_STDLIB_H ) + check_include_file( "string.h" HAVE_STRING_H ) + check_include_file( "memory.h" HAVE_MEMORY_H ) + check_include_file( "strings.h" HAVE_STRINGS_H ) + check_include_file( "stdint.h" HAVE_STDINT_H ) + check_include_file( "unistd.h" HAVE_UNISTD_H ) + check_include_file( "sgidefs.h" HAVE_SGIDEFS_H ) + check_include_file( "stdafx.h" HAVE_STDAFX_H ) + check_include_file( "elf.h" HAVE_ELF_H ) + check_include_file( "libelf.h" HAVE_LIBELF_H ) + check_include_file( "libelf/libelf.h" HAVE_LIBELF_LIBELF_H) + check_include_file( "alloca.h" HAVE_ALLOCA_H ) + check_include_file( "elfaccess.h" HAVE_ELFACCESS_H) + check_include_file( "sys/elf_386.h" HAVE_SYS_ELF_386_H ) + check_include_file( "sys/elf_amd64.h" HAVE_SYS_ELF_AMD64_H) + check_include_file( "sys/elf_sparc.h" HAVE_SYS_ELF_SPARC_H) + check_include_file( "sys/ia64/elf.h" HAVE_SYS_IA64_ELF_H ) + set(VERSION 0.3.1) + set(PACKAGE_VERSION "\"${VERSION}\"") + configure_file(libdwarf/cmake/config.h.cmake config.h) + file(GLOB_RECURSE LIBDWARF_SOURCES "libdwarf/src/lib/libdwarf/*.c") + add_library(libdwarf STATIC ${LIBDWARF_SOURCES}) + set_target_properties(libdwarf PROPERTIES OUTPUT_NAME "libdwarf") + if(HAVE_LIBELF_H OR HAVE_LIBELF_LIBELF_H) + target_link_libraries(libdwarf PUBLIC libelf) + endif() + target_include_directories(libdwarf SYSTEM PUBLIC "libdwarf/src/lib/libdwarf" ${CMAKE_BINARY_DIR}/contrib) + file(READ "addr2line/addr2line.c" ADDR2LINE_CONTENT) + string(REPLACE "static int" "int" ADDR2LINE_CONTENT "${ADDR2LINE_CONTENT}") + string(REPLACE "static void" "void" ADDR2LINE_CONTENT "${ADDR2LINE_CONTENT}") + string(REPLACE "main(" "main_addr2line(" ADDR2LINE_CONTENT "${ADDR2LINE_CONTENT}") + file(WRITE "addr2line/addr2line.c" "${ADDR2LINE_CONTENT}") + add_library(addr2line STATIC "addr2line/addr2line.c") + target_link_libraries(addr2line PUBLIC libdwarf dl z) + target_include_directories(addr2line PUBLIC "libdwarf/src/lib/libdwarf" ) +endif(${BUILD_ADDR2LINE}) # ================================================================================================ diff --git a/include/os/osMemory.h b/include/os/osMemory.h index 92d9319d5c..ba69a32941 100644 --- a/include/os/osMemory.h +++ b/include/os/osMemory.h @@ -35,6 +35,7 @@ void *taosMemoryRealloc(void *ptr, int32_t size); void *taosMemoryStrDup(void *ptr); void taosMemoryFree(void *ptr); int32_t taosMemorySize(void *ptr); +void taosPrintBackTrace(); #define taosMemoryFreeClear(ptr) \ do { \ diff --git a/source/os/CMakeLists.txt b/source/os/CMakeLists.txt index d709bbbcc2..ad6cfc8b95 100644 --- a/source/os/CMakeLists.txt +++ b/source/os/CMakeLists.txt @@ -17,15 +17,25 @@ endif () if(USE_TD_MEMORY) add_definitions(-DUSE_TD_MEMORY) endif () +if(BUILD_ADDR2LINE) + target_include_directories( + os + PUBLIC "${TD_SOURCE_DIR}/contrib/libdwarf/src/lib/libdwarf" + ) + add_definitions(-DUSE_ADDR2LINE) + target_link_libraries( + os PUBLIC addr2line dl z + ) +endif () target_link_libraries( - os pthread + os PUBLIC pthread ) if(NOT TD_WINDOWS) target_link_libraries( - os dl m rt + os PUBLIC dl m rt ) else() target_link_libraries( - os ws2_32 iconv msvcregex wcwidth winmm + os PUBLIC ws2_32 iconv msvcregex wcwidth winmm ) endif(NOT TD_WINDOWS) diff --git a/source/os/src/osMemory.c b/source/os/src/osMemory.c index 73c37c28f7..b1b91699a6 100644 --- a/source/os/src/osMemory.c +++ b/source/os/src/osMemory.c @@ -17,7 +17,7 @@ #include #include "os.h" -#ifdef USE_TD_MEMORY +#if defined(USE_TD_MEMORY) || defined(USE_ADDR2LINE) #define TD_MEMORY_SYMBOL ('T' << 24 | 'A' << 16 | 'O' << 8 | 'S') @@ -71,14 +71,110 @@ int32_t taosBackTrace(void **buffer, int32_t size) { return frame; } -#endif - // char **taosBackTraceSymbols(int32_t *size) { // void *buffer[20] = {NULL}; // *size = taosBackTrace(buffer, 20); // return backtrace_symbols(buffer, *size); // } +#ifdef USE_ADDR2LINE + +#include "osThread.h" +#include "libdwarf.h" +#include "dwarf.h" + +#define DW_PR_DUu "llu" + +typedef struct lookup_table +{ + Dwarf_Line *table; + Dwarf_Line_Context *ctxts; + int cnt; + Dwarf_Addr low; + Dwarf_Addr high; +} lookup_tableT; + +extern int create_lookup_table(Dwarf_Debug dbg, lookup_tableT *lookup_table); +extern void delete_lookup_table(lookup_tableT *lookup_table); + +size_t addr = 0; +lookup_tableT lookup_table; +Dwarf_Debug tDbg; +static TdThreadOnce traceThreadInit = PTHREAD_ONCE_INIT; + +void endTrace() { + delete_lookup_table(&lookup_table); + dwarf_finish(tDbg); +} +void startTrace() { + int ret; + Dwarf_Ptr errarg = 0; + + FILE *fp = fopen("/proc/self/maps", "r"); + fscanf(fp, "%lx-", &addr); + fclose(fp); + + ret = dwarf_init_path("/proc/self/exe", NULL, 0, DW_GROUPNUMBER_ANY, NULL, errarg, &tDbg, NULL); + if (ret == DW_DLV_NO_ENTRY) { + printf("Unable to open file"); + return; + } + + ret = create_lookup_table(tDbg, &lookup_table); + if (ret != DW_DLV_OK) { + printf("Unable to create lookup table"); + return; + } + atexit(endTrace); +} +static void print_line(Dwarf_Debug dbg, Dwarf_Line line, Dwarf_Addr pc) { + char *linesrc = "??"; + Dwarf_Unsigned lineno = 0; + + if (line) { + dwarf_linesrc(line, &linesrc, NULL); + dwarf_lineno(line, &lineno, NULL); + } + printf("%s:%" DW_PR_DUu "\n", linesrc, lineno); + if (line) dwarf_dealloc(dbg, linesrc, DW_DLA_STRING); +} +void taosPrintBackTrace() { + int size = 20; + void **buffer[20]; + Dwarf_Addr pc; + int32_t frame = 0; + void **ebp; + void **ret = NULL; + size_t func_frame_distance = 0; + + taosThreadOnce(&traceThreadInit, startTrace); + + if (buffer != NULL && size > 0) { + ebp = taosGetEbp(); + func_frame_distance = (size_t)*ebp - (size_t)ebp; + while (ebp && frame < size && (func_frame_distance < (1ULL << 24)) && (func_frame_distance > 0)) { + ret = ebp + 1; + buffer[frame++] = *ret; + ebp = (void **)(*ebp); + func_frame_distance = (size_t)*ebp - (size_t)ebp; + } + for (size_t i = 0; i < frame; i++) { + pc = (size_t)buffer[i] - addr; + if (pc > 0) { + if (pc >= lookup_table.low && pc < lookup_table.high) { + Dwarf_Line line = lookup_table.table[pc - lookup_table.low]; + if (line) print_line(tDbg, line, pc); + } + } + } + } +} +#endif +#endif +#endif + +#ifndef USE_ADDR2LINE +void taosPrintBackTrace() { return; } #endif void *taosMemoryMalloc(int32_t size) {