├── .gitignore ├── CMakeLists.txt ├── COPYING ├── CREDITS ├── HOWTO ├── INSTALL ├── NEWS ├── README ├── README.md ├── TODO ├── Utilities.cmake ├── backend.h ├── backtrace.h ├── breakpoint.c ├── breakpoint.h ├── client ├── bfdinc.h ├── binfile.c ├── binfile.h ├── client.c ├── client.h ├── dump.c ├── dump.h ├── job.c ├── job.h ├── process.c ├── process.h ├── readline.c └── readline.h ├── common.c ├── common.h ├── config.h.in ├── config ├── autoconf │ ├── compile │ ├── config.guess │ ├── config.sub │ ├── depcomp │ ├── install-sh │ ├── ltmain.sh │ └── missing └── m4 │ ├── libtool.m4 │ ├── ltoptions.m4 │ ├── ltsugar.m4 │ ├── ltversion.m4 │ └── lt~obsolete.m4 ├── debian ├── changelog ├── compat ├── control ├── copyright ├── rules └── source │ └── format ├── debug.c ├── debug.h ├── dict.c ├── dict.h ├── dwarf.c ├── dwarf.h ├── event.c ├── event.h ├── forward.h ├── library.c ├── library.h ├── list.h ├── main.c ├── main.h ├── memtrace.h ├── mtelf.c ├── mtelf.h ├── mtrace-ng.1 ├── mtrace-ng.conf.5 ├── mtrace.h ├── options.c ├── options.h ├── rbtree.c ├── rbtree.h ├── report.c ├── report.h ├── server.c ├── server.h ├── sysdeps ├── linux-gnu │ ├── arm │ │ ├── arch.c │ │ ├── arch.h │ │ ├── cpu.cmake │ │ ├── dwarf-arm.c │ │ └── regs.c │ ├── ioevent.c │ ├── ioevent.h │ ├── os.c │ ├── os.h │ ├── ppc │ │ ├── arch.c │ │ ├── arch.h │ │ ├── cpu.cmake │ │ ├── dwarf-ppc.c │ │ └── regs.c │ ├── proc.c │ ├── socket.c │ ├── socket.h │ ├── sysdeps.cmake │ ├── thread.c │ ├── trace.c │ └── x86 │ │ ├── arch.c │ │ ├── arch.h │ │ ├── cpu.cmake │ │ ├── dwarf-x86.c │ │ └── regs.c └── sysdep.h ├── task.c ├── task.h ├── thread.h ├── timer.h ├── trace.c └── trace.h /.gitignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.o 3 | *.o.* 4 | *.a 5 | *.s 6 | *.so 7 | *.lo 8 | *.la 9 | *.log 10 | *.lst 11 | *.symtypes 12 | *.elf 13 | *.bin 14 | *.gz 15 | *.bz2 16 | *.lzma 17 | *.xz 18 | *.lz4 19 | *.lzo 20 | *.patch 21 | *.gcno 22 | *.orig 23 | *.save 24 | *~ 25 | Makefile 26 | config.h 27 | config.status 28 | stamp-h1 29 | libtool 30 | docross 31 | doremote 32 | dokvm 33 | dosmw 34 | mtrace-ng 35 | debian/files 36 | debian/mtrace-ng.substvars 37 | debian/mtrace-ng 38 | tags 39 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | set(MT "mtrace-ng") 3 | project(${MT} C) 4 | 5 | set(MT_VERSION_STRING "0.8.2") 6 | 7 | option(DISABLE_CLIENT "whether to disable client support" OFF) 8 | 9 | set(default_build_type "Release") 10 | if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 11 | set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose type of build" FORCE) 12 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS 13 | "Debug" "Release" "LTO") 14 | endif() 15 | 16 | include(CheckFunctionExists) 17 | include(CheckIncludeFile) 18 | include(CheckIncludeFiles) 19 | include(CheckSymbolExists) 20 | 21 | include(${CMAKE_SOURCE_DIR}/Utilities.cmake) 22 | 23 | SET(C_SRCS 24 | breakpoint.c 25 | common.c 26 | debug.c 27 | dict.c 28 | dwarf.c 29 | event.c 30 | library.c 31 | main.c 32 | mtelf.c 33 | options.c 34 | rbtree.c 35 | report.c 36 | server.c 37 | task.c 38 | trace.c 39 | ) 40 | 41 | include_directories( 42 | "${PROJECT_BINARY_DIR}" 43 | "${PROJECT_SOURCE_DIR}" 44 | "${PROJECT_SOURCE_DIR}/sysdeps" 45 | ) 46 | 47 | set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0 -fno-omit-frame-pointer -fsanitize=address -fsanitize=undefined -D__FORITFY_SOURCE=2 -rdynamic -DDEBUG") 48 | set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address -fsanitize=undefined") 49 | 50 | set(CMAKE_C_FLAGS_LTO "${CMAKE_C_FLAGS_RELEASE} -flto") 51 | set(CMAKE_EXE_LINKER_FLAGS_LTO "${CMAKE_LINKER_FLAGS_RELEASE} -flto") 52 | 53 | add_compile_options(-Wall -Wextra) 54 | 55 | if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 7) 56 | add_compile_options(-Wno-implicit-fallthrough) 57 | endif() 58 | 59 | if (NOT DISABLE_CLIENT) 60 | SET(C_SRCS 61 | ${C_SRCS} 62 | client/binfile.c 63 | client/client.c 64 | client/dump.c 65 | client/job.c 66 | client/process.c 67 | client/readline.c 68 | ) 69 | 70 | include_directories( 71 | "${PROJECT_SOURCE_DIR}/client" 72 | ) 73 | endif() 74 | 75 | target_architecture(TARGET_ARCH) 76 | if (TARGET_ARCH) 77 | message(STATUS "target architecture is ${TARGET_ARCH}") 78 | else() 79 | message(FATAL_ERROR "unknown target architecture") 80 | endif() 81 | 82 | if (TARGET_ARCH MATCHES "x86|x86_64") 83 | set(MT_CPU "x86") 84 | elseif (TARGET_ARCH MATCHES "arm") 85 | set(MT_CPU "arm") 86 | elseif (TARGET_ARCH MATCHES "powerpc") 87 | set(MT_CPU "ppc") 88 | else() 89 | message(FATAL_ERROR "unsuported target architecture: ${TARGET_ARCH}") 90 | endif() 91 | 92 | target_os(TARGET_OS) 93 | if (TARGET_OS) 94 | message(STATUS "target OS is ${TARGET_OS}") 95 | else() 96 | message(FATAL_ERROR "unknown target OS: ${TARGET_OS}") 97 | endif() 98 | 99 | if (TARGET_OS STREQUAL "linux") 100 | set(MT_OS "linux-gnu") 101 | else() 102 | message(FATAL_ERROR "unsuported target os ${TARGET_OS}") 103 | endif() 104 | 105 | find_package(PkgConfig REQUIRED) 106 | pkg_check_modules(LIB_ELF REQUIRED libelf) 107 | 108 | find_and_test_library(LIB_PTHREAD pthread "pthread.h" "pthread_create") 109 | 110 | set(CMAKE_REQUIRED_DEFINITIONS "-D_GNU_SOURCE") 111 | find_and_test_library(LIB_DL dl "dlfcn.h" dladdr) 112 | unset(CMAKE_REQUIRED_DEFINITIONS) 113 | 114 | find_and_test_library(LIB_RT rt "time.h" "clock_gettime") 115 | 116 | if (NOT DISABLE_CLIENT) 117 | set(CURSES_NEED_NCURSES TRUE) 118 | find_package(Curses REQUIRED) 119 | 120 | find_and_test_library(LIB_READLINE readline "stdio.h;readline/readline.h" "rl_callback_read_char") 121 | 122 | set(CMAKE_REQUIRED_DEFINITIONS "-DPACKAGE_VERSION=${MT_VERSION_STRING} -DPACKAGE=1") 123 | find_library(LIB_BFD bfd) 124 | if(NOT LIB_BFD) 125 | message(FATAL_ERROR "libbfd not found.") 126 | endif() 127 | 128 | find_library(LIB_IBERTY iberty) 129 | if(NOT LIB_IBERTY) 130 | message(FATAL_ERROR "liberty not found.") 131 | endif() 132 | 133 | pkg_check_modules(LIB_ZLIB REQUIRED zlib) 134 | 135 | CHECK_INCLUDE_FILES_ERROR("termcap.h" HAVE_TERMCAP_H) 136 | 137 | endif() 138 | 139 | check_function_exists(process_vm_readv HAVE_PROCESS_VM_READV) 140 | 141 | configure_file( 142 | "${PROJECT_SOURCE_DIR}/config.h.in" 143 | "${PROJECT_BINARY_DIR}/config.h" 144 | ) 145 | 146 | include(${CMAKE_SOURCE_DIR}/sysdeps/${MT_OS}/sysdeps.cmake) 147 | 148 | if (LIB_ELF_INCLUDE_DIRS) 149 | include_directories("${LIB_ELF_INCLUDE_DIRS}") 150 | endif() 151 | 152 | add_executable(${MT} ${C_SRCS}) 153 | target_link_libraries(${MT} ${LIB_ELF_LIBRARIES} ${LIB_PTHREAD} ${LIB_DL} ${LIB_RT} ${LIB_READLINE}) 154 | if(LIB_BFD) 155 | target_compile_options(${MT} PRIVATE -DPACKAGE) 156 | target_link_libraries(${MT} ${LIB_BFD} ${LIB_ZLIB_LIBRARIES} ${LIB_IBERTY}) 157 | endif() 158 | target_compile_options(${MT} PUBLIC ${LIB_ELF_CFLAGS_OTHER}) 159 | 160 | install(TARGETS ${PROJECT_NAME} DESTINATION bin/) 161 | install(FILES ${MT}.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 COMPONENT doc) 162 | install(FILES ${MT}.conf.5 DESTINATION ${CMAKE_INSTALL_MANDIR}/man5 COMPONENT doc) 163 | 164 | #echo_all_cmake_variable_values() 165 | 166 | -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | the source is based on 2 | ltrace http://ltrace.org/ 3 | libunwind http://www.nongnu.org/libunwind/ 4 | linux https://kernel.org/ 5 | -------------------------------------------------------------------------------- /HOWTO: -------------------------------------------------------------------------------- 1 | The easiest way for using mtrace-ng is simply run a program under the control of mtrace-ng: 2 | 3 | mtrace-ng -t -d 10 a.out 4 | 5 | This will run a.out and records all memory allocations. When the program exits or mtrace-ng is terminated, it dumps all open memory allocations for each different stack backtrace: 6 | 7 | . 8 | . 9 | . 10 | Stack (mmap): 11 | bytes used: 8392704 12 | number of open allocations: 1 13 | total number of allocations: 1 14 | tsc: 4 15 | [0x7f9e207abfd7] /lib64/libpthread.so.0 pthread_create 16 | [0x4010e0] /home/stefani/mt/test/x.c:128 test 17 | [0x40126a] /home/stefani/mt/test/x.c:189 main 18 | [0x7f9e20427b55] /lib64/libc.so.6 __libc_start_main 19 | [0x400b89] /home/stefani/mt/test/a.out _start 20 | Stack (malloc): 21 | bytes used: 4800 22 | number of open allocations: 8 23 | total number of allocations: 30 24 | tsc: 75 25 | [0x400dee] /home/stefani/mt/test/x.c:56 ThreadFuncA 26 | [0x7f9e207ab3a4] /lib64/libpthread.so.0 __pthread_get_minstack 27 | [0x7f9e204ee18d] /lib64/libc.so.6 clone 28 | 29 | In this case you see for the last stack backtrace which calls malloc() by function ThreadFuncA in file /home/stefani/mt/test/x.c at line 56, which has 8 open allocations using a total of 4800 bytes. 30 | 31 | The default sort order is "allocations", which sorts the output by the number of open allocations. The lowest value is printed out first and the highest value at last. So the most interesting values are always in view. If you wish a different sort order und can pass a -S option, for example. 32 | 33 | mtrace-ng -t -d 10 -s usage a.out 34 | 35 | This will sort by the total sum of bytes used: 36 | 37 | Stack (malloc): 38 | bytes used: 288 39 | number of open allocations: 1 40 | total number of allocations: 1 41 | tsc: 1 42 | [0x7ff0ca5562e2] /lib64/ld-linux-x86-64.so.2 _dl_mcount 43 | [0x7ff0ca556a8e] /lib64/ld-linux-x86-64.so.2 _dl_allocate_tls 44 | [0x7ff0c990c069] /lib64/libpthread.so.0 pthread_create 45 | [0x401022] /home/stefani/mt/test/x.c:107 test 46 | [0x40126a] /home/stefani/mt/test/x.c:189 main 47 | [0x7ff0c9587b55] /lib64/libc.so.6 __libc_start_main 48 | [0x400b89] /home/stefani/mt/test/a.out _start 49 | . 50 | . 51 | . 52 | Stack (mmap): 53 | bytes used: 8392704 54 | number of open allocations: 1 55 | total number of allocations: 1 56 | tsc: 2 57 | [0x7ff0c990bfd7] /lib64/libpthread.so.0 pthread_create 58 | [0x401081] /home/stefani/mt/test/x.c:117 test 59 | [0x40126a] /home/stefani/mt/test/x.c:189 main 60 | [0x7ff0c9587b55] /lib64/libc.so.6 __libc_start_main 61 | [0x400b89] /home/stefani/mt/test/a.out _start 62 | Stack (mmap): 63 | bytes used: 8392704 64 | number of open allocations: 1 65 | total number of allocations: 1 66 | tsc: 4 67 | [0x7ff0c990bfd7] /lib64/libpthread.so.0 pthread_create 68 | [0x4010e0] /home/stefani/mt/test/x.c:128 test 69 | [0x40126a] /home/stefani/mt/test/x.c:189 main 70 | [0x7ff0c9587b55] /lib64/libc.so.6 __libc_start_main 71 | [0x400b89] /home/stefani/mt/test/a.out _start 72 | 73 | So you can see that the last two stack backtraces both called mmap() from inside the pthread_create() function. But since there are two different backtrace stacks there will be not merged together (the first on is called by x.c:117 and the other by x.c:128). Lets assume for the above example the stack backtrace depth is set (to the not really useful) value of 1, then mtrace-ng would output: 74 | 75 | Stack (mmap): 76 | bytes used: 16785408 77 | number of open allocations: 2 78 | total number of allocations: 2 79 | tsc: 4 80 | [0x7ff0c990bfd7] /lib64/libpthread.so.0 pthread_create 81 | 82 | In this case it is not possible to identifiy which function has been called pthread_create() and some important informations get lost. So it always reasonable to use a stack depth which allows to distinguish the callers. For C programs a depth value of 10 is recommended and for C++ a minimum of 20 is useful. 83 | 84 | It is also possible to write the output to a file instead to stderr, for example: 85 | 86 | mtrace-ng -t -d 10 -o /tmp/mtrace-ng.out a.out 87 | 88 | In this case the dump will written to /tmp/mtrace-ng.out after the program exits or mtrace-ng is terminated. Note that in the case the sort order is inverted, the highest value is written first to the file and the lowest value at last. So the most interesting values are always in view when opening the file with an editor. 89 | 90 | It is also possible to attach to an already running program: 91 | 92 | mtrace-ng -t -d 10 -o /tmp/mtrace-ng.out -p $(pidof -s a.out) 93 | 94 | This is e.g. useful when you not want do trace the whole startup of the program or you want to test only a specific function of a program. Imaging a test scenario where a leak is assumed. So attached mtrace-ng, run the tests (more then once is better) and then terminated mtrace-ng by Ctrl-C. One of last dump stack backtraces should show the culprit. 95 | 96 | A more sophisticate way to find a memory leak is to scan for lost pointer values, e.g. 97 | 98 | mtrace-ng -a -s leaks -d 10 -o /tmp/mtrace-ng.out -p $(pidof -s a.out) 99 | 100 | After attach and run the tests and terminating mtrace-ng by Ctrl-C, the memory will be scanned for lost pointer. The dump output will then sorted by the number of leaked allocations: 101 | 102 | process 12166 scanning 18 allocations 103 | process 12166 104 | leaks reported: 15 105 | new leaks found: 15 106 | leaked bytes: 8064 107 | leaked at 0x02030010 (288 bytes) 108 | leaked at 0x02030140 (288 bytes) 109 | leaked at 0x02030270 (288 bytes) 110 | leaked at 0x7fb4740008c0 (0 bytes) 111 | leaked at 0x7fb4740008e0 (400 bytes) 112 | leaked at 0x7fb474000a80 (800 bytes) 113 | leaked at 0x7fb474000db0 (1200 bytes) 114 | leaked at 0x7fb474001270 (0 bytes) 115 | leaked at 0x7fb474001290 (400 bytes) 116 | leaked at 0x7fb474001430 (800 bytes) 117 | leaked at 0x7fb474001760 (1200 bytes) 118 | leaked at 0x7fb474001c20 (0 bytes) 119 | leaked at 0x7fb474001c40 (400 bytes) 120 | leaked at 0x7fb474001de0 (800 bytes) 121 | leaked at 0x7fb474002110 (1200 bytes) 122 | leaks total: 15 123 | . 124 | . 125 | . 126 | Stack (malloc): 127 | bytes used: 288 128 | number of open allocations: 1 129 | total number of allocations: 1 130 | leaked allocations: 1 (288 bytes) 131 | tsc: 6 132 | [0x7fb47aae72e2] /lib64/ld-linux-x86-64.so.2 _dl_mcount 133 | [0x7fb47aae7a8e] /lib64/ld-linux-x86-64.so.2 _dl_allocate_tls 134 | [0x7fb479e9d069] /lib64/libpthread.so.0 pthread_create 135 | [0x4010e0] /home/stefani/mt/test/x.c:128 test 136 | [0x40126a] /home/stefani/mt/test/x.c:189 main 137 | [0x7fb479b18b55] /lib64/libc.so.6 __libc_start_main 138 | [0x400b89] /home/stefani/mt/test/a.out _start 139 | Stack (malloc): 140 | bytes used: 7200 141 | number of open allocations: 12 142 | total number of allocations: 45 143 | leaked allocations: 12 (7200 bytes) 144 | tsc: 110 145 | [0x400dee] /home/stefani/mt/test/x.c:56 ThreadFuncA 146 | [0x7fb479e9c3a4] /lib64/libpthread.so.0 __pthread_get_minstack 147 | [0x7fb479bdf18d] /lib64/libc.so.6 clone 148 | 149 | So you can see there are 15 leaked pointer in this case and the main culprit is a malloc() called from ThreadFuncA(). 150 | 151 | When no C++ Code is traced or when using the libstdc++ (which calls malloc() and free() inside the allocation operators), the breakpoints for the C++ allocators can be omitted by the --nocpp option. This increases the trace performance. 152 | 153 | There is also a server mode and a client with an command line interface. This is useful when you want get information during the runtime 154 | of a program, for example: 155 | 156 | mtrace-ng -f -r 0.0.0.0 -w -s -d 10 a.out 157 | 158 | This start the client waiting for a client connection before running the program a.out. 159 | 160 | Then you can connect the client using an other terminal or on an other computer: 161 | 162 | mtrace-ng -r 127.0.0.1 163 | memtrace info: 164 | follow fork: no 165 | follow exec: no 166 | verbose: no 167 | do trace: yes 168 | stack depth: 10 169 | mtrace> 170 | 171 | No you can ask for help with the command "help", or dump the current state of the bookkeeping by using the command "dump". 172 | 173 | For more information about the interactive mode see the manual page mtrace-ng(1) section INTERACTIVE MODE. 174 | 175 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sstefani/mtrace/237bf3aa6061a6d32f66bad0214d2d89253d3228/NEWS -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | README.md -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Mtrace 2 | ------ 3 | 4 | mtrace-ng is a dynamic memory tracer, debugger and statistical analyses tool for C and C++, which intercepts, records and reports all kinds of dynamic memory allocations. 5 | 6 | It supports the developer to get statistics about the memory usage and finding memory leaks in an arbitrate program. Since mtrace-ng is using breakpoints for tracing the program, there is no need of modification of the source code nor any recompilation. 7 | 8 | The mtrace-ng utility intercepts the following library calls: 9 | 10 | void *malloc(size_t size); 11 | void free(void *ptr); 12 | void *calloc(size_t nmemb, size_t size); 13 | void *realloc(void *ptr, size_t size); 14 | int posix_memalign(void **memptr, size_t alignment, size_t size); 15 | void *aligned_alloc(size_t alignment, size_t size); 16 | void *valloc(size_t size); 17 | void *memalign(size_t alignment, size_t size); 18 | void *pvalloc(size_t size); 19 | void cfree(void *ptr); 20 | void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); 21 | void *mmap64(void *addr, size_t length, int prot, int flags, int fd, off_t offset); 22 | int munmap(void *addr, size_t length); 23 | void *mremap(void *old_address, size_t old_size, size_t new_size, int flags, ... /* void *new_address */); 24 | 25 | void *operator new(size_t size) throw (std::bad_alloc) 26 | void *operator new(size_t size, const std::nothrow_t& nt) __THROW 27 | void *operator new[](size_t size) throw (std::bad_alloc) 28 | void *operator new[](size_t size, const std::nothrow_t& nt) __THROW 29 | void operator delete(void* p) __THROW 30 | void operator delete(void* p, const std::nothrow_t& nt) __THROW 31 | void operator delete[](void* p) __THROW 32 | void operator delete[](void* p, const std::nothrow_t& nt) __THROW 33 | 34 | 35 | For each allocation a backtrace will be recorded. This backtrace allows to trace and identify the callers of an allocation function. The depth of this backtrace could be set by the -d option. Identical backtraces will be handled as one caller, since there is no way to distinguish the callers. 36 | 37 | Unlike other dynamic memory tracer, mtrace-ng is able to find no longer referenced memory allocation by scanning all writable memory mappings of the program against the pointer values of the allocations. If a pointer value of an open allocated memory block will not found on any aligned memory addresses, it will be marked and reported as leaked. The scan can take some time, depending on the size of the writeable memory mappings and the number of open allocations. 38 | 39 | The mtrace-ng utility was designed to run in a very constrained environment, like small embedded systems. This is one of the reasons for a client/server architecture. The server runs on the target side and the interactive client runs on the host side, the communication is done via TCP. If server and client running on the same machine then the communication can be done via UNIX Domain Socket. Both sides can run on different architectures, address sizes and endianness, but for tracing 64 bit programs the client must be compiled as a 64 bit program. On the host side all binaries (including debug information) must be accessible, there is no need for debug information on the target side. 40 | 41 | 42 | mtrace-ng offers different kind of working modes. A non interactive mode, a server mode and a interactive client mode. 43 | 44 | Non interactive mode 45 | -------------------- 46 | The most common mode is the non interactive mode, which allows to run and/or attach to a process, similar to strace. mtrace-ng will show all open allocations when the traced program exists or mtrace-ng will be terminated. 47 | 48 | Server mode 49 | ----------- 50 | For system with memory restrictions or for using in a cross architecture environment, mtrace-ng offers a server mode which moves the memory bookkeeping and address resolution outside to a connected client. In this case the server must be started on target system where the program is executed. Then the client has to be started on the remote host system. 51 | 52 | Interactive client mode 53 | ----------------------- 54 | To get a more detailed information about the dynamic memory consumption mtrace-ng can be started in an interactive mode. This mode is available for client mode or when attaching to a process. See the section INTERACTIVE MODE of the manual page mtrace-ng(1) to learn more about the interactive commands in mtrace-ng. 55 | 56 | 57 | Restrictions 58 | ------------ 59 | There is currently support for X86 (32 and 64 Bit), PowerPC (32 Bit) and ARM (32 Bit, no Thumb support). Only Linux is yet supported, but there are plans to support different operating systems and CPU's. 60 | 61 | Thanks 62 | ------ 63 | 64 | The development of this tool was financial supported and sponsored by 65 | Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 66 | 67 | About the author 68 | ---------------- 69 | 70 | Stefani Seibold 71 | Work and life in Munich/Germany 72 | Freelancer 73 | Linux Kernel Hacker (KFIFO, VDSO32 for x86) 74 | Linux Kernel Drivers 75 | System-, Embedded- and Realtime-Programmer 76 | Email: stefani@seibold.net 77 | 78 | 6. July 2015 79 | Munich, Germany 80 | 81 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | ppc single step enhancement 2 | arm thumb support 3 | dwarf debug support 4 | arm & ppc hw bp support 5 | invalid stack trace cache for unmapped libraries 6 | mremap revamp 7 | -------------------------------------------------------------------------------- /Utilities.cmake: -------------------------------------------------------------------------------- 1 | function(target_architecture output_var) 2 | 3 | set(archdetect_c_code " 4 | #if defined(__arm__) || defined(__TARGET_ARCH_ARM) || defined(_M_ARM) 5 | #error cmake_ARCH arm 6 | #elif defined(__aarch64__) || defined(_M_ARM64) 7 | #error cmake_ARCH aarch64 8 | #elif defined(__i386) || defined(__i386__) || defined(_M_IX86) 9 | #error cmake_ARCH x86 10 | #elif defined(__x86_64) || defined(x__x86_64__) || defined(__amd64) || defined(_M_X64) 11 | #error cmake_ARCH x86_64 12 | #elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64) 13 | #error cmake_ARCH ia64 14 | #elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) || defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) || defined(_M_MPPC) || defined(_M_PPC) 15 | #if defined(__ppc64__) || defined(__powerpc64__) || defined(__64BIT__) 16 | #error cmake_ARCH ppc64 17 | #else 18 | #error cmake_ARCH ppc 19 | #endif 20 | #elif defined(__mips64) 21 | #error cmake_ARCH mips64 22 | #elif defined(__mips) 23 | #error cmake_ARCH mips 24 | #endif 25 | 26 | #error cmake_ARCH unknown 27 | ") 28 | 29 | set(F "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/_test_.c") 30 | 31 | file(WRITE ${F} "${archdetect_c_code}") 32 | 33 | enable_language(C) 34 | 35 | try_run( 36 | run_result_unused 37 | compile_result_unused 38 | "${CMAKE_BINARY_DIR}" 39 | "${F}" 40 | COMPILE_OUTPUT_VARIABLE ARCH 41 | CMAKE_FLAGS CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES} 42 | ) 43 | file(REMOVE "${F}" "${osdetect_c_code}") 44 | 45 | string(REGEX MATCH "cmake_ARCH ([a-zA-Z0-9_]+)" ARCH "${ARCH}") 46 | 47 | string(REPLACE "cmake_ARCH " "" ARCH "${ARCH}") 48 | 49 | if (NOT ARCH) 50 | set(ARCH unknown) 51 | endif() 52 | 53 | set(${output_var} "${ARCH}" PARENT_SCOPE) 54 | endfunction() 55 | 56 | function(target_os output_var) 57 | 58 | set(osdetect_c_code " 59 | #if defined(_WIN32) || defined(_WIN64) 60 | #error cmake_OS windows 61 | #elif defined(__linux) || defined(__linux__) || defined(__gnu_linux__) 62 | #error cmake_OS linux 63 | #elif defined(__APPLE__) && defined(TARGET_OS_MAC) 64 | #error cmake_OS osx 65 | #elif defined(__unix__) 66 | #error cmake_OS unix 67 | #endif 68 | 69 | #error cmake_ARCH unknown 70 | ") 71 | 72 | set(F "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/_test_.c") 73 | 74 | file(WRITE ${F} "${osdetect_c_code}") 75 | 76 | enable_language(C) 77 | 78 | try_run( 79 | run_result_unused 80 | compile_result_unused 81 | "${CMAKE_BINARY_DIR}" 82 | "${F}" 83 | COMPILE_OUTPUT_VARIABLE OS 84 | CMAKE_FLAGS CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES} 85 | ) 86 | file(REMOVE "${F}" "${osdetect_c_code}") 87 | 88 | string(REGEX MATCH "cmake_OS ([a-zA-Z0-9_]+)" OS "${OS}") 89 | 90 | string(REPLACE "cmake_OS " "" OS "${OS}") 91 | 92 | if (NOT OS) 93 | set(OS unknown) 94 | endif() 95 | 96 | set(${output_var} "${OS}" PARENT_SCOPE) 97 | endfunction() 98 | 99 | macro(CHECK_INCLUDE_FILES_ERROR INCLUDE_FILES HAVE_FILE) 100 | CHECK_INCLUDE_FILES("${INCLUDE_FILES}" ${HAVE_FILE}) 101 | IF(NOT ${HAVE_FILE}) 102 | message(FATAL_ERROR "${INCLUDE_FILE} not found") 103 | ENDIF() 104 | endmacro() 105 | 106 | function(find_library_error VAR LIB) 107 | find_library(${VAR} ${LIB}) 108 | IF (NOT ${VAR}) 109 | message(FATAL_ERROR "lib ${LIB} not found") 110 | ENDIF() 111 | endfunction() 112 | 113 | function(find_and_test_library VAR LIB INCLUDES SYM) 114 | find_library_error(${VAR} "${LIB}") 115 | CHECK_INCLUDE_FILES_ERROR("${INCLUDES}" _HAVE_FILE) 116 | set(CMAKE_REQUIRED_LIBRARIES "${${VAR}}") 117 | set(HAVE_SYM "_HAVE_SYM_${SYM}") 118 | check_symbol_exists("${SYM}" "${INCLUDES}" ${HAVE_SYM}) 119 | IF (NOT ${HAVE_SYM}) 120 | message(FATAL_ERROR "symbol ${SYM} not found in library ${LIB}") 121 | endif() 122 | endfunction() 123 | 124 | 125 | function(echo_all_cmake_variable_values) 126 | get_cmake_property(vs VARIABLES) 127 | foreach(v ${vs}) 128 | message(STATUS "${v}='${${v}}'") 129 | endforeach(v) 130 | endfunction() 131 | 132 | -------------------------------------------------------------------------------- /backend.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_BACKEND_H 24 | #define _INC_BACKEND_H 25 | 26 | #include "config.h" 27 | 28 | #include "arch.h" 29 | #include "os.h" 30 | #include "forward.h" 31 | #include "mtrace.h" 32 | 33 | #include 34 | #include 35 | 36 | /* Convert a pid to a path to the corresponding binary. */ 37 | char *pid2name(pid_t pid); 38 | 39 | /* return the cwd of a pid. */ 40 | char *pid2cwd(pid_t pid); 41 | 42 | /* Given a pid, find a leader of thread group. */ 43 | pid_t process_leader(pid_t pid); 44 | 45 | /* Given a pid of leader thread, fill in pids of all the tasks. The 46 | * function will initialize the pointer *ret_tasks to a 47 | * newly-allocated array, and will store number of elements in that 48 | * array to *ret_n. You have to free that buffer when you don't need 49 | * it anymore. */ 50 | int process_tasks(pid_t pid, pid_t **ret_tasks, size_t *ret_n); 51 | 52 | /* set tracing options, the task must be in state traced */ 53 | int trace_set_options(struct task *task); 54 | 55 | /* make the forked process traceable */ 56 | void trace_me(void); 57 | 58 | /* stop tracing of a task. */ 59 | int untrace_task(struct task *task); 60 | 61 | /* Called when mtrace-ng needs to attach to task */ 62 | int trace_attach(struct task *task); 63 | 64 | /* wait for a task ready for tracing */ 65 | int trace_wait(struct task *task); 66 | 67 | /* continue process */ 68 | int continue_task(struct task *task, int signum); 69 | 70 | /* Return current instruction pointer */ 71 | arch_addr_t get_instruction_pointer(struct task *task); 72 | 73 | /* Set instruction pointer of task to addr */ 74 | void set_instruction_pointer(struct task *task, arch_addr_t addr); 75 | 76 | /* do a single step */ 77 | int do_singlestep(struct task *task, struct breakpoint *bp); 78 | 79 | /* handle a single step event */ 80 | int handle_singlestep(struct task *task, int (*singlestep)(struct task *task), struct breakpoint *bp); 81 | 82 | /* Find and return caller address, i.e. the address where the current 83 | * function returns. */ 84 | arch_addr_t get_return_addr(struct task *task); 85 | 86 | /* get address of IP register */ 87 | unsigned int ip_reg_addr(void); 88 | 89 | #if HW_BREAKPOINTS > 0 90 | /* returns true if the hw breakpoint is pendig */ 91 | int get_hw_bp_state(struct task *task, unsigned int n); 92 | 93 | /* set instruction hw breakpoint */ 94 | int set_hw_bp(struct task *task, unsigned int n, arch_addr_t addr); 95 | 96 | /* remove instruction hw breakpoint */ 97 | int reset_hw_bp(struct task *task, unsigned int n); 98 | 99 | /* remove all instruction hw breakpoints */ 100 | int reset_all_hw_bp(struct task *task); 101 | #endif 102 | 103 | /* save the process context (state, registers, stack pointer) */ 104 | int fetch_context(struct task *task); 105 | 106 | /* save the process context for parameter fetching */ 107 | void save_param_context(struct task *task); 108 | 109 | /* get return value of a remote function */ 110 | unsigned long fetch_retval(struct task *task); 111 | 112 | /* get parameter value of a remote function */ 113 | unsigned long fetch_param(struct task *task, unsigned int param); 114 | 115 | /* get register value of a remote function */ 116 | unsigned long fetch_reg(struct task *task, unsigned int reg); 117 | 118 | /* Should copy len bytes from address addr of task to local buffer dst */ 119 | ssize_t copy_from_proc(struct task *task, arch_addr_t addr, void *dst, size_t len); 120 | 121 | /* Should copy len bytes from local buffer src to address addr of the remote task */ 122 | ssize_t copy_to_proc(struct task *task, arch_addr_t addr, const void *src, size_t len); 123 | 124 | /* Should copy len bytes from address addr of remote task to local 125 | * buffer dst and overwrite the task data with src */ 126 | ssize_t copy_from_to_proc(struct task *task, arch_addr_t addr, const void *src, void *dst, size_t len); 127 | 128 | /* Should copy max. len of a string from address addr from the remote task 129 | * to local buffer dst */ 130 | ssize_t copy_str_from_proc(struct task *task, arch_addr_t addr, char *dst, size_t len); 131 | 132 | /* Called at some point after we have attached to the process. This callback 133 | * should insert an introspection breakpoint for handling dynamic linker 134 | * library loads. */ 135 | int linkmap_init(struct task *task, arch_addr_t dyn_addr); 136 | 137 | /* This should extract entry point address and interpreter (dynamic 138 | * linker) bias if possible. Returns 0 if there were no errors, -1 139 | * otherwise. Sets *entryp and *interp_biasp to non-zero values if 140 | * the corresponding value is known, or zero otherwise; this is not 141 | * done for pointers that are NULL. */ 142 | int process_get_entry(struct task *task, unsigned long *entryp, unsigned long *interp_biasp); 143 | 144 | /* The following callbacks have to be implemented in OS backend if 145 | * os.h defines OS_HAVE_PROCESS_DATA. */ 146 | #ifdef OS_HAVE_PROCESS_DATA 147 | int os_task_init(struct task *task); 148 | void os_task_destroy(struct task *task); 149 | int os_task_clone(struct task *retp, struct task *task); 150 | #endif 151 | 152 | /* The following callbacks have to be implemented in OS backend if 153 | * os.h defines ARCH_HAVE_PROCESS_DATA. */ 154 | #ifdef ARCH_HAVE_PROCESS_DATA 155 | int arch_task_init(struct task *task); 156 | void arch_task_destroy(struct task *task); 157 | int arch_task_clone(struct task *retp, struct task *task); 158 | #endif 159 | 160 | /* stop all thread of a given task */ 161 | void stop_threads(struct task *task); 162 | 163 | /* scan writeable memory segments */ 164 | void *mem_scan(struct task *task, struct mt_msg *cmd, void *payload, unsigned long *data_len); 165 | 166 | /* os specific init */ 167 | int os_init(void); 168 | 169 | /* wait for the next unqueued trace event */ 170 | struct task *wait_event(); 171 | 172 | /* wakeup a wait_event() call */ 173 | void wait_event_wakeup(void); 174 | 175 | /* return true the elf file is 64 bit */ 176 | int is_64bit(struct mt_elf *mte); 177 | 178 | /* change user id of a running process */ 179 | void change_uid(void); 180 | 181 | #endif 182 | 183 | -------------------------------------------------------------------------------- /backtrace.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_BACKTRACE_H 24 | #define _INC_BACKTRACE_H 25 | 26 | #include 27 | 28 | #include "dwarf.h" 29 | #include "main.h" 30 | #include "options.h" 31 | #include "task.h" 32 | #include "timer.h" 33 | 34 | /* init backtrace for given leader task */ 35 | static inline int backtrace_init(struct task *task) 36 | { 37 | assert(task->leader == task); 38 | assert(task->backtrace == NULL); 39 | 40 | task->backtrace = dwarf_init(task->is_64bit); 41 | 42 | return task->backtrace != NULL; 43 | } 44 | 45 | /* destroy backtrace for given leader task */ 46 | static inline void backtrace_destroy(struct task *task) 47 | { 48 | assert(task->leader == task); 49 | 50 | if (task->backtrace) { 51 | dwarf_destroy(task->backtrace); 52 | 53 | task->backtrace = NULL; 54 | } 55 | } 56 | 57 | /* start backtrace for given task */ 58 | static inline int backtrace_init_unwind(struct task *task) 59 | { 60 | assert(task->leader); 61 | assert(task->leader->backtrace); 62 | 63 | return dwarf_init_unwind(task->leader->backtrace, task); 64 | } 65 | 66 | /* get backtrace IP address for given task */ 67 | static inline unsigned long backtrace_get_ip(struct task *task) 68 | { 69 | assert(task->leader); 70 | assert(task->leader->backtrace); 71 | 72 | return dwarf_get_ip(task->leader->backtrace); 73 | } 74 | 75 | /* step to next backtrace given task */ 76 | static inline int backtrace_step(struct task *task) 77 | { 78 | int ret; 79 | struct timespec start; 80 | 81 | assert(task->leader); 82 | assert(task->leader->backtrace); 83 | 84 | if (unlikely(options.verbose > 1)) 85 | start_time(&start); 86 | 87 | ret = dwarf_step(task->leader->backtrace); 88 | 89 | if (unlikely(options.verbose > 1)) 90 | set_timer(&start, &backtrace_time); 91 | 92 | return ret; 93 | } 94 | 95 | /* get backtrace location type of given task */ 96 | static inline int backtrace_location_type(struct task *task) 97 | { 98 | assert(task->leader); 99 | assert(task->leader->backtrace); 100 | 101 | return dwarf_location_type(task->leader->backtrace); 102 | } 103 | #endif 104 | 105 | -------------------------------------------------------------------------------- /breakpoint.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_BREAKPOINT_H 24 | #define _INC_BREAKPOINT_H 25 | 26 | #include 27 | 28 | #include "arch.h" 29 | #include "list.h" 30 | #include "sysdep.h" 31 | #include "forward.h" 32 | 33 | #define BP_REORDER_THRESHOLD 2048U 34 | 35 | #define BP_SW 0 36 | #define BP_HW_SCRATCH 1 37 | #define BP_HW 2 38 | #define BP_AUTO 3 39 | 40 | struct breakpoint { 41 | #if HW_BREAKPOINTS > 1 42 | unsigned int hwcnt; 43 | #endif 44 | unsigned int refcnt; 45 | unsigned int count; 46 | 47 | unsigned int ext:8; 48 | unsigned int type:2; 49 | unsigned int enabled:1; 50 | unsigned int locked:1; 51 | unsigned int deleted:1; 52 | unsigned int sw:1; 53 | unsigned int hw:1; 54 | unsigned int was_hw:1; 55 | unsigned int break_insn:1; 56 | union { 57 | unsigned char orig_value[BREAKPOINT_LENGTH]; 58 | #if HW_BREAKPOINTS > 0 59 | unsigned int hw_bp_slot; 60 | #endif 61 | }; 62 | 63 | int (*on_hit)(struct task *task, struct breakpoint *bp); 64 | arch_addr_t addr; 65 | struct library_symbol *libsym; 66 | struct list_head link_list; 67 | }; 68 | 69 | /* setup the basic breakpoint support for a given leader */ 70 | void breakpoint_setup(struct task *leader); 71 | 72 | /* get a new breakpoint structure. */ 73 | struct breakpoint *breakpoint_new(struct task *task, arch_addr_t addr, struct library_symbol *libsym, int type); 74 | 75 | /* get a new extended breakpoint structure . */ 76 | struct breakpoint *breakpoint_new_ext(struct task *task, arch_addr_t addr, struct library_symbol *libsym, int type, size_t ext); 77 | 78 | /* insert a new breakpoint structure if necessary and turn the breakpoint on */ 79 | struct breakpoint *breakpoint_insert(struct task *task, arch_addr_t addr, struct library_symbol *libsym, int type); 80 | 81 | /* delete a breakpoint in task */ 82 | void breakpoint_delete(struct task *task, struct breakpoint *bp); 83 | 84 | /* Enable breakpoint in task */ 85 | void breakpoint_enable(struct task *task, struct breakpoint *bp); 86 | 87 | /* Disable task breakpoint task */ 88 | void breakpoint_disable(struct task *task, struct breakpoint *bp); 89 | 90 | void breakpoint_enable_all(struct task *leader); 91 | void breakpoint_disable_all(struct task *leader); 92 | void breakpoint_invalidate_all(struct task *leader); 93 | void breakpoint_enable_all_nonlocked(struct task *leader); 94 | void breakpoint_disable_all_nonlocked(struct task *leader); 95 | void breakpoint_clear_all(struct task *leader); 96 | int breakpoint_clone_all(struct task *clone, struct task *leader); 97 | 98 | struct breakpoint *breakpoint_find(struct task *leader, arch_addr_t addr); 99 | 100 | #if HW_BREAKPOINTS > 0 101 | void enable_scratch_hw_bp(struct task *task, struct breakpoint *bp); 102 | void disable_scratch_hw_bp(struct task *task, struct breakpoint *bp); 103 | #else 104 | static inline void enable_scratch_hw_bp(struct task *task, struct breakpoint *bp) 105 | { 106 | (void)task; 107 | (void)bp; 108 | } 109 | 110 | static inline void disable_scratch_hw_bp(struct task *task, struct breakpoint *bp) 111 | { 112 | (void)task; 113 | (void)bp; 114 | } 115 | #endif 116 | 117 | #if HW_BREAKPOINTS > 1 118 | void reorder_hw_bp(struct task *task); 119 | 120 | void breakpoint_hw_clone(struct task *task); 121 | void breakpoint_hw_destroy(struct task *task); 122 | #else 123 | static inline void breakpoint_hw_clone(struct task *task) 124 | { 125 | (void)task; 126 | } 127 | 128 | static inline void breakpoint_hw_destroy(struct task *task) 129 | { 130 | (void)task; 131 | } 132 | #endif 133 | 134 | struct breakpoint *breakpoint_get(struct breakpoint *bp); 135 | 136 | int breakpoint_put(struct breakpoint *bp); 137 | 138 | #endif 139 | 140 | -------------------------------------------------------------------------------- /client/bfdinc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_CLIENT_BININC_H 24 | #define _INC_CLIENT_BININC_H 25 | 26 | #include "config.h" 27 | 28 | #ifndef PACKAGE 29 | #define PACKAGE "binfile" 30 | #endif 31 | 32 | #ifndef PACKAGE_VERSION 33 | #define PACKAGE_VERSION "1.0" 34 | #endif 35 | 36 | #include 37 | 38 | #undef PACKAGE 39 | #undef PACKAGE_VERSION 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /client/binfile.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #define _GNU_SOURCE 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | 33 | /* try to detect libfd version and set up wrapper accprdingly. */ 34 | #ifdef bfd_get_section_flags 35 | // 2.31 (and possibly earlier) has bfd_get_section_flags 36 | #define bfd_section_size_wrapper(_ptr, _section) bfd_section_size(_ptr, _section) 37 | #define bfd_section_vma_wrapper(_ptr, _section) bfd_section_vma(_ptr, _section) 38 | #else 39 | // works for 2.34 40 | #define bfd_get_section_flags(_unused, _section) bfd_section_flags(_section) 41 | #define bfd_section_size_wrapper(_unused, _section) bfd_section_size(_section) 42 | #define bfd_section_vma_wrapper(_unused, _section) bfd_section_vma(_section) 43 | #endif 44 | 45 | #include "binfile.h" 46 | #include "process.h" 47 | 48 | static LIST_HEAD(list_of_binfiles); 49 | 50 | /* These variables are used to pass information between 51 | translate_addresses and find_address_in_section. */ 52 | struct sym_info { 53 | bfd_vma pc; 54 | asymbol **syms; 55 | const char *filename; 56 | const char *functionname; 57 | unsigned int line; 58 | bfd_boolean found; 59 | }; 60 | 61 | static long slurp_symtab(struct bin_file *binfile) 62 | { 63 | long storage; 64 | long symcount; 65 | bfd_boolean dynamic = FALSE; 66 | 67 | if ((bfd_get_file_flags(binfile->abfd) & HAS_SYMS) == 0) 68 | return 0; 69 | 70 | storage = bfd_get_symtab_upper_bound(binfile->abfd); 71 | if (!storage) { 72 | storage = bfd_get_dynamic_symtab_upper_bound(binfile->abfd); 73 | dynamic = TRUE; 74 | } 75 | 76 | if (storage < 0) 77 | return 0; 78 | 79 | binfile->syms = (asymbol **)malloc(storage); 80 | if (dynamic) 81 | symcount = bfd_canonicalize_dynamic_symtab(binfile->abfd, binfile->syms); 82 | else 83 | symcount = bfd_canonicalize_symtab(binfile->abfd, binfile->syms); 84 | if (symcount < 0) 85 | return 0; 86 | 87 | /* If there are no symbols left after canonicalization and 88 | we have not tried the dynamic symbols then give them a go. */ 89 | if (symcount == 0 && ! dynamic && (storage = bfd_get_dynamic_symtab_upper_bound(binfile->abfd)) > 0) { 90 | free(binfile->syms); 91 | binfile->syms = malloc(storage); 92 | symcount = bfd_canonicalize_dynamic_symtab(binfile->abfd, binfile->syms); 93 | } 94 | return symcount; 95 | } 96 | 97 | static void find_address_in_section(bfd *abfd, asection *section, void *data __attribute__ ((__unused__))) 98 | { 99 | bfd_vma vma; 100 | bfd_size_type size; 101 | struct sym_info *psi = (struct sym_info *) data; 102 | 103 | if (psi->found) 104 | return; 105 | 106 | if ((bfd_get_section_flags(abfd, section) & SEC_ALLOC) == 0) 107 | return; 108 | 109 | vma = bfd_section_vma_wrapper(abfd, section); 110 | if (psi->pc < vma) 111 | return; 112 | size = bfd_section_size_wrapper(abfd, section); 113 | if (psi->pc >= vma + size) 114 | return; 115 | 116 | psi->found = bfd_find_nearest_line(abfd, section, psi->syms, psi->pc - vma, &psi->filename, &psi->functionname, &psi->line); 117 | } 118 | 119 | struct rb_sym *bin_file_lookup(struct bin_file *binfile, bfd_vma addr, unsigned long off) 120 | { 121 | struct sym_info si = { 0 }; 122 | char *sym_buf = NULL; 123 | struct rb_root *root = &binfile->sym_table; 124 | struct rb_node **new = &(root->rb_node), *parent = NULL; 125 | struct rb_sym *this; 126 | unsigned int si_info = 0; 127 | 128 | if (!binfile) 129 | return NULL; 130 | 131 | /* Figure out where to put new node */ 132 | while (*new) { 133 | this = container_of(*new, struct rb_sym, node); 134 | 135 | parent = *new; 136 | 137 | if (addr < this->addr) 138 | new = &((*new)->rb_left); 139 | else 140 | if (addr > this->addr) 141 | new = &((*new)->rb_right); 142 | else { 143 | bin_file_sym_get(this); 144 | 145 | return this; 146 | } 147 | } 148 | 149 | si.pc = (binfile->abfd->flags & EXEC_P) ? addr : addr - off; 150 | si.syms = binfile->syms; 151 | si.found = FALSE; 152 | si.line = 0; 153 | 154 | bfd_map_over_sections(binfile->abfd, find_address_in_section, &si); 155 | 156 | if (si.found) { 157 | const char *name; 158 | char *alloc = NULL; 159 | 160 | if (sym_buf) 161 | free(sym_buf); 162 | 163 | name = si.functionname; 164 | 165 | if (!name || !*name) 166 | name = "?"; 167 | else { 168 | alloc = bfd_demangle(binfile->abfd, name, DMGL_ANSI | DMGL_PARAMS | DMGL_RET_DROP | DMGL_AUTO); 169 | if (alloc) 170 | name = alloc; 171 | } 172 | 173 | if (si.filename) { 174 | if (si.line) { 175 | if (asprintf(&sym_buf, "%s:%u %s", si.filename, si.line, name) == -1) 176 | sym_buf = NULL; 177 | else 178 | si_info = 1; 179 | } 180 | else { 181 | if (asprintf(&sym_buf, "%s %s", si.filename, name) == -1) 182 | sym_buf = NULL; 183 | else 184 | si_info = 1; 185 | } 186 | } 187 | else 188 | sym_buf = strdup(name); 189 | 190 | if (alloc) 191 | free(alloc); 192 | } 193 | 194 | this = malloc(sizeof(*this)); 195 | if (!this) 196 | return NULL; 197 | 198 | this->addr = addr; 199 | this->sym = sym_buf; 200 | this->refcnt = 1; 201 | this->binfile = binfile; 202 | this->si_info = si_info; 203 | 204 | ++binfile->refcnt; 205 | 206 | /* Add new node and rebalance tree. */ 207 | rb_link_node(&this->node, parent, new); 208 | rb_insert_color(&this->node, root); 209 | 210 | return this; 211 | } 212 | 213 | struct bin_file *bin_file_open(const char *filename, const char *mapname) 214 | { 215 | char **matching; 216 | struct bin_file *binfile; 217 | struct list_head *it; 218 | 219 | if (!filename) 220 | return NULL; 221 | 222 | list_for_each(it, &list_of_binfiles) { 223 | binfile = container_of(it, struct bin_file, list); 224 | 225 | if (!strcmp(filename, binfile->filename)) { 226 | bin_file_get(binfile); 227 | return binfile; 228 | } 229 | } 230 | 231 | binfile = malloc(sizeof(struct bin_file)); 232 | if (!binfile) 233 | return NULL; 234 | 235 | binfile->filename = strdup(filename); 236 | binfile->mapname = strdup(mapname); 237 | binfile->refcnt = 1; 238 | binfile->sym_table = RB_ROOT; 239 | binfile->abfd = bfd_openr(binfile->filename, NULL); 240 | 241 | if (!binfile->abfd) 242 | goto error; 243 | 244 | if (bfd_check_format(binfile->abfd, bfd_archive)) 245 | goto error; 246 | 247 | if (!bfd_check_format_matches(binfile->abfd, bfd_object, &matching)) 248 | goto error; 249 | 250 | if (slurp_symtab(binfile) <= 0) 251 | goto error; 252 | 253 | list_add_tail(&binfile->list, &list_of_binfiles); 254 | 255 | return binfile; 256 | error: 257 | if (binfile->abfd) 258 | bfd_close(binfile->abfd); 259 | free(binfile->filename); 260 | free(binfile->mapname); 261 | free(binfile); 262 | 263 | return NULL; 264 | } 265 | 266 | void bin_file_get(struct bin_file *binfile) 267 | { 268 | ++binfile->refcnt; 269 | } 270 | 271 | void bin_file_put(struct bin_file *binfile) 272 | { 273 | if (!binfile) 274 | return; 275 | 276 | if (!--binfile->refcnt) { 277 | list_del(&binfile->list); 278 | 279 | if (binfile->syms) 280 | free(binfile->syms); 281 | 282 | if (binfile->abfd) 283 | bfd_close(binfile->abfd); 284 | 285 | free(binfile->filename); 286 | free(binfile->mapname); 287 | free(binfile); 288 | } 289 | } 290 | 291 | void bin_file_sym_get(struct rb_sym *sym) 292 | { 293 | struct bin_file *binfile = sym->binfile; 294 | 295 | ++sym->refcnt; 296 | ++binfile->refcnt; 297 | } 298 | 299 | void bin_file_sym_put(struct rb_sym *sym) 300 | { 301 | struct bin_file *binfile = sym->binfile; 302 | 303 | if (!--sym->refcnt) { 304 | free(sym->sym); 305 | 306 | if (binfile) 307 | rb_erase(&sym->node, &binfile->sym_table); 308 | free(sym); 309 | } 310 | bin_file_put(binfile); 311 | } 312 | 313 | -------------------------------------------------------------------------------- /client/binfile.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_CLIENT_BINFILE_H 24 | #define _INC_CLIENT_BINFILE_H 25 | 26 | #include "bfdinc.h" 27 | #include "list.h" 28 | #include "rbtree.h" 29 | 30 | struct rb_sym { 31 | struct rb_node node; 32 | bfd_vma addr; 33 | char *sym; 34 | struct bin_file *binfile; 35 | unsigned long refcnt; 36 | unsigned int si_info; 37 | }; 38 | 39 | struct bin_file { 40 | struct list_head list; 41 | bfd *abfd; 42 | asymbol **syms; 43 | struct rb_root sym_table; 44 | unsigned long refcnt; 45 | char *filename; 46 | char *mapname; 47 | }; 48 | 49 | struct bin_file *bin_file_open(const char *filename, const char *mapname); 50 | void bin_file_put(struct bin_file *binfile); 51 | void bin_file_get(struct bin_file *binfile); 52 | struct rb_sym *bin_file_lookup(struct bin_file *binfile, bfd_vma addr, unsigned long off); 53 | void bin_file_sym_get(struct rb_sym *sym); 54 | void bin_file_sym_put(struct rb_sym *sym); 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /client/client.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_CLIENT_CLIENT_H 24 | #define _INC_CLIENT_CLIENT_H 25 | 26 | #include "memtrace.h" 27 | 28 | struct process; 29 | 30 | struct process *client_first_process(void); 31 | struct process *client_find_process(unsigned int pid); 32 | void client_iterate_processes(int (*func)(struct process *process)); 33 | void client_show_info(void); 34 | int client_set_depth(int depth); 35 | void client_request_info(void); 36 | int client_wait_op(enum mt_operation op); 37 | void client_close(void); 38 | int client_send_msg(struct process *process, enum mt_operation op, void *payload, unsigned int payload_len); 39 | int client_connected(void); 40 | int client_start(void); 41 | int client_start_pair(int handle); 42 | int client_stop(void); 43 | int client_logfile(void); 44 | 45 | #endif 46 | 47 | -------------------------------------------------------------------------------- /client/dump.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #define _GNU_SOURCE 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "dump.h" 36 | #include "ioevent.h" 37 | 38 | static int dump_term; 39 | static FILE *dump_outfile; 40 | static int dump_char; 41 | 42 | static int rows, cols; 43 | static int row, col; 44 | 45 | static int get_term_size(void) 46 | { 47 | #ifdef TIOCGSIZE 48 | struct ttysize ttys; 49 | #endif 50 | #ifdef TIOCGWINSZ 51 | struct winsize wins; 52 | #endif 53 | const char *s; 54 | 55 | #ifdef TIOCGSIZE 56 | if (ioctl(0, TIOCGSIZE, &ttys) != -1) { 57 | rows = ttys.ts_lines; 58 | cols = ttys.ts_cols; 59 | return 0; 60 | } 61 | #endif 62 | #ifdef TIOCGWINSZ 63 | if (ioctl(0, TIOCGWINSZ, &wins) != -1) { 64 | rows = wins.ws_row; 65 | cols = wins.ws_col; 66 | return 0; 67 | } 68 | #endif 69 | if (rows) { 70 | s = getenv("LINES"); 71 | if (s) 72 | rows = strtol(s, NULL, 10); 73 | else 74 | rows = 25; 75 | } 76 | 77 | if (cols) { 78 | s=getenv("COLUMNS"); 79 | if (s) 80 | cols = strtol(s, NULL, 10); 81 | else 82 | cols = 80; 83 | } 84 | 85 | 86 | return 0; 87 | } 88 | 89 | int dump_init(FILE *file) 90 | { 91 | dump_outfile = file; 92 | 93 | if (!dump_outfile) { 94 | dump_term = 0; 95 | row = 0; 96 | col = 0; 97 | get_term_size(); 98 | } 99 | 100 | return 0; 101 | } 102 | 103 | static int dump_getchar(void) 104 | { 105 | dump_char = getchar(); 106 | return 0; 107 | } 108 | 109 | static int dump_pager(void) 110 | { 111 | struct termios termios; 112 | struct termios termios_old; 113 | int len; 114 | ioevent_func oldfunc; 115 | 116 | len = printf("Press for next line, q for quit and any other for next page\r") - 1; 117 | fflush(stdout); 118 | 119 | tcgetattr(0, &termios_old); 120 | termios = termios_old; 121 | cfmakeraw(&termios); 122 | 123 | tcsetattr(0, TCSADRAIN, &termios); 124 | oldfunc = ioevent_set_input_func(0, dump_getchar); 125 | 126 | dump_char = 0; 127 | do { 128 | ioevent_watch(-1); 129 | } while(!dump_char); 130 | 131 | ioevent_set_input_func(0, oldfunc); 132 | tcsetattr(0, TCSANOW, &termios_old); 133 | 134 | printf("%*s\r", len, ""); 135 | fflush(stdout); 136 | 137 | switch(dump_char) { 138 | case '\03': 139 | case 'q': 140 | if (col) 141 | fputc('\n', stdout); 142 | dump_term = 1; 143 | return -1; 144 | case ' ': 145 | get_term_size(); 146 | row = rows - 1; 147 | break; 148 | default: 149 | get_term_size(); 150 | row = 0; 151 | break; 152 | } 153 | 154 | return 0; 155 | } 156 | 157 | static int next_nl(char *str, int l) 158 | { 159 | int n; 160 | 161 | for(n = 0; *str; ++n) { 162 | if (!l--) 163 | break; 164 | 165 | if (*str++ == '\n') 166 | break; 167 | } 168 | return n; 169 | } 170 | 171 | static int dump_line(char *s, int n) 172 | { 173 | if (dump_term) 174 | return -1; 175 | 176 | col += fwrite(s, sizeof(char), n, stdout); 177 | 178 | if (s[n] == '\n') { 179 | if (col < cols) 180 | fputc('\n', stdout); 181 | row++; 182 | col = 0; 183 | } 184 | else { 185 | if (col >= cols) { 186 | row++; 187 | col = 0; 188 | } 189 | } 190 | 191 | if (row >= rows) { 192 | if (dump_pager()) 193 | return -1; 194 | } 195 | return 0; 196 | } 197 | 198 | int dump_printf(const char *fmt, ...) 199 | { 200 | char *str; 201 | char *s; 202 | int n; 203 | va_list args; 204 | int ret = 0; 205 | 206 | if (dump_outfile) { 207 | va_start(args, fmt); 208 | vfprintf(dump_outfile, fmt, args); 209 | va_end(args); 210 | return 0; 211 | } 212 | 213 | va_start(args, fmt); 214 | n = vasprintf(&str, fmt, args); 215 | va_end(args); 216 | 217 | if (n == -1) 218 | return -1; 219 | 220 | for(s = str; *s; ) { 221 | n = next_nl(s, cols - col); 222 | 223 | ret = dump_line(s, n); 224 | if (ret) 225 | break; 226 | 227 | s += n; 228 | 229 | if (*s == '\n') { 230 | ++s; 231 | ++n; 232 | } 233 | } 234 | 235 | free(str); 236 | return ret; 237 | } 238 | 239 | int dump_flush(void) 240 | { 241 | if (dump_outfile) 242 | fflush(dump_outfile); 243 | else 244 | fflush(stdout); 245 | return 0; 246 | } 247 | 248 | -------------------------------------------------------------------------------- /client/dump.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_CLIENT_DUMP_H 24 | #define _INC_CLIENT_DUMP_H 25 | 26 | #include 27 | 28 | int dump_init(FILE *file); 29 | int dump_printf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); 30 | int dump_flush(void); 31 | 32 | #endif 33 | 34 | -------------------------------------------------------------------------------- /client/job.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "client.h" 36 | #include "common.h" 37 | #include "job.h" 38 | #include "process.h" 39 | 40 | void leaks_scan(struct process *process, int mode) 41 | { 42 | process_leaks_scan(process, mode); 43 | 44 | client_wait_op(MT_SCAN); 45 | } 46 | 47 | void dump_stacks(struct process *process, void (*dump)(struct process *process, const char *outfile, int lflag), const char *outfile, int lflag) 48 | { 49 | if (!process->n_allocations) 50 | return; 51 | 52 | dump(process, outfile, lflag); 53 | } 54 | 55 | -------------------------------------------------------------------------------- /client/job.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_CLIENT_JOB_H 24 | #define _INC_CLIENT_JOB_H 25 | 26 | struct process; 27 | 28 | void leaks_scan(struct process *process, int mode); 29 | void dump_stacks(struct process *process, void (*dump)(struct process *process, const char *outfile, int lflag), const char *outfile, int lflag); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /client/process.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_CLIENT_PROCESS_H 24 | #define _INC_CLIENT_PROCESS_H 25 | 26 | #include 27 | 28 | #include "list.h" 29 | #include "memtrace.h" 30 | #include "rbtree.h" 31 | 32 | #define SCAN_ALL 0 33 | #define SCAN_LEAK 1 34 | #define SCAN_NEW 2 35 | 36 | struct alloc_block; 37 | 38 | enum process_status { 39 | MT_PROCESS_RUNNING, /* process is running */ 40 | MT_PROCESS_EXIT, /* _exit() has been called in process */ 41 | MT_PROCESS_EXITING, /* process is about exiting */ 42 | MT_PROCESS_IGNORE, /* ignore the process */ 43 | MT_PROCESS_DETACH, /* trace will be detached */ 44 | }; 45 | 46 | struct lib { 47 | struct list_head list; 48 | const char *pathname; 49 | unsigned long offset; 50 | unsigned long addr; 51 | unsigned long size; 52 | }; 53 | 54 | struct process { 55 | enum process_status status; 56 | unsigned int pid; 57 | char *filename; 58 | unsigned long bytes_used; 59 | unsigned long n_allocations; 60 | unsigned long total_allocations; 61 | unsigned long leaks; 62 | unsigned long long leaked_bytes; 63 | unsigned long stack_trees; 64 | struct rb_root block_table; 65 | struct rb_root stack_table; 66 | struct list_head map_list; 67 | struct list_head realloc_list; 68 | unsigned long long tsc; 69 | unsigned int tracing:1; 70 | unsigned int swap_endian:1; 71 | unsigned int is_64bit:1; 72 | unsigned int attached:1; 73 | unsigned long (*get_ulong)(void *); 74 | void (*put_ulong)(void *, unsigned long); 75 | uint16_t (*val16)(uint16_t val); 76 | uint32_t (*val32)(uint32_t val); 77 | uint64_t (*val64)(uint64_t val); 78 | uint8_t ptr_size; 79 | }; 80 | 81 | struct process *process_new(unsigned int pid, unsigned int swap_endian, unsigned int tracing); 82 | void process_reset(struct process *process); 83 | void process_reset_allocations(struct process *process); 84 | void process_reinit(struct process *process, unsigned int swap_endian, unsigned int is_64bit, unsigned int attached); 85 | void process_set_clone(struct process *process, struct process *clone); 86 | struct process *process_clone_of(struct process *process); 87 | void process_duplicate(struct process *process, struct process *copy); 88 | void process_run(struct process *process, const char *libpath, const char *path, char **args); 89 | void process_set_status(struct process *process, enum process_status status); 90 | void process_start_input(struct process *process); 91 | void process_stop_input(struct process *process); 92 | void process_about_exit(struct process *process); 93 | int process_exit(struct process *process); 94 | void process_status(struct process *process); 95 | int process_scan(struct process *curr, void *leaks, uint32_t payload_len); 96 | void process_alloc(struct process *process, struct mt_msg *msg, void *payload); 97 | void process_free(struct process *process, struct mt_msg *msg, void *payload); 98 | void process_munmap(struct process *process, struct mt_msg *msg, void *payload); 99 | void process_add_map(struct process *process, void *payload, uint32_t payload_len); 100 | void process_del_map(struct process *process, void *payload, uint32_t payload_len); 101 | int process_detach(struct process *process); 102 | void process_realloc_done(struct process *process, struct mt_msg *mt_msg, void *payload); 103 | 104 | unsigned long process_leaks_scan(struct process *process, int mode); 105 | 106 | void process_dump_sortby(struct process *process); 107 | void process_dump_sort_average(struct process *process, const char *outfile, int lflag); 108 | void process_dump_sort_usage(struct process *process, const char *outfile, int lflag); 109 | void process_dump_sort_leaks(struct process *process, const char *outfile, int lflag); 110 | void process_dump_sort_bytes_leaked(struct process *process, const char *outfile, int lflag); 111 | void process_dump_sort_allocations(struct process *process, const char *outfile, int lflag); 112 | void process_dump_sort_total(struct process *process, const char *outfile, int lflag); 113 | void process_dump_sort_tsc(struct process *process, const char *outfile, int lflag); 114 | void process_dump_sort_mismatched(struct process *process, const char *outfile, int lflag); 115 | void process_dump_sort_badfree(struct process *process, const char *outfile, int lflag); 116 | void process_dump_stacks(struct process *process, const char *outfile, int lflag); 117 | 118 | void add_ignore_regex(regex_t *re); 119 | 120 | #endif 121 | 122 | -------------------------------------------------------------------------------- /client/readline.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_CLIENT_READLINE_H 24 | #define _INC_CLIENT_READLINE_H 25 | 26 | void readline_init(void); 27 | void readline_exit(void); 28 | 29 | #endif 30 | 31 | -------------------------------------------------------------------------------- /common.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #define _GNU_SOURCE 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "common.h" 32 | 33 | void _fatal(const char *file, const char *func, int line, const char *format, ...) 34 | { 35 | va_list args; 36 | char *message = NULL; 37 | 38 | va_start(args, format); 39 | if (vasprintf(&message, format, args) == -1) 40 | abort(); 41 | va_end(args); 42 | 43 | fprintf(stderr,"%s(%s:%d):\n %s\n", file, func, line, message); 44 | 45 | free(message); 46 | } 47 | 48 | char *safe_strncpy(char *dst, const char *src, size_t size) 49 | { 50 | if (!size) 51 | return dst; 52 | dst[--size] = '\0'; 53 | return strncpy(dst, src, size); 54 | } 55 | 56 | unsigned long get_val32(void *data, unsigned long index) 57 | { 58 | return (unsigned long)*(uint32_t *)(data + index * sizeof(uint32_t)); 59 | } 60 | 61 | unsigned long get_val64(void *data, unsigned long index) 62 | { 63 | return (unsigned long)*(uint64_t *)(data + index * sizeof(uint64_t)); 64 | } 65 | 66 | unsigned long find_block(unsigned long (*get_val)(void *data, unsigned long index), void *arr, unsigned long n, unsigned long addr) 67 | { 68 | unsigned long first, middle, last, val; 69 | 70 | first = 0; 71 | last = n; 72 | 73 | if (addr < get_val(arr, first)) 74 | return n; 75 | 76 | if (addr > get_val(arr, last - 1)) 77 | return n; 78 | 79 | do { 80 | middle = (first + last) >> 1; 81 | 82 | val = get_val(arr, middle); 83 | 84 | if (addr < val) 85 | last = middle; 86 | else 87 | if (addr > val) 88 | first = middle + 1; 89 | else 90 | return middle; 91 | } while (first < last); 92 | 93 | return n; 94 | } 95 | 96 | -------------------------------------------------------------------------------- /common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_COMMON_H 24 | #define _INC_COMMON_H 25 | 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | #ifndef ARRAY_SIZE 32 | #define ARRAY_SIZE(x) (sizeof (x) / sizeof *(x)) 33 | #endif 34 | 35 | /** 36 | * Macro to convert a constant number value into a string constant 37 | */ 38 | #define XSTR(x) #x 39 | #define STR(x) XSTR(x) 40 | 41 | #ifndef offsetof 42 | #ifdef __compiler_offsetof 43 | #define offsetof(TYPE, MEMBER) __compiler_offsetof(TYPE, MEMBER) 44 | #else 45 | #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 46 | #endif 47 | #endif 48 | 49 | /** 50 | * container_of - cast a member of a structure out to the containing structure 51 | * @ptr: the pointer to the member. 52 | * @type: the type of the container struct this is embedded in. 53 | * @member: the name of the member within the struct. 54 | * 55 | */ 56 | #define container_of(ptr, type, member) ({ \ 57 | const typeof( ((type *)0)->member ) *__mptr = (ptr); \ 58 | (type *)( (char *)__mptr - offsetof(type,member) );}) 59 | 60 | 61 | #if 1 62 | #define likely(x) __builtin_expect(!!(x), 1) 63 | #define unlikely(x) __builtin_expect(!!(x), 0) 64 | #else 65 | #define likely(x) (x) 66 | #define unlikely(x) (x) 67 | #endif 68 | 69 | #define fatal(fmt...) _fatal(__FILE__,__PRETTY_FUNCTION__,__LINE__ , ##fmt),abort() 70 | 71 | void _fatal(const char *file, const char *func, int line, const char *format, ...) __attribute__ ((format (printf, 4, 5)));; 72 | 73 | char *safe_strncpy(char *dst, const char *src, size_t size); 74 | 75 | unsigned long get_val32(void *data, unsigned long index); 76 | 77 | unsigned long get_val64(void *data, unsigned long index); 78 | 79 | unsigned long find_block(unsigned long (*get_val)(void *data, unsigned long index), void *arr, unsigned long n, unsigned long addr); 80 | 81 | #endif 82 | 83 | -------------------------------------------------------------------------------- /config.h.in: -------------------------------------------------------------------------------- 1 | #define PACKAGE_VERSION "@MT_VERSION_STRING@" 2 | 3 | #ifndef HAVE_PROCESS_VM_READV 4 | #cmakedefine HAVE_PROCESS_VM_READV 5 | #endif 6 | 7 | #ifndef HAVE_LIBSELINUX 8 | #cmakedefine HAVE_LIBSELINUX 9 | #endif 10 | 11 | #ifndef DISABLE_CLIENT 12 | #cmakedefine DISABLE_CLIENT 13 | #endif 14 | -------------------------------------------------------------------------------- /config/autoconf/missing: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Common wrapper for a few potentially missing GNU programs. 3 | 4 | scriptversion=2013-10-28.13; # UTC 5 | 6 | # Copyright (C) 1996-2014 Free Software Foundation, Inc. 7 | # Originally written by Fran,cois Pinard , 1996. 8 | 9 | # This program is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 2, or (at your option) 12 | # any later version. 13 | 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program. If not, see . 21 | 22 | # As a special exception to the GNU General Public License, if you 23 | # distribute this file as part of a program that contains a 24 | # configuration script generated by Autoconf, you may include it under 25 | # the same distribution terms that you use for the rest of that program. 26 | 27 | if test $# -eq 0; then 28 | echo 1>&2 "Try '$0 --help' for more information" 29 | exit 1 30 | fi 31 | 32 | case $1 in 33 | 34 | --is-lightweight) 35 | # Used by our autoconf macros to check whether the available missing 36 | # script is modern enough. 37 | exit 0 38 | ;; 39 | 40 | --run) 41 | # Back-compat with the calling convention used by older automake. 42 | shift 43 | ;; 44 | 45 | -h|--h|--he|--hel|--help) 46 | echo "\ 47 | $0 [OPTION]... PROGRAM [ARGUMENT]... 48 | 49 | Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due 50 | to PROGRAM being missing or too old. 51 | 52 | Options: 53 | -h, --help display this help and exit 54 | -v, --version output version information and exit 55 | 56 | Supported PROGRAM values: 57 | aclocal autoconf autoheader autom4te automake makeinfo 58 | bison yacc flex lex help2man 59 | 60 | Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 61 | 'g' are ignored when checking the name. 62 | 63 | Send bug reports to ." 64 | exit $? 65 | ;; 66 | 67 | -v|--v|--ve|--ver|--vers|--versi|--versio|--version) 68 | echo "missing $scriptversion (GNU Automake)" 69 | exit $? 70 | ;; 71 | 72 | -*) 73 | echo 1>&2 "$0: unknown '$1' option" 74 | echo 1>&2 "Try '$0 --help' for more information" 75 | exit 1 76 | ;; 77 | 78 | esac 79 | 80 | # Run the given program, remember its exit status. 81 | "$@"; st=$? 82 | 83 | # If it succeeded, we are done. 84 | test $st -eq 0 && exit 0 85 | 86 | # Also exit now if we it failed (or wasn't found), and '--version' was 87 | # passed; such an option is passed most likely to detect whether the 88 | # program is present and works. 89 | case $2 in --version|--help) exit $st;; esac 90 | 91 | # Exit code 63 means version mismatch. This often happens when the user 92 | # tries to use an ancient version of a tool on a file that requires a 93 | # minimum version. 94 | if test $st -eq 63; then 95 | msg="probably too old" 96 | elif test $st -eq 127; then 97 | # Program was missing. 98 | msg="missing on your system" 99 | else 100 | # Program was found and executed, but failed. Give up. 101 | exit $st 102 | fi 103 | 104 | perl_URL=http://www.perl.org/ 105 | flex_URL=http://flex.sourceforge.net/ 106 | gnu_software_URL=http://www.gnu.org/software 107 | 108 | program_details () 109 | { 110 | case $1 in 111 | aclocal|automake) 112 | echo "The '$1' program is part of the GNU Automake package:" 113 | echo "<$gnu_software_URL/automake>" 114 | echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" 115 | echo "<$gnu_software_URL/autoconf>" 116 | echo "<$gnu_software_URL/m4/>" 117 | echo "<$perl_URL>" 118 | ;; 119 | autoconf|autom4te|autoheader) 120 | echo "The '$1' program is part of the GNU Autoconf package:" 121 | echo "<$gnu_software_URL/autoconf/>" 122 | echo "It also requires GNU m4 and Perl in order to run:" 123 | echo "<$gnu_software_URL/m4/>" 124 | echo "<$perl_URL>" 125 | ;; 126 | esac 127 | } 128 | 129 | give_advice () 130 | { 131 | # Normalize program name to check for. 132 | normalized_program=`echo "$1" | sed ' 133 | s/^gnu-//; t 134 | s/^gnu//; t 135 | s/^g//; t'` 136 | 137 | printf '%s\n' "'$1' is $msg." 138 | 139 | configure_deps="'configure.ac' or m4 files included by 'configure.ac'" 140 | case $normalized_program in 141 | autoconf*) 142 | echo "You should only need it if you modified 'configure.ac'," 143 | echo "or m4 files included by it." 144 | program_details 'autoconf' 145 | ;; 146 | autoheader*) 147 | echo "You should only need it if you modified 'acconfig.h' or" 148 | echo "$configure_deps." 149 | program_details 'autoheader' 150 | ;; 151 | automake*) 152 | echo "You should only need it if you modified 'Makefile.am' or" 153 | echo "$configure_deps." 154 | program_details 'automake' 155 | ;; 156 | aclocal*) 157 | echo "You should only need it if you modified 'acinclude.m4' or" 158 | echo "$configure_deps." 159 | program_details 'aclocal' 160 | ;; 161 | autom4te*) 162 | echo "You might have modified some maintainer files that require" 163 | echo "the 'autom4te' program to be rebuilt." 164 | program_details 'autom4te' 165 | ;; 166 | bison*|yacc*) 167 | echo "You should only need it if you modified a '.y' file." 168 | echo "You may want to install the GNU Bison package:" 169 | echo "<$gnu_software_URL/bison/>" 170 | ;; 171 | lex*|flex*) 172 | echo "You should only need it if you modified a '.l' file." 173 | echo "You may want to install the Fast Lexical Analyzer package:" 174 | echo "<$flex_URL>" 175 | ;; 176 | help2man*) 177 | echo "You should only need it if you modified a dependency" \ 178 | "of a man page." 179 | echo "You may want to install the GNU Help2man package:" 180 | echo "<$gnu_software_URL/help2man/>" 181 | ;; 182 | makeinfo*) 183 | echo "You should only need it if you modified a '.texi' file, or" 184 | echo "any other file indirectly affecting the aspect of the manual." 185 | echo "You might want to install the Texinfo package:" 186 | echo "<$gnu_software_URL/texinfo/>" 187 | echo "The spurious makeinfo call might also be the consequence of" 188 | echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" 189 | echo "want to install GNU make:" 190 | echo "<$gnu_software_URL/make/>" 191 | ;; 192 | *) 193 | echo "You might have modified some files without having the proper" 194 | echo "tools for further handling them. Check the 'README' file, it" 195 | echo "often tells you about the needed prerequisites for installing" 196 | echo "this package. You may also peek at any GNU archive site, in" 197 | echo "case some other package contains this missing '$1' program." 198 | ;; 199 | esac 200 | } 201 | 202 | give_advice "$1" | sed -e '1s/^/WARNING: /' \ 203 | -e '2,$s/^/ /' >&2 204 | 205 | # Propagate the correct exit status (expected to be 127 for a program 206 | # not found, 63 for a program that failed due to version mismatch). 207 | exit $st 208 | 209 | # Local variables: 210 | # eval: (add-hook 'write-file-hooks 'time-stamp) 211 | # time-stamp-start: "scriptversion=" 212 | # time-stamp-format: "%:y-%02m-%02d.%02H" 213 | # time-stamp-time-zone: "UTC" 214 | # time-stamp-end: "; # UTC" 215 | # End: 216 | -------------------------------------------------------------------------------- /config/m4/ltsugar.m4: -------------------------------------------------------------------------------- 1 | # ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- 2 | # 3 | # Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software 4 | # Foundation, Inc. 5 | # Written by Gary V. Vaughan, 2004 6 | # 7 | # This file is free software; the Free Software Foundation gives 8 | # unlimited permission to copy and/or distribute it, with or without 9 | # modifications, as long as this notice is preserved. 10 | 11 | # serial 6 ltsugar.m4 12 | 13 | # This is to help aclocal find these macros, as it can't see m4_define. 14 | AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) 15 | 16 | 17 | # lt_join(SEP, ARG1, [ARG2...]) 18 | # ----------------------------- 19 | # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their 20 | # associated separator. 21 | # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier 22 | # versions in m4sugar had bugs. 23 | m4_define([lt_join], 24 | [m4_if([$#], [1], [], 25 | [$#], [2], [[$2]], 26 | [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) 27 | m4_define([_lt_join], 28 | [m4_if([$#$2], [2], [], 29 | [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) 30 | 31 | 32 | # lt_car(LIST) 33 | # lt_cdr(LIST) 34 | # ------------ 35 | # Manipulate m4 lists. 36 | # These macros are necessary as long as will still need to support 37 | # Autoconf-2.59, which quotes differently. 38 | m4_define([lt_car], [[$1]]) 39 | m4_define([lt_cdr], 40 | [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], 41 | [$#], 1, [], 42 | [m4_dquote(m4_shift($@))])]) 43 | m4_define([lt_unquote], $1) 44 | 45 | 46 | # lt_append(MACRO-NAME, STRING, [SEPARATOR]) 47 | # ------------------------------------------ 48 | # Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'. 49 | # Note that neither SEPARATOR nor STRING are expanded; they are appended 50 | # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). 51 | # No SEPARATOR is output if MACRO-NAME was previously undefined (different 52 | # than defined and empty). 53 | # 54 | # This macro is needed until we can rely on Autoconf 2.62, since earlier 55 | # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. 56 | m4_define([lt_append], 57 | [m4_define([$1], 58 | m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) 59 | 60 | 61 | 62 | # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) 63 | # ---------------------------------------------------------- 64 | # Produce a SEP delimited list of all paired combinations of elements of 65 | # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list 66 | # has the form PREFIXmINFIXSUFFIXn. 67 | # Needed until we can rely on m4_combine added in Autoconf 2.62. 68 | m4_define([lt_combine], 69 | [m4_if(m4_eval([$# > 3]), [1], 70 | [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl 71 | [[m4_foreach([_Lt_prefix], [$2], 72 | [m4_foreach([_Lt_suffix], 73 | ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, 74 | [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) 75 | 76 | 77 | # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) 78 | # ----------------------------------------------------------------------- 79 | # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited 80 | # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. 81 | m4_define([lt_if_append_uniq], 82 | [m4_ifdef([$1], 83 | [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], 84 | [lt_append([$1], [$2], [$3])$4], 85 | [$5])], 86 | [lt_append([$1], [$2], [$3])$4])]) 87 | 88 | 89 | # lt_dict_add(DICT, KEY, VALUE) 90 | # ----------------------------- 91 | m4_define([lt_dict_add], 92 | [m4_define([$1($2)], [$3])]) 93 | 94 | 95 | # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) 96 | # -------------------------------------------- 97 | m4_define([lt_dict_add_subkey], 98 | [m4_define([$1($2:$3)], [$4])]) 99 | 100 | 101 | # lt_dict_fetch(DICT, KEY, [SUBKEY]) 102 | # ---------------------------------- 103 | m4_define([lt_dict_fetch], 104 | [m4_ifval([$3], 105 | m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), 106 | m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) 107 | 108 | 109 | # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) 110 | # ----------------------------------------------------------------- 111 | m4_define([lt_if_dict_fetch], 112 | [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], 113 | [$5], 114 | [$6])]) 115 | 116 | 117 | # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) 118 | # -------------------------------------------------------------- 119 | m4_define([lt_dict_filter], 120 | [m4_if([$5], [], [], 121 | [lt_join(m4_quote(m4_default([$4], [[, ]])), 122 | lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), 123 | [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl 124 | ]) 125 | -------------------------------------------------------------------------------- /config/m4/ltversion.m4: -------------------------------------------------------------------------------- 1 | # ltversion.m4 -- version numbers -*- Autoconf -*- 2 | # 3 | # Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc. 4 | # Written by Scott James Remnant, 2004 5 | # 6 | # This file is free software; the Free Software Foundation gives 7 | # unlimited permission to copy and/or distribute it, with or without 8 | # modifications, as long as this notice is preserved. 9 | 10 | # @configure_input@ 11 | 12 | # serial 4179 ltversion.m4 13 | # This file is part of GNU Libtool 14 | 15 | m4_define([LT_PACKAGE_VERSION], [2.4.6]) 16 | m4_define([LT_PACKAGE_REVISION], [2.4.6]) 17 | 18 | AC_DEFUN([LTVERSION_VERSION], 19 | [macro_version='2.4.6' 20 | macro_revision='2.4.6' 21 | _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) 22 | _LT_DECL(, macro_revision, 0) 23 | ]) 24 | -------------------------------------------------------------------------------- /config/m4/lt~obsolete.m4: -------------------------------------------------------------------------------- 1 | # lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- 2 | # 3 | # Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software 4 | # Foundation, Inc. 5 | # Written by Scott James Remnant, 2004. 6 | # 7 | # This file is free software; the Free Software Foundation gives 8 | # unlimited permission to copy and/or distribute it, with or without 9 | # modifications, as long as this notice is preserved. 10 | 11 | # serial 5 lt~obsolete.m4 12 | 13 | # These exist entirely to fool aclocal when bootstrapping libtool. 14 | # 15 | # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN), 16 | # which have later been changed to m4_define as they aren't part of the 17 | # exported API, or moved to Autoconf or Automake where they belong. 18 | # 19 | # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN 20 | # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us 21 | # using a macro with the same name in our local m4/libtool.m4 it'll 22 | # pull the old libtool.m4 in (it doesn't see our shiny new m4_define 23 | # and doesn't know about Autoconf macros at all.) 24 | # 25 | # So we provide this file, which has a silly filename so it's always 26 | # included after everything else. This provides aclocal with the 27 | # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything 28 | # because those macros already exist, or will be overwritten later. 29 | # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. 30 | # 31 | # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. 32 | # Yes, that means every name once taken will need to remain here until 33 | # we give up compatibility with versions before 1.7, at which point 34 | # we need to keep only those names which we still refer to. 35 | 36 | # This is to help aclocal find these macros, as it can't see m4_define. 37 | AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) 38 | 39 | m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) 40 | m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) 41 | m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) 42 | m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) 43 | m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) 44 | m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) 45 | m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) 46 | m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) 47 | m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) 48 | m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) 49 | m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) 50 | m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) 51 | m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) 52 | m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) 53 | m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) 54 | m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) 55 | m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) 56 | m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) 57 | m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) 58 | m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) 59 | m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) 60 | m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) 61 | m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) 62 | m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) 63 | m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) 64 | m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) 65 | m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) 66 | m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) 67 | m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) 68 | m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) 69 | m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) 70 | m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) 71 | m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) 72 | m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) 73 | m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) 74 | m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) 75 | m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) 76 | m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) 77 | m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) 78 | m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) 79 | m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) 80 | m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) 81 | m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) 82 | m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) 83 | m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) 84 | m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) 85 | m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) 86 | m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) 87 | m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) 88 | m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) 89 | m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) 90 | m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) 91 | m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) 92 | m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) 93 | m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) 94 | m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) 95 | m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) 96 | m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) 97 | m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) 98 | m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) 99 | m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) 100 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | mtrace-ng (0.4) UNRELEASED; urgency=medium 2 | 3 | * Created an unreleased debian package 4 | 5 | -- Stefani Seibold Tue, 04 Nov 2015 08:45:00 +0100 6 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: mtrace-ng 2 | Section: utils 3 | Priority: optional 4 | Maintainer: Package Maintainers 5 | Build-Depends: debhelper (>= 8.0.0), autotools-dev, binutils-dev, libreadline6-dev, libselinux1-dev, libtinfo-dev, libelf-dev, zlib1g-dev, libncurses5-dev, libiberty-dev 6 | Standards-Version: 3.9.4 7 | Vcs-Git: https://github.com/sstefani/mtrace.git 8 | 9 | 10 | Package: mtrace-ng 11 | Architecture: i386 amd64 12 | Depends: ${shlibs:Depends}, ${misc:Depends} 13 | Description: dynamic memory tracer and debugger 14 | mtrace is a dynamic memory tracer, debugger and statistical analyses tool for C and C++, which intercepts, records and reports all kinds of dynamic memory allocations 15 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: mtrace-ng 3 | Source: https://github.com/sstefani/mtrace 4 | 5 | Files: * 6 | Copyright: 2015 Stefani Seibold 7 | License: GPL-2.0+ 8 | 9 | License: GPL-2.0+ 10 | This package is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation; either version 2 of the License, or 13 | (at your option) any later version. 14 | . 15 | This package is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | . 20 | You should have received a copy of the GNU General Public License 21 | along with this program. If not, see 22 | . 23 | On Debian systems, the complete text of the GNU General 24 | Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". 25 | 26 | # Please also look if there are files or directories which have a 27 | # different copyright/license attached and list them here. 28 | # Please avoid to pick license terms that are more restrictive than the 29 | # packaged work, as it may make Debian's contributions unacceptable upstream. 30 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | 4 | # Uncomment this to turn on verbose mode. 5 | #export DH_VERBOSE=1 6 | 7 | %: 8 | dh $@ --with autotools-dev 9 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (native) 2 | -------------------------------------------------------------------------------- /debug.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #define _GNU_SOURCE 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include "common.h" 30 | #include "options.h" 31 | 32 | #include "debug.h" 33 | 34 | #ifdef DEBUG 35 | 36 | void _debug(int level, const char *file, const char *function, int line, const char *fmt, ...) 37 | { 38 | char *buf = NULL; 39 | va_list args; 40 | 41 | if (!(options.debug & level)) 42 | return; 43 | 44 | va_start(args, fmt); 45 | if (vasprintf(&buf, fmt, args) == -1) 46 | abort(); 47 | va_end(args); 48 | 49 | fprintf(stderr, "DEBUG: %s():%s@%d - %s\n", function, file, line, buf); 50 | 51 | free(buf); 52 | } 53 | 54 | #endif 55 | 56 | -------------------------------------------------------------------------------- /debug.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_DEBUG_H 24 | #define _INC_DEBUG_H 25 | 26 | #include "config.h" 27 | 28 | /* debug levels: 29 | */ 30 | enum { 31 | DEBUG_TRACE = 1, 32 | DEBUG_DWARF = 2, 33 | DEBUG_EVENT = 4, 34 | DEBUG_PROCESS = 8, 35 | DEBUG_FUNCTION = 16, 36 | }; 37 | 38 | #ifdef DEBUG 39 | void _debug(int level, const char *file, const char *function, int line, const char *fmt, ...) __attribute__ ((format(printf, 5, 6))); 40 | #else 41 | static inline void _debug(int level, const char *file, const char *function, int line, const char *fmt, ...) 42 | { 43 | (void)level; 44 | (void)file; 45 | (void)function; 46 | (void)line; 47 | (void)fmt; 48 | } 49 | #endif 50 | 51 | #define debug(level, expr...) _debug(level, __FILE__, __FUNCTION__, __LINE__, expr) 52 | 53 | #endif 54 | 55 | -------------------------------------------------------------------------------- /dict.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "common.h" 30 | #include "dict.h" 31 | #include "list.h" 32 | 33 | struct dict_entry { 34 | struct list_head list; 35 | unsigned long key; 36 | const void *value; 37 | }; 38 | 39 | struct dict { 40 | unsigned int size; 41 | unsigned int (*key2hash)(unsigned long); 42 | int (*key_cmp)(unsigned long, unsigned long); 43 | struct list_head buckets[0]; 44 | }; 45 | 46 | struct dict *dict_init(unsigned int size, unsigned int (*key2hash)(unsigned long), int (*key_cmp)(unsigned long, unsigned long)) 47 | { 48 | struct dict *d; 49 | unsigned int i; 50 | 51 | d = malloc(sizeof(*d) + sizeof(d->buckets[0]) * size); 52 | 53 | d->size = size; 54 | d->key2hash = key2hash; 55 | d->key_cmp = key_cmp; 56 | 57 | for (i = 0; i < d->size; i++) 58 | INIT_LIST_HEAD(&d->buckets[i]); 59 | 60 | return d; 61 | } 62 | 63 | void dict_clear(struct dict *d) 64 | { 65 | unsigned int i; 66 | struct list_head *it, *next; 67 | 68 | for (i = 0; i < d->size; i++) { 69 | list_for_each_safe(it, next, &d->buckets[i]) { 70 | struct dict_entry *entry = container_of(it, struct dict_entry, list); 71 | 72 | free(entry); 73 | } 74 | } 75 | free(d); 76 | } 77 | 78 | static struct dict_entry *_dict_find_entry(struct dict *d, unsigned long key, unsigned int hash) 79 | { 80 | struct list_head *it; 81 | 82 | list_for_each(it, &d->buckets[hash]) { 83 | struct dict_entry *entry = container_of(it, struct dict_entry, list); 84 | 85 | if (!d->key_cmp(key, entry->key)) 86 | return entry; 87 | } 88 | return NULL; 89 | } 90 | 91 | int dict_add(struct dict *d, unsigned long key, const void *value) 92 | { 93 | struct dict_entry *newentry; 94 | unsigned int hash = d->key2hash(key) % d->size; 95 | 96 | if (_dict_find_entry(d, key, hash)) 97 | return -1; 98 | 99 | newentry = malloc(sizeof(*newentry)); 100 | 101 | newentry->key = key; 102 | newentry->value = value; 103 | 104 | INIT_LIST_HEAD(&newentry->list); 105 | 106 | list_add(&newentry->list, &d->buckets[hash]); 107 | 108 | return 0; 109 | } 110 | 111 | const void *dict_remove_entry(struct dict *d, unsigned long key) 112 | { 113 | unsigned int hash = d->key2hash(key) % d->size; 114 | struct dict_entry *entry = _dict_find_entry(d, key, hash); 115 | 116 | if (entry) { 117 | const void *value = entry->value; 118 | 119 | list_del(&entry->list); 120 | free(entry); 121 | 122 | return value; 123 | } 124 | return NULL; 125 | } 126 | 127 | const void *dict_find_entry(struct dict *d, unsigned long key) 128 | { 129 | unsigned int hash = d->key2hash(key) % d->size; 130 | struct dict_entry *entry = _dict_find_entry(d, key, hash); 131 | 132 | return entry ? entry->value : NULL; 133 | } 134 | 135 | int dict_apply_to_all(struct dict *d, int (*func)(unsigned long key, const void *value, void *data), void *data) 136 | { 137 | unsigned int i; 138 | 139 | for (i = 0; i < d->size; i++) { 140 | struct list_head *it, *next; 141 | 142 | list_for_each_safe(it, next, &d->buckets[i]) { 143 | struct dict_entry *entry = container_of(it, struct dict_entry, list); 144 | 145 | if (func(entry->key, entry->value, data)) 146 | return -1; 147 | } 148 | } 149 | return 0; 150 | } 151 | 152 | -------------------------------------------------------------------------------- /dict.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_DICT_H 24 | #define _INC_DICT_H 25 | 26 | struct dict; 27 | 28 | struct dict *dict_init(unsigned int size, unsigned int (*key2hash)(unsigned long), int (*key_cmp)(unsigned long, unsigned long)); 29 | void dict_clear(struct dict *d); 30 | int dict_add(struct dict *d, unsigned long key, const void *value); 31 | const void *dict_remove_entry(struct dict *d, unsigned long key); 32 | const void *dict_find_entry(struct dict *d, unsigned long key); 33 | int dict_apply_to_all(struct dict *d, int (*func) (unsigned long key, const void *value, void *data), void *data); 34 | 35 | #endif 36 | 37 | -------------------------------------------------------------------------------- /dwarf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * This file is based on the libunwind source 5 | * 6 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 7 | * 8 | * This program is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU General Public License as 10 | * published by the Free Software Foundation; either version 2 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, but 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | * 02110-1301 USA 22 | */ 23 | 24 | #ifndef _INC_DWARF_H 25 | #define _INC_DWARF_H 26 | 27 | #include 28 | 29 | #include "arch.h" 30 | #include "common.h" 31 | #include "forward.h" 32 | #include "library.h" 33 | #include "mtelf.h" 34 | 35 | #define DWARF_LOC(r, t) ((struct dwarf_loc){ .val = (r), .type = (t) }) 36 | 37 | #define DWARF_GET_LOC(l) ((l).val) 38 | 39 | #define DWARF_LOC_TYPE_MEM 0 40 | #define DWARF_LOC_TYPE_REG 1 41 | #define DWARF_LOC_TYPE_VAL 2 42 | 43 | #define DWARF_NULL_LOC DWARF_LOC(0, 0) 44 | #define DWARF_MEM_LOC(m) DWARF_LOC((m), DWARF_LOC_TYPE_MEM) 45 | #define DWARF_REG_LOC(r) DWARF_LOC((r), DWARF_LOC_TYPE_REG) 46 | #define DWARF_VAL_LOC(v) DWARF_LOC((v), DWARF_LOC_TYPE_VAL) 47 | 48 | #define DWARF_IS_NULL_LOC(l) ({ struct dwarf_loc _l = (l); _l.val == 0 && _l.type == 0; }) 49 | #define DWARF_IS_MEM_LOC(l) ((l).type == DWARF_LOC_TYPE_MEM) 50 | #define DWARF_IS_REG_LOC(l) ((l).type == DWARF_LOC_TYPE_REG) 51 | #define DWARF_IS_VAL_LOC(l) ((l).type == DWARF_LOC_TYPE_VAL) 52 | 53 | #define DWARF_ADDR_SIZE(as) ((as)->is_64bit ? 8 : 4) 54 | 55 | #define DWARF_ENOMEM 1 /* out of memory */ 56 | #define DWARF_EBADREG 2 /* bad register number */ 57 | #define DWARF_EBADFRAME 3 /* bad frame */ 58 | #define DWARF_EINVAL 4 /* unsupported operation or bad value */ 59 | #define DWARF_EBADVERSION 5 /* unwind info has unsupported version */ 60 | #define DWARF_ENOINFO 6 /* no unwind info found */ 61 | #define DWARF_STOPUNWIND 7 62 | 63 | struct dwarf_cie_info { 64 | arch_addr_t start_ip; /* first IP covered by this procedure */ 65 | arch_addr_t ip_range; /* ip range covered by this procedure */ 66 | arch_addr_t cie_instr_start; /* start addr. of CIE "initial_instructions" */ 67 | arch_addr_t cie_instr_end; /* end addr. of CIE "initial_instructions" */ 68 | arch_addr_t fde_instr_start; /* start addr. of FDE "instructions" */ 69 | arch_addr_t fde_instr_end; /* end addr. of FDE "instructions" */ 70 | arch_addr_t code_align; /* code-alignment factor */ 71 | arch_addr_t data_align; /* data-alignment factor */ 72 | arch_addr_t ret_addr_column; /* column of return-address register */ 73 | uint16_t abi; 74 | uint16_t tag; 75 | uint8_t fde_encoding; 76 | uint8_t lsda_encoding; 77 | unsigned int sized_augmentation:1; 78 | unsigned int have_abi_marker:1; 79 | unsigned int signal_frame:1; 80 | }; 81 | 82 | struct dwarf_loc { 83 | unsigned long val; 84 | unsigned int type; 85 | }; 86 | 87 | struct dwarf_cursor { 88 | struct task *task; 89 | arch_addr_t cfa; /* canonical frame address; aka frame-/stack-pointer */ 90 | arch_addr_t ip; /* instruction pointer */ 91 | arch_addr_t ret_addr_column; /* column for return-address */ 92 | unsigned int use_prev_instr:1; /* use previous (= call) or current (= signal) instruction? */ 93 | unsigned int valid:1; 94 | struct libref *libref; 95 | struct dwarf_cie_info dci; 96 | struct dwarf_loc *loc; 97 | }; 98 | 99 | struct dwarf_addr_space { 100 | unsigned int is_64bit:1; 101 | struct dwarf_cursor cursor; 102 | unsigned int ip_reg; 103 | unsigned int ret_reg; 104 | unsigned int num_regs; 105 | }; 106 | 107 | struct dwarf_eh_frame_hdr; 108 | 109 | void *dwarf_init(int is_64bit); 110 | void dwarf_destroy(struct dwarf_addr_space *as); 111 | int dwarf_init_unwind(struct dwarf_addr_space *as, struct task *task); 112 | int dwarf_step(struct dwarf_addr_space *as); 113 | 114 | int dwarf_locate_map(struct dwarf_addr_space *as, arch_addr_t ip); 115 | 116 | int dwarf_get(struct dwarf_addr_space *as, struct dwarf_loc loc, arch_addr_t *valp); 117 | 118 | int dwarf_get_unwind_table(struct task *task, struct libref *libref); 119 | 120 | int dwarf_arch_init(struct dwarf_addr_space *as); 121 | int dwarf_arch_init_unwind(struct dwarf_addr_space *as); 122 | int dwarf_arch_step(struct dwarf_addr_space *as); 123 | int dwarf_arch_map_reg(struct dwarf_addr_space *as, unsigned int reg); 124 | int dwarf_arch_check_call(struct dwarf_addr_space *as, arch_addr_t ip); 125 | 126 | #ifdef DWARF_TO_REGNUM 127 | unsigned int dwarf_to_regnum(unsigned int reg); 128 | #else 129 | static inline __attribute__((const)) unsigned int dwarf_to_regnum(unsigned int reg) 130 | { 131 | return reg; 132 | } 133 | #endif 134 | 135 | static inline arch_addr_t dwarf_get_ip(struct dwarf_addr_space *as) 136 | { 137 | struct dwarf_cursor *c = &as->cursor; 138 | 139 | if (unlikely(!c->valid)) 140 | return ARCH_ADDR_T(0); 141 | 142 | return c->ip; 143 | } 144 | 145 | static inline int dwarf_location_type(struct dwarf_addr_space *as) 146 | { 147 | struct libref *libref = as->cursor.libref; 148 | 149 | if (!libref) 150 | return -1; 151 | 152 | return libref->type; 153 | } 154 | #endif 155 | 156 | -------------------------------------------------------------------------------- /event.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_EVENT_H 24 | #define _INC_EVENT_H 25 | 26 | #include "forward.h" 27 | #include "list.h" 28 | 29 | enum event_type { 30 | EVENT_NONE = 0, 31 | EVENT_SIGNAL, 32 | EVENT_ABOUT_EXIT, 33 | EVENT_EXIT, 34 | EVENT_EXIT_SIGNAL, 35 | EVENT_FORK, 36 | EVENT_CLONE, 37 | EVENT_VFORK, 38 | EVENT_EXEC, 39 | EVENT_BREAKPOINT, 40 | EVENT_NEW, 41 | }; 42 | 43 | struct event { 44 | struct list_head list; 45 | enum event_type type; 46 | union { 47 | int ret_val; /* EVENT_EXIT */ 48 | int signum; /* EVENT_SIGNAL, EVENT_EXIT_SIGNAL */ 49 | struct breakpoint *breakpoint; /* EVENT_BREAKPOINT */ 50 | int newpid; /* EVENT_CLONE, EVENT_FORK, EVENT_VFORK */ 51 | } e_un; 52 | }; 53 | 54 | void init_event(struct task *task); 55 | void remove_event(struct task *task); 56 | struct task *next_event(void); 57 | void queue_event(struct task *task); 58 | int handle_event(struct task *task); 59 | 60 | #endif 61 | 62 | -------------------------------------------------------------------------------- /forward.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | /* Important types defined in other header files are declared here. */ 24 | 25 | #ifndef _INC_FORWARD_H 26 | #define _INC_FORWARD_H 27 | 28 | struct event; 29 | struct task; 30 | struct breakpoint; 31 | struct libref; 32 | struct library; 33 | struct library_symbol; 34 | struct mt_elf; 35 | struct mt_msg; 36 | 37 | #endif 38 | 39 | -------------------------------------------------------------------------------- /library.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_LIBRARY_H 24 | #define _INC_LIBRARY_H 25 | 26 | #include 27 | 28 | #include "forward.h" 29 | #include "sysdep.h" 30 | #include "list.h" 31 | #include "mtelf.h" 32 | #include "rbtree.h" 33 | 34 | #define LIBTYPE_LIB 0 35 | #define LIBTYPE_MAIN 1 36 | #define LIBTYPE_LOADER 2 37 | 38 | struct library_symbol { 39 | struct list_head list; 40 | struct libref *libref; 41 | const struct function *func; 42 | arch_addr_t addr; 43 | }; 44 | 45 | struct libref { 46 | /* Unique dynamic entry address */ 47 | arch_addr_t dyn; 48 | 49 | /* base address assign by the loader */ 50 | unsigned long bias; 51 | 52 | /* Absolute address of the entry point. Useful for main 53 | * binary, though I suppose the value might be useful for the 54 | * dynamic linker, too (in case we ever want to do early 55 | * process tracing). */ 56 | arch_addr_t entry; 57 | 58 | const char *filename; 59 | 60 | /* executable segment */ 61 | unsigned long txt_vaddr; 62 | unsigned long txt_size; 63 | unsigned long txt_offset; 64 | 65 | /* mapped image */ 66 | void *mmap_addr; 67 | unsigned long mmap_offset; 68 | unsigned long mmap_size; 69 | 70 | /* global-pointer */ 71 | arch_addr_t pltgot; 72 | unsigned long eh_hdr_offset; 73 | unsigned long eh_hdr_vaddr; 74 | void *fde_tab; 75 | unsigned long fde_count; 76 | unsigned int type; 77 | 78 | #ifdef __arm__ 79 | void *exidx_data; 80 | unsigned long exidx_len; 81 | #endif 82 | 83 | unsigned int refcnt; 84 | 85 | /* Symbols associated with the library. This includes a 86 | * symbols that don't have a breakpoint attached (yet). */ 87 | struct list_head sym_list; 88 | }; 89 | 90 | struct library { 91 | /* link list of libraries associated with the task */ 92 | struct list_head list; 93 | 94 | /* red/black tree of libraries associated with the task */ 95 | struct rb_node rb_node; 96 | 97 | /* pointer to the real library refernce */ 98 | struct libref *libref; 99 | }; 100 | 101 | /* create a new symbol */ 102 | struct library_symbol *library_symbol_new(struct libref *libref, arch_addr_t addr, const struct function *func); 103 | 104 | /* Add a library to the list of the thread leader libraries. */ 105 | struct library *library_add(struct task *leader, struct libref *libref); 106 | 107 | /* delete a given list of libraries */ 108 | void library_delete_list(struct task *leader, struct list_head *list); 109 | 110 | /* delete all libraries of a given leader */ 111 | void library_clear_all(struct task *leader); 112 | 113 | /* cline all libraries of a given leader to a new task leader*/ 114 | int library_clone_all(struct task *clone, struct task *leader); 115 | 116 | /* setup library list of a given leader */ 117 | void library_setup(struct task *leader); 118 | 119 | /* get the pathname of the executable */ 120 | const char *library_execname(struct task *leader); 121 | 122 | /* Iterate through list of symbols of library. */ 123 | struct library_symbol *library_find_symbol(struct libref *libref, arch_addr_t addr); 124 | 125 | /* find a library with a given dynamic entry address */ 126 | struct library *library_find_by_dyn(struct list_head *list, arch_addr_t dyn); 127 | 128 | /* create a library reference. */ 129 | struct libref *libref_new(unsigned int type); 130 | 131 | /* delete a library reference. */ 132 | void libref_delete(struct libref *libref); 133 | 134 | /* Set library filename. Frees the old name if necessary. */ 135 | void libref_set_filename(struct libref *libref, const char *new_name); 136 | 137 | /* find library by address */ 138 | struct libref *addr2libref(struct task *leader, arch_addr_t addr); 139 | 140 | #endif 141 | 142 | -------------------------------------------------------------------------------- /list.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * This file is based on linux kernel list.h 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License as 8 | * published by the Free Software Foundation; either version 2 of the 9 | * License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 19 | * 02110-1301 USA 20 | */ 21 | 22 | #ifndef _INC_LIST_H 23 | #define _INC_LIST_H 24 | 25 | #define prefetch(x) __builtin_prefetch(x) 26 | 27 | struct list_head { 28 | struct list_head *next, *prev; 29 | }; 30 | 31 | /* 32 | * Simple doubly linked list implementation. 33 | * 34 | * Some of the internal functions ("__xxx") are useful when 35 | * manipulating whole lists rather than single entries, as 36 | * sometimes we already know the next/prev entries and we can 37 | * generate better code by using them directly rather than 38 | * using the generic single-entry routines. 39 | */ 40 | 41 | #define LIST_HEAD_INIT(name) { &(name), &(name) } 42 | 43 | #define LIST_HEAD(name) \ 44 | struct list_head name = LIST_HEAD_INIT(name) 45 | 46 | static inline void INIT_LIST_HEAD(struct list_head *list) 47 | { 48 | list->next = list; 49 | list->prev = list; 50 | } 51 | 52 | /* 53 | * Insert a new entry between two known consecutive entries. 54 | * 55 | * This is only for internal list manipulation where we know 56 | * the prev/next entries already! 57 | */ 58 | static inline void __list_add(struct list_head *elem, struct list_head *prev, struct list_head *next) 59 | { 60 | next->prev = elem; 61 | elem->next = next; 62 | elem->prev = prev; 63 | prev->next = elem; 64 | } 65 | 66 | /** 67 | * list_add - add a new entry 68 | * @elem: new entry to be added 69 | * @head: list head to add it after 70 | * 71 | * Insert a new entry after the specified head. 72 | * This is good for implementing stacks. 73 | */ 74 | static inline void list_add(struct list_head *elem, struct list_head *head) 75 | { 76 | __list_add(elem, head, head->next); 77 | } 78 | 79 | 80 | /** 81 | * list_add_tail - add a new entry 82 | * @elem: new entry to be added 83 | * @head: list head to add it before 84 | * 85 | * Insert a new entry before the specified head. 86 | * This is useful for implementing queues. 87 | */ 88 | static inline void list_add_tail(struct list_head *elem, struct list_head *head) 89 | { 90 | __list_add(elem, head->prev, head); 91 | } 92 | 93 | /* 94 | * Delete a list entry by making the prev/next entries 95 | * point to each other. 96 | * 97 | * This is only for internal list manipulation where we know 98 | * the prev/next entries already! 99 | */ 100 | static inline void __list_del(struct list_head *prev, struct list_head *next) 101 | { 102 | next->prev = prev; 103 | prev->next = next; 104 | } 105 | 106 | /** 107 | * list_del - deletes entry from list. 108 | * @entry: the element to delete from the list. 109 | * Note: list_empty() on entry does not return true after this, the entry is 110 | * in an undefined state. 111 | */ 112 | static inline void __list_del_entry(struct list_head *entry) 113 | { 114 | __list_del(entry->prev, entry->next); 115 | } 116 | 117 | static inline void list_del(struct list_head *entry) 118 | { 119 | __list_del(entry->prev, entry->next); 120 | entry->next = entry; 121 | entry->prev = entry; 122 | } 123 | 124 | /** 125 | * list_move - delete from one list and add as another's head 126 | * @list: the entry to move 127 | * @head: the head that will precede our entry 128 | */ 129 | static inline void list_move(struct list_head *list, struct list_head *head) 130 | { 131 | __list_del_entry(list); 132 | list_add(list, head); 133 | } 134 | 135 | /** 136 | * list_move_tail - delete from one list and add as another's tail 137 | * @list: the entry to move 138 | * @head: the head that will follow our entry 139 | */ 140 | static inline void list_move_tail(struct list_head *list, 141 | struct list_head *head) 142 | { 143 | __list_del_entry(list); 144 | list_add_tail(list, head); 145 | } 146 | 147 | /** 148 | * list_is_last - tests whether @list is the last entry in list @head 149 | * @list: the entry to test 150 | * @head: the head of the list 151 | */ 152 | static inline int list_is_last(const struct list_head *list, 153 | const struct list_head *head) 154 | { 155 | return list->next == head; 156 | } 157 | 158 | /** 159 | * list_empty - tests whether a list is empty 160 | * @head: the list to test. 161 | */ 162 | static inline int list_empty(const struct list_head *head) 163 | { 164 | return head->next == head; 165 | } 166 | 167 | /** 168 | * list_is_singular - tests whether a list has just one entry. 169 | * @head: the list to test. 170 | */ 171 | static inline int list_is_singular(const struct list_head *head) 172 | { 173 | return !list_empty(head) && (head->next == head->prev); 174 | } 175 | 176 | static inline void __list_splice(const struct list_head *list, 177 | struct list_head *prev, 178 | struct list_head *next) 179 | { 180 | struct list_head *first = list->next; 181 | struct list_head *last = list->prev; 182 | 183 | first->prev = prev; 184 | prev->next = first; 185 | 186 | last->next = next; 187 | next->prev = last; 188 | } 189 | 190 | /** 191 | * list_splice_init - join two lists and reinitialise the emptied list. 192 | * @list: the new list to add. 193 | * @head: the place to add it in the first list. 194 | * 195 | * The list at @list is reinitialised 196 | */ 197 | static inline void list_splice_init(struct list_head *list, 198 | struct list_head *head) 199 | { 200 | if (!list_empty(list)) { 201 | __list_splice(list, head, head->next); 202 | INIT_LIST_HEAD(list); 203 | } 204 | } 205 | 206 | /** 207 | * list_for_each - iterate over a list 208 | * @pos: the &struct list_head to use as a loop cursor. 209 | * @head: the head for your list. 210 | */ 211 | #define list_for_each(pos, head) \ 212 | for (pos = (head)->next; prefetch(pos->next), pos != (head); \ 213 | pos = pos->next) 214 | 215 | /** 216 | * list_for_each_safe - iterate over a list safe against removal of list entry 217 | * @pos: the &struct list_head to use as a loop cursor. 218 | * @n: another &struct list_head to use as temporary storage 219 | * @head: the head for your list. 220 | */ 221 | #define list_for_each_safe(pos, n, head) \ 222 | for (pos = (head)->next, n = pos->next; pos != (head); \ 223 | pos = n, n = pos->next) 224 | 225 | #endif 226 | 227 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #include "config.h" 24 | 25 | #define _GNU_SOURCE 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include "backend.h" 40 | #include "breakpoint.h" 41 | #include "common.h" 42 | #ifndef DISABLE_CLIENT 43 | #include "client.h" 44 | #endif 45 | #include "debug.h" 46 | #include "options.h" 47 | #include "library.h" 48 | #include "main.h" 49 | #include "mtelf.h" 50 | #include "mtrace.h" 51 | #include "server.h" 52 | #include "task.h" 53 | #include "trace.h" 54 | 55 | struct mt_timer stop_time; 56 | struct mt_timer sw_bp_time; 57 | struct mt_timer hw_bp_time; 58 | struct mt_timer backtrace_time; 59 | struct mt_timer reorder_time; 60 | struct mt_timer report_in_time; 61 | struct mt_timer report_out_time; 62 | struct mt_timer skip_bp_time; 63 | 64 | pid_t mtrace_pid; 65 | 66 | static int do_exit; 67 | 68 | void mtrace_request_exit(void) 69 | { 70 | if (do_exit) 71 | return; 72 | 73 | if (unlikely(options.verbose)) 74 | fprintf(stderr, "+++ request exit\n"); 75 | 76 | do_exit = 1; 77 | wait_event_wakeup(); 78 | } 79 | 80 | static void detach_process(struct task *leader) 81 | { 82 | if (!leader) 83 | return; 84 | 85 | pid_t pid = leader->pid; 86 | 87 | report_detach(leader); 88 | 89 | while(server_handle_command() != -1) { 90 | struct task *task = pid2task(pid); 91 | 92 | if (!task) 93 | break; 94 | 95 | if (!task->stopped) 96 | break; 97 | } 98 | } 99 | 100 | static void mtrace_exit(void) 101 | { 102 | if (!options.interactive) { 103 | each_process(stop_threads); 104 | each_process(detach_process); 105 | } 106 | 107 | each_process(remove_proc); 108 | each_pid(remove_task); 109 | } 110 | 111 | static void mtrace_init(char **cmd_args) 112 | { 113 | struct opt_p_t *opt_p_tmp; 114 | 115 | mtrace_pid = getpid(); 116 | 117 | if (options.command) { 118 | struct task *task = task_create(cmd_args); 119 | 120 | if (!task) 121 | exit(EXIT_FAILURE); 122 | 123 | if (unlikely(options.verbose)) 124 | fprintf(stderr, "+++ process pid=%d created (%s)\n", task->pid, library_execname(task)); 125 | } 126 | 127 | for(opt_p_tmp = options.opt_p; opt_p_tmp; opt_p_tmp = opt_p_tmp->next) 128 | open_pid(opt_p_tmp->pid); 129 | } 130 | 131 | static void mtrace_main(void) 132 | { 133 | struct task *task; 134 | 135 | while(!do_exit) { 136 | if (task_list_empty()) 137 | break; 138 | 139 | task = next_event(); 140 | if (task) { 141 | if (handle_event(task) == -1) 142 | break; 143 | } 144 | 145 | if (server_poll() == -1) 146 | break; 147 | } 148 | } 149 | 150 | int main(int argc, char *argv[]) 151 | { 152 | char **cmd_args = process_options(argc, argv); 153 | 154 | if (options.trace) { 155 | if (options.logfile) { 156 | if (server_logfile() == -1) 157 | exit(EXIT_FAILURE); 158 | } 159 | else 160 | if (options.server) { 161 | if (server_start() == -1) 162 | exit(EXIT_FAILURE); 163 | } 164 | else { 165 | #ifdef DISABLE_CLIENT 166 | fprintf(stderr, "direct mode not supported\n"); 167 | exit(EXIT_FAILURE); 168 | #else 169 | int ret = server_start_pair(); 170 | 171 | if (ret == -1) 172 | exit(EXIT_FAILURE); 173 | 174 | if (client_start_pair(ret)) 175 | exit(EXIT_FAILURE); 176 | #endif 177 | } 178 | } 179 | else { 180 | #ifdef DISABLE_CLIENT 181 | fprintf(stderr, "direct mode not supported\n"); 182 | exit(EXIT_FAILURE); 183 | #else 184 | if (options.logfile) { 185 | if (client_logfile() == -1) 186 | exit(EXIT_FAILURE); 187 | } 188 | else 189 | if (client_start() == -1) 190 | exit(EXIT_FAILURE); 191 | return 0; 192 | #endif 193 | } 194 | 195 | if (os_init()) 196 | exit(EXIT_FAILURE); 197 | 198 | mtrace_init(cmd_args); 199 | mtrace_main(); 200 | mtrace_exit(); 201 | 202 | report_info(0); 203 | report_disconnect(); 204 | 205 | #ifndef DISABLE_CLIENT 206 | client_stop(); 207 | #endif 208 | server_stop(); 209 | 210 | return 0; 211 | } 212 | 213 | -------------------------------------------------------------------------------- /main.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_MAIN_H 24 | #define _INC_MAIN_H 25 | 26 | #include 27 | 28 | #include "timer.h" 29 | 30 | void mtrace_request_exit(void); 31 | 32 | struct mt_timer stop_time; 33 | struct mt_timer sw_bp_time; 34 | struct mt_timer hw_bp_time; 35 | struct mt_timer backtrace_time; 36 | struct mt_timer reorder_time; 37 | struct mt_timer report_in_time; 38 | struct mt_timer report_out_time; 39 | struct mt_timer skip_bp_time; 40 | 41 | pid_t mtrace_pid; 42 | #endif 43 | 44 | -------------------------------------------------------------------------------- /memtrace.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_MEMTRACE_H 24 | #define _INC_MEMTRACE_H 25 | 26 | #include 27 | 28 | #if __LP64__ 29 | #define IS64BIT 1 30 | #else 31 | #define IS64BIT 0 32 | #endif 33 | 34 | #define MEMTRACE_SI_VERSION 9 35 | 36 | #define MEMTRACE_SI_FORK 1 37 | #define MEMTRACE_SI_EXEC 2 38 | #define MEMTRACE_SI_VERBOSE 4 39 | 40 | enum mt_operation { 41 | MT_INFO = 0, 42 | MT_DISCONNECT, 43 | MT_ADD_MAP, 44 | MT_DEL_MAP, 45 | MT_ATTACH, 46 | MT_ATTACH64, 47 | MT_FORK, 48 | MT_ABOUT_EXIT, 49 | MT_EXIT, 50 | MT_NOFOLLOW, 51 | MT_MALLOC, 52 | MT_REALLOC_ENTER, 53 | MT_REALLOC_DONE, 54 | MT_REALLOC, 55 | MT_FREE, 56 | MT_MMAP, 57 | MT_MMAP64, 58 | MT_MUNMAP, 59 | MT_MEMALIGN, 60 | MT_POSIX_MEMALIGN, 61 | MT_ALIGNED_ALLOC, 62 | MT_VALLOC, 63 | MT_PVALLOC, 64 | MT_SCAN, 65 | MT_STOP, 66 | MT_START, 67 | MT_DETACH, 68 | MT_NEW, 69 | MT_NEW_ARRAY, 70 | MT_DELETE, 71 | MT_DELETE_ARRAY, 72 | MT_DEPTH, 73 | }; 74 | 75 | struct __attribute__((packed)) mt_msg { 76 | uint16_t operation; 77 | uint16_t pid; 78 | uint32_t payload_len; 79 | }; 80 | 81 | struct __attribute__((packed)) mt_attached_payload { 82 | uint8_t attached; 83 | }; 84 | 85 | struct __attribute__((packed)) mt_alloc_payload_64 { 86 | uint64_t ptr; 87 | uint64_t size; 88 | uint64_t data[0]; 89 | }; 90 | 91 | struct __attribute__((packed)) mt_alloc_payload_32 { 92 | uint32_t ptr; 93 | uint32_t size; 94 | uint32_t data[0]; 95 | }; 96 | 97 | struct __attribute__((packed)) mt_pid_payload { 98 | uint32_t pid; 99 | }; 100 | 101 | struct __attribute__((packed)) mt_scan_payload { 102 | uint32_t ptr_size; 103 | uint32_t pad; // for 64 bit alignment 104 | uint64_t mask; 105 | char data[0]; 106 | }; 107 | 108 | struct __attribute__((packed)) memtrace_timer_info { 109 | uint32_t max; 110 | uint32_t count; 111 | uint64_t culminate; 112 | }; 113 | 114 | struct __attribute__((packed)) memtrace_info { 115 | uint8_t version; 116 | uint8_t mode; 117 | uint8_t do_trace; 118 | uint8_t stack_depth; 119 | uint8_t verbose; 120 | uint8_t unused[3]; 121 | struct memtrace_timer_info stop_time; 122 | struct memtrace_timer_info sw_bp_time; 123 | struct memtrace_timer_info hw_bp_time; 124 | struct memtrace_timer_info backtrace_time; 125 | struct memtrace_timer_info reorder_time; 126 | struct memtrace_timer_info report_in_time; 127 | struct memtrace_timer_info report_out_time; 128 | struct memtrace_timer_info skip_bp_time; 129 | }; 130 | 131 | struct __attribute__((packed)) memtrace_depth { 132 | uint8_t stack_depth; 133 | }; 134 | 135 | struct __attribute__((packed)) mt_map_payload { 136 | uint64_t addr; 137 | uint64_t offset; 138 | uint64_t size; 139 | uint64_t bias; 140 | char filename[0]; 141 | }; 142 | 143 | #endif 144 | 145 | -------------------------------------------------------------------------------- /mtelf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_MTRACE_ELF_H 24 | #define _INC_MTRACE_ELF_H 25 | 26 | #include 27 | #include 28 | 29 | #include "forward.h" 30 | #include "sysdep.h" 31 | 32 | int elf_read_library(struct task *task, struct libref *libref, const char *filename, GElf_Addr bias); 33 | 34 | /* Create a library object representing the main binary. */ 35 | struct libref *elf_read_main_binary(struct task *task, int was_attached); 36 | 37 | int mte_cmp_machine(struct mt_elf *mte, Elf64_Half type); 38 | 39 | #endif 40 | 41 | -------------------------------------------------------------------------------- /mtrace-ng.conf.5: -------------------------------------------------------------------------------- 1 | .\" -*-nroff-*- 2 | .\" Copyright (c) 2015 Stefani Seibold 3 | .\" 4 | .\" This program is free software; you can redistribute it and/or 5 | .\" modify it under the terms of the GNU General Public License as 6 | .\" published by the Free Software Foundation; either version 2 of the 7 | .\" License, or (at your option) any later version. 8 | .\" 9 | .\" This program is distributed in the hope that it will be useful, but 10 | .\" WITHOUT ANY WARRANTY; without even the implied warranty of 11 | .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | .\" General Public License for more details. 13 | .\" 14 | .\" You should have received a copy of the GNU General Public License 15 | .\" along with this program; if not, write to the Free Software 16 | .\" Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 17 | .\" 02110-1301 USA 18 | .\" 19 | .TH mtrace-ng.conf "5" "May 2015" "" "mtrace-ng configuration file" 20 | .SH "NAME" 21 | .LP 22 | \fBmtrace-ng.conf\fR \- Configuration file for \fBmtrace-ng(1)\fR. 23 | 24 | .SH DESCRIPTION 25 | 26 | This manual page describes \fBmtrace-ng.conf\fR, a file that contains 27 | configuration information for \fBmtrace-ng(1)\fR to use. 28 | 29 | Each line of a configuration file describes at most a single item. 30 | Lines composed entirely of white space are ignored, as are lines 31 | starting with a hash characters (comment lines). 32 | 33 | Currently only one command is available: \fIignore\fR 34 | 35 | .SH ignore 36 | 37 | The ignore command is followed by a regular expression. All allocations where 38 | the regular expression match will be ignored by the memory allocation 39 | bookkeeping. 40 | 41 | The syntax is as follows: 42 | 43 | .RS 44 | \fIignore\fR \fIregex\fR 45 | .RE 46 | 47 | It is possible to use several ignore commands for several regular expressions. 48 | 49 | .SH AUTHOR 50 | Stefani Seibold 51 | -------------------------------------------------------------------------------- /mtrace.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_MTRACE_H 24 | #define _INC_MTRACE_H 25 | 26 | typedef unsigned long arch_addr_t; 27 | 28 | #define ARCH_ADDR_T(x) ((arch_addr_t)(x)) 29 | 30 | #endif 31 | 32 | -------------------------------------------------------------------------------- /options.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_OPTIONS_H 24 | #define _INC_OPTIONS_H 25 | 26 | #include 27 | #include 28 | 29 | #include "config.h" 30 | #include "forward.h" 31 | 32 | #define OPT_SORT_ALLOCATIONS 0 33 | #define OPT_SORT_AVERAGE 1 34 | #define OPT_SORT_BYTES_LEAKED 2 35 | #define OPT_SORT_LEAKS 3 36 | #define OPT_SORT_STACKS 4 37 | #define OPT_SORT_TOTAL 5 38 | #define OPT_SORT_TSC 6 39 | #define OPT_SORT_USAGE 7 40 | #define OPT_SORT_MISMATCHED 8 41 | #define OPT_SORT_BADFREE 9 42 | 43 | struct opt_p_t { 44 | pid_t pid; 45 | struct opt_p_t *next; 46 | }; 47 | 48 | struct opt_F_t { 49 | const char *filename; 50 | struct opt_F_t *next; 51 | }; 52 | 53 | struct opt_b_t { 54 | char *pathname; 55 | struct opt_b_t *next; 56 | }; 57 | 58 | struct opt_O_t { 59 | char *pathname; 60 | struct opt_O_t *next; 61 | }; 62 | 63 | struct options_t { 64 | int auto_scan; /* scan memory on every exit of a trace program */ 65 | int bt_depth; /* how may levels of stack frames to show */ 66 | int follow; /* trace child processes */ 67 | int follow_exec; /* follow exec system calls */ 68 | int interactive; /* interactive mode */ 69 | FILE *output; /* output to a specific file */ 70 | int trace; /* trace mode flag */ 71 | int kill; /* kill on errors */ 72 | int server; /* true for server listen */ 73 | char *logfile; /* logfile path */ 74 | char *address; /* connect to socket path or address */ 75 | char *user; /* -u: username to run command as */ 76 | int verbose; /* verbose mode */ 77 | int wait; /* wait for client connection */ 78 | char *port; /* socket port */ 79 | char *command; /* command string */ 80 | int cwd; /* current working directory handle */ 81 | struct opt_p_t *opt_p; /* attach to process with a given pid */ 82 | struct opt_F_t *opt_F; /* alternate configuration file(s) */ 83 | struct opt_b_t *opt_b; /* binary search path(s) */ 84 | struct opt_O_t *opt_O; /* omits path list */ 85 | int sort_by; /* sort dump in non interative and non server mode */ 86 | int sanity; /* check mismatching operations against new/new[] allocations */ 87 | int debug; /* debug */ 88 | int nocpp; /* disable trace of c++ allocation operators */ 89 | int nohwbp; /* disable hardware breakpoint support */ 90 | int lflag; /* long dump */ 91 | }; 92 | 93 | extern struct options_t options; 94 | 95 | char **process_options(int argc, char **argv); 96 | 97 | #endif 98 | 99 | -------------------------------------------------------------------------------- /rbtree.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Red Black Trees 3 | * This file is part of mtrace-ng. 4 | * This file is based on the linux kernel source 5 | * Copyright (C) 1999 Andrea Arcangeli 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_RBTREE_H 24 | #define _INC_RBTREE_H 25 | 26 | #include 27 | 28 | #include "common.h" 29 | 30 | struct rb_node 31 | { 32 | unsigned long rb_parent_color; 33 | #define RB_RED 0 34 | #define RB_BLACK 1 35 | struct rb_node *rb_right; 36 | struct rb_node *rb_left; 37 | } __attribute__((aligned(sizeof(long)))); 38 | 39 | struct rb_root 40 | { 41 | struct rb_node *rb_node; 42 | }; 43 | 44 | #define RB_ROOT (struct rb_root) { NULL, } 45 | 46 | void rb_insert_color(struct rb_node *, struct rb_root *); 47 | void rb_erase(struct rb_node *, struct rb_root *); 48 | 49 | /* Postorder iteration - always visit the parent after its children */ 50 | struct rb_node *rb_first_postorder(const struct rb_root *); 51 | struct rb_node *rb_next_postorder(const struct rb_node *); 52 | 53 | /* Find logical next and previous nodes in a tree */ 54 | struct rb_node *rb_next(const struct rb_node *); 55 | struct rb_node *rb_prev(const struct rb_node *); 56 | struct rb_node *rb_first(const struct rb_root *); 57 | struct rb_node *rb_last(const struct rb_root *); 58 | 59 | static inline void rb_link_node(struct rb_node *node, struct rb_node *parent, 60 | struct rb_node **rb_link) 61 | { 62 | node->rb_parent_color = (unsigned long )parent; 63 | node->rb_left = node->rb_right = NULL; 64 | 65 | *rb_link = node; 66 | } 67 | 68 | int rb_iterate(const struct rb_root *root, int (*func)(struct rb_node *,void *data), void *user); 69 | 70 | #define rb_entry(ptr, type, member) container_of(ptr, type, member) 71 | 72 | #define rb_entry_safe(ptr, type, member) \ 73 | ({ typeof(ptr) ____ptr = (ptr); \ 74 | ____ptr ? rb_entry(____ptr, type, member) : NULL; \ 75 | }) 76 | 77 | /** 78 | * rbtree_postorder_for_each_entry_safe - iterate over rb_root in post order of 79 | * given type safe against removal of rb_node entry 80 | * 81 | * @pos: the 'type *' to use as a loop cursor. 82 | * @n: another 'type *' to use as temporary storage 83 | * @root: 'rb_root *' of the rbtree. 84 | * @field: the name of the rb_node field within 'type'. 85 | */ 86 | #define rbtree_postorder_for_each_entry_safe(pos, n, root, field) \ 87 | for (pos = rb_entry_safe(rb_first_postorder(root), typeof(*pos), field); \ 88 | pos && ({ n = rb_entry_safe(rb_next_postorder(&pos->field), \ 89 | typeof(*pos), field); 1; }); \ 90 | pos = n) 91 | 92 | #endif 93 | 94 | -------------------------------------------------------------------------------- /report.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_REPORT_H 24 | #define _INC_REPORT_H 25 | 26 | #include 27 | 28 | #include "forward.h" 29 | 30 | struct function { 31 | /* symbol name */ 32 | const char *demangled_name; 33 | /* symbol name */ 34 | const char *name; 35 | /* level for aliased symbol */ 36 | unsigned int level; 37 | /* report when function is entered */ 38 | void (*report_in)(struct task *task, struct library_symbol *libsym); 39 | /* report when function is exited */ 40 | void (*report_out)(struct task *task, struct library_symbol *libsym); 41 | }; 42 | 43 | const struct function *flist_matches_symbol(const char *sym_name); 44 | 45 | int report_add_map(struct task *task, struct library *lib); 46 | int report_del_map(struct task *task, struct library *lib); 47 | int report_info(int do_trace); 48 | int report_scan(pid_t pid, const void *data, unsigned int data_len); 49 | int report_attach(struct task *task, int was_attached); 50 | int report_fork(struct task *task, struct task *ptask); 51 | int report_exit(struct task *task); 52 | int report_about_exit(struct task *task); 53 | int report_nofollow(struct task *task); 54 | int report_disconnect(void); 55 | int report_processes(void); 56 | int report_detach(struct task *task); 57 | 58 | #endif 59 | 60 | -------------------------------------------------------------------------------- /server.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_SERVER_H 24 | #define _INC_SERVER_H 25 | 26 | #include "forward.h" 27 | 28 | #include "socket.h" 29 | 30 | int server_start(void); 31 | int server_start_pair(void); 32 | int server_send_msg(enum mt_operation op, uint32_t pid, const void *payload, unsigned int payload_len); 33 | int server_handle_command(void); 34 | int server_connected(void); 35 | int server_stop(void); 36 | int server_poll(void); 37 | int server_logfile(void); 38 | 39 | #endif 40 | 41 | -------------------------------------------------------------------------------- /sysdeps/linux-gnu/arm/arch.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_SYSDEPS_LINUX_GNU_ARM_ARCH_H 24 | #define _INC_SYSDEPS_LINUX_GNU_ARM_ARCH_H 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #define BREAKPOINT_VALUE { 0xf0, 0x01, 0xf0, 0xe7 } 33 | #define BREAKPOINT_LENGTH 4 34 | #define THUMB_BREAKPOINT_VALUE { 0x01, 0xde } 35 | #define THUMB_BREAKPOINT_LENGTH 2 36 | #define DECR_PC_AFTER_BREAK 0 37 | #define ARCH_HAVE_FETCH_ARG 38 | #define ARCH_HAVE_SIZEOF 39 | #define ARCH_HAVE_ALIGNOF 40 | #define ARCH_ENDIAN_LITTLE 41 | #define ARCH_HAVE_ATOMIC_SINGLESTEP 42 | 43 | #define MT_ELFCLASS ELFCLASS32 44 | #define MT_ELF_MACHINE EM_ARM 45 | 46 | #define ARCH_SINGLESTEP 47 | 48 | #define DWARF_TO_REGNUM 49 | 50 | #define HW_BREAKPOINTS 0 51 | 52 | struct context { 53 | struct pt_regs regs; 54 | }; 55 | 56 | #endif 57 | 58 | -------------------------------------------------------------------------------- /sysdeps/linux-gnu/arm/cpu.cmake: -------------------------------------------------------------------------------- 1 | list(APPEND C_SRCS 2 | sysdeps/${MT_OS}/${MT_CPU}/arch.c 3 | sysdeps/${MT_OS}/${MT_CPU}/dwarf-arm.c 4 | sysdeps/${MT_OS}/${MT_CPU}/regs.c 5 | ) 6 | 7 | -------------------------------------------------------------------------------- /sysdeps/linux-gnu/arm/regs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | #include "config.h" 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "backend.h" 31 | #include "task.h" 32 | #include "arch.h" 33 | 34 | #if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) 35 | #define PTRACE_PEEKUSER PTRACE_PEEKUSR 36 | #endif 37 | 38 | #if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) 39 | #define PTRACE_POKEUSER PTRACE_POKEUSR 40 | #endif 41 | 42 | arch_addr_t get_instruction_pointer(struct task *task) 43 | { 44 | return ARCH_ADDR_T(task->context.regs.ARM_pc); 45 | } 46 | 47 | void set_instruction_pointer(struct task *task, arch_addr_t addr) 48 | { 49 | unsigned long val = (unsigned long)addr; 50 | 51 | if (task->context.regs.ARM_pc == (long)val) 52 | return; 53 | 54 | task->context.regs.ARM_pc = val; 55 | 56 | if (ptrace(PTRACE_POKEUSER, task->pid, offsetof(struct pt_regs, ARM_pc), val) == -1) { 57 | if (errno != ESRCH) 58 | fprintf(stderr, "pid=%d Couldn't set instruction pointer: %s\n", task->pid, strerror(errno)); 59 | } 60 | } 61 | 62 | unsigned int ip_reg_addr(void) 63 | { 64 | return offsetof(struct pt_regs, ARM_pc); 65 | } 66 | 67 | arch_addr_t get_return_addr(struct task *task) 68 | { 69 | return ARCH_ADDR_T(task->context.regs.ARM_lr); 70 | } 71 | 72 | int fetch_context(struct task *task) 73 | { 74 | if (ptrace(PTRACE_GETREGS, task->pid, 0, &task->context.regs) == -1) { 75 | if (errno != ESRCH) 76 | fprintf(stderr, "pid=%d Couldn't fetch register context: %s\n", task->pid, strerror(errno)); 77 | 78 | memset(&task->context.regs, 0, sizeof(task->context.regs)); 79 | return -1; 80 | } 81 | return 0; 82 | } 83 | 84 | void save_param_context(struct task *task) 85 | { 86 | task->saved_context = task->context; 87 | } 88 | 89 | unsigned long fetch_param(struct task *task, unsigned int param) 90 | { 91 | unsigned long val; 92 | 93 | switch (param) { 94 | case 0: 95 | val = task->saved_context.regs.ARM_r0; 96 | break; 97 | case 1: 98 | val = task->saved_context.regs.ARM_r1; 99 | break; 100 | case 2: 101 | val = task->saved_context.regs.ARM_r2; 102 | break; 103 | case 3: 104 | val = task->saved_context.regs.ARM_r3; 105 | break; 106 | default: 107 | copy_from_proc(task, task->saved_context.regs.ARM_sp + (param - 4) * sizeof(val), &val, sizeof(val)); 108 | } 109 | return val; 110 | } 111 | 112 | unsigned long fetch_retval(struct task *task) 113 | { 114 | return task->context.regs.ARM_r0; 115 | } 116 | 117 | unsigned long fetch_reg(struct task *task, unsigned int reg) 118 | { 119 | unsigned long val; 120 | 121 | switch(reg) { 122 | case offsetof(struct pt_regs, ARM_cpsr): 123 | val = task->context.regs.ARM_cpsr; 124 | break; 125 | case offsetof(struct pt_regs, ARM_pc): 126 | val = task->context.regs.ARM_pc; 127 | break; 128 | case offsetof(struct pt_regs, ARM_lr): 129 | val = task->context.regs.ARM_lr; 130 | break; 131 | case offsetof(struct pt_regs, ARM_sp): 132 | val = task->context.regs.ARM_sp; 133 | break; 134 | case offsetof(struct pt_regs, ARM_ip): 135 | val = task->context.regs.ARM_ip; 136 | break; 137 | case offsetof(struct pt_regs, ARM_fp): 138 | val = task->context.regs.ARM_fp; 139 | break; 140 | case offsetof(struct pt_regs, ARM_r10): 141 | val = task->context.regs.ARM_r10; 142 | break; 143 | case offsetof(struct pt_regs, ARM_r9): 144 | val = task->context.regs.ARM_r9; 145 | break; 146 | case offsetof(struct pt_regs, ARM_r8): 147 | val = task->context.regs.ARM_r8; 148 | break; 149 | case offsetof(struct pt_regs, ARM_r7): 150 | val = task->context.regs.ARM_r7; 151 | break; 152 | case offsetof(struct pt_regs, ARM_r6): 153 | val = task->context.regs.ARM_r6; 154 | break; 155 | case offsetof(struct pt_regs, ARM_r5): 156 | val = task->context.regs.ARM_r5; 157 | break; 158 | case offsetof(struct pt_regs, ARM_r4): 159 | val = task->context.regs.ARM_r4; 160 | break; 161 | case offsetof(struct pt_regs, ARM_r3): 162 | val = task->context.regs.ARM_r3; 163 | break; 164 | case offsetof(struct pt_regs, ARM_r2): 165 | val = task->context.regs.ARM_r2; 166 | break; 167 | case offsetof(struct pt_regs, ARM_r1): 168 | val = task->context.regs.ARM_r1; 169 | break; 170 | case offsetof(struct pt_regs, ARM_r0): 171 | val = task->context.regs.ARM_r0; 172 | break; 173 | case offsetof(struct pt_regs, ARM_ORIG_r0): 174 | val = task->context.regs.ARM_ORIG_r0; 175 | break; 176 | default: 177 | abort(); 178 | } 179 | return val; 180 | } 181 | 182 | -------------------------------------------------------------------------------- /sysdeps/linux-gnu/ioevent.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #define _GNU_SOURCE 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "common.h" 32 | #include "ioevent.h" 33 | 34 | struct io_watch_event { 35 | int (*func)(void); 36 | }; 37 | 38 | struct pollfd *io_watch_poll; 39 | struct io_watch_event *io_watch_event; 40 | static unsigned int io_watch_size; 41 | static unsigned int io_watch_elems; 42 | 43 | static inline void io_watch_set(unsigned int idx, int fd, ioevent_func func) 44 | { 45 | io_watch_event[idx].func = func; 46 | 47 | io_watch_poll[idx].fd = fd; 48 | io_watch_poll[idx].events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL; 49 | } 50 | 51 | int ioevent_add_input(int fd, ioevent_func func) 52 | { 53 | unsigned int i; 54 | 55 | for(i = 0; i < io_watch_elems; ++i) { 56 | if (io_watch_poll[i].fd == fd) { 57 | io_watch_set(i, fd, func); 58 | return 1; 59 | } 60 | } 61 | 62 | if (io_watch_size == io_watch_elems) { 63 | io_watch_size += 16; 64 | 65 | io_watch_poll = realloc(io_watch_poll, sizeof(struct pollfd) * io_watch_size); 66 | io_watch_event = realloc(io_watch_event, sizeof(struct io_watch_event) * io_watch_size); 67 | } 68 | 69 | io_watch_set(io_watch_elems, fd, func); 70 | 71 | ++io_watch_elems; 72 | 73 | return 0; 74 | } 75 | 76 | int ioevent_del_input(int fd) 77 | { 78 | unsigned int i; 79 | 80 | for(i = 0; i < io_watch_elems; ++i) { 81 | if (io_watch_poll[i].fd == fd) { 82 | --io_watch_elems; 83 | 84 | if (i != io_watch_elems) { 85 | io_watch_set(i, 86 | io_watch_poll[io_watch_elems].fd, 87 | io_watch_event[io_watch_elems].func 88 | ); 89 | } 90 | return 0; 91 | } 92 | } 93 | return -1; 94 | } 95 | 96 | int ioevent_watch(int timeout) 97 | { 98 | unsigned int i; 99 | int ret; 100 | 101 | ret = TEMP_FAILURE_RETRY(poll(io_watch_poll, io_watch_elems, timeout)); 102 | if (ret < 0) 103 | return ret; 104 | 105 | ret = 0; 106 | 107 | for(i = 0; i < io_watch_elems; ++i) { 108 | if (io_watch_poll[i].revents) { 109 | if (io_watch_event[i].func() == -1) 110 | ret = -1; 111 | } 112 | } 113 | return ret; 114 | } 115 | 116 | ioevent_func ioevent_set_input_func(int fd, ioevent_func func) 117 | { 118 | unsigned int i; 119 | 120 | for(i = 0; i < io_watch_elems; ++i) { 121 | if (io_watch_poll[i].fd == fd) { 122 | int (*old)(void) = io_watch_event[i].func; 123 | 124 | io_watch_event[i].func = func; 125 | 126 | return old; 127 | } 128 | } 129 | return NULL; 130 | } 131 | 132 | int ioevent_wait_input(int fd, int timeout) 133 | { 134 | struct pollfd pfd[1]; 135 | 136 | pfd[0].fd = fd; 137 | pfd[0].events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL; 138 | 139 | return TEMP_FAILURE_RETRY(poll(pfd, ARRAY_SIZE(pfd), timeout)); 140 | } 141 | 142 | -------------------------------------------------------------------------------- /sysdeps/linux-gnu/ioevent.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_SYSDEPS_LINUX_GNU_IOEVENT_H 24 | #define _INC_SYSDEPS_LINUX_GNU_IOEVENT_H 25 | 26 | typedef int (*ioevent_func)(void); 27 | 28 | int ioevent_add_input(int fd, ioevent_func func); 29 | int ioevent_del_input(int fd); 30 | int ioevent_watch(int timeout); 31 | int ioevent_wait_input(int fd, int timeout); 32 | ioevent_func ioevent_set_input_func(int fd, ioevent_func func); 33 | 34 | #endif 35 | 36 | -------------------------------------------------------------------------------- /sysdeps/linux-gnu/os.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_SYSDEPS_LINUX_GNU_OS_H 24 | #define _INC_SYSDEPS_LINUX_GNU_OS_H 25 | 26 | #include 27 | 28 | #include "mtrace.h" 29 | 30 | #ifndef PAGE_SIZE 31 | #define PAGE_SIZE 4096 32 | #endif 33 | 34 | #define OS_HAVE_PROCESS_DATA 35 | struct os_task_data { 36 | arch_addr_t debug_addr; 37 | int debug_state; 38 | }; 39 | 40 | #endif 41 | 42 | -------------------------------------------------------------------------------- /sysdeps/linux-gnu/ppc/arch.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #include "arch.h" 24 | #include "mtelf.h" 25 | 26 | int is_64bit(struct mt_elf *mte) 27 | { 28 | return !mte_cmp_machine(mte, EM_PPC); 29 | } 30 | 31 | -------------------------------------------------------------------------------- /sysdeps/linux-gnu/ppc/arch.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_SYSDEPS_LINUX_GNU_PPC_ARCH_H 24 | #define _INC_SYSDEPS_LINUX_GNU_PPC_ARCH_H 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 } 32 | #define BREAKPOINT_LENGTH 4 33 | #define DECR_PC_AFTER_BREAK 0 34 | #define ARCH_ENDIAN_BIG 35 | #define ARCH_HAVE_ATOMIC_SINGLESTEP 36 | 37 | #define MT_ELFCLASS ELFCLASS32 38 | #define MT_ELF_MACHINE EM_PPC 39 | 40 | #ifdef __powerpc64__ 41 | #define MT_ELFCLASS2 ELFCLASS64 42 | #define MT_ELF_MACHINE2 EM_PPC64 43 | #endif 44 | 45 | #define DWARF_TO_REGNUM 46 | 47 | #define HW_BREAKPOINTS 0 48 | 49 | struct context { 50 | struct pt_regs regs; 51 | }; 52 | 53 | #endif 54 | 55 | -------------------------------------------------------------------------------- /sysdeps/linux-gnu/ppc/cpu.cmake: -------------------------------------------------------------------------------- 1 | list(APPEND C_SRCS 2 | sysdeps/${MT_OS}/${MT_CPU}/arch.c 3 | sysdeps/${MT_OS}/${MT_CPU}/dwarf-ppc.c 4 | sysdeps/${MT_OS}/${MT_CPU}/regs.c 5 | ) 6 | 7 | -------------------------------------------------------------------------------- /sysdeps/linux-gnu/ppc/dwarf-ppc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "common.h" 29 | #include "backend.h" 30 | #include "debug.h" 31 | #include "dwarf.h" 32 | #include "task.h" 33 | 34 | #define R_LR 65 35 | #define R_CTR 66 36 | #define R_CR0 68 37 | #define R_CR1 69 38 | #define R_CR2 70 39 | #define R_CR3 71 40 | #define R_CR4 72 41 | #define R_XER 76 42 | #define R_VR0 77 43 | #define R_VRSAVE 109 44 | #define R_VSCR 110 45 | #define R_SPEFSCR 112 46 | #define R_FRAME_POINTER 113 47 | 48 | enum dwarf_ppc_regnum { 49 | DWARF_PPC_R0, 50 | DWARF_PPC_R1, /* called STACK_POINTER in gcc */ 51 | DWARF_PPC_R2, 52 | DWARF_PPC_R3, 53 | DWARF_PPC_R4, 54 | DWARF_PPC_R5, 55 | DWARF_PPC_R6, 56 | DWARF_PPC_R7, 57 | DWARF_PPC_R8, 58 | DWARF_PPC_R9, 59 | DWARF_PPC_R10, 60 | DWARF_PPC_R11, /* called STATIC_CHAIN in gcc */ 61 | DWARF_PPC_R12, 62 | DWARF_PPC_R13, 63 | DWARF_PPC_R14, 64 | DWARF_PPC_R15, 65 | DWARF_PPC_R16, 66 | DWARF_PPC_R17, 67 | DWARF_PPC_R18, 68 | DWARF_PPC_R19, 69 | DWARF_PPC_R20, 70 | DWARF_PPC_R21, 71 | DWARF_PPC_R22, 72 | DWARF_PPC_R23, 73 | DWARF_PPC_R24, 74 | DWARF_PPC_R25, 75 | DWARF_PPC_R26, 76 | DWARF_PPC_R27, 77 | DWARF_PPC_R28, 78 | DWARF_PPC_R29, 79 | DWARF_PPC_R30, 80 | DWARF_PPC_R31, /* called HARD_FRAME_POINTER in gcc */ 81 | DWARF_PPC_LR, /* Link Register */ 82 | DWARF_PPC_CTR, /* Count Register */ 83 | DWARF_PPC_CR0, /* Condition Register */ 84 | DWARF_PPC_CR1, 85 | DWARF_PPC_CR2, 86 | DWARF_PPC_CR3, 87 | DWARF_PPC_CR4, 88 | DWARF_PPC_XER, /* Fixed-Point Status and Control Register */ 89 | DWARF_PPC_VR0, 90 | DWARF_PPC_VRSAVE, 91 | DWARF_PPC_VSCR, 92 | DWARF_PPC_FPSCR, 93 | DWARF_PPC_FRAME_POINTER, 94 | }; 95 | 96 | static const uint8_t dwarf_to_regnum_map[] = { 97 | [DWARF_PPC_R0] = PT_R0 + 1, 98 | [DWARF_PPC_R1] = PT_R1 + 1, 99 | [DWARF_PPC_R2] = PT_R2 + 1, 100 | [DWARF_PPC_R3] = PT_R3 + 1, 101 | [DWARF_PPC_R4] = PT_R4 + 1, 102 | [DWARF_PPC_R5] = PT_R5 + 1, 103 | [DWARF_PPC_R6] = PT_R6 + 1, 104 | [DWARF_PPC_R7] = PT_R7 + 1, 105 | [DWARF_PPC_R8] = PT_R8 + 1, 106 | [DWARF_PPC_R9] = PT_R9 + 1, 107 | [DWARF_PPC_R10] = PT_R10 + 1, 108 | [DWARF_PPC_R11] = PT_R11 + 1, 109 | [DWARF_PPC_R12] = PT_R12 + 1, 110 | [DWARF_PPC_R13] = PT_R13 + 1, 111 | [DWARF_PPC_R14] = PT_R14 + 1, 112 | [DWARF_PPC_R15] = PT_R15 + 1, 113 | [DWARF_PPC_R16] = PT_R16 + 1, 114 | [DWARF_PPC_R17] = PT_R17 + 1, 115 | [DWARF_PPC_R18] = PT_R18 + 1, 116 | [DWARF_PPC_R19] = PT_R19 + 1, 117 | [DWARF_PPC_R20] = PT_R20 + 1, 118 | [DWARF_PPC_R21] = PT_R21 + 1, 119 | [DWARF_PPC_R22] = PT_R22 + 1, 120 | [DWARF_PPC_R23] = PT_R23 + 1, 121 | [DWARF_PPC_R24] = PT_R24 + 1, 122 | [DWARF_PPC_R25] = PT_R25 + 1, 123 | [DWARF_PPC_R26] = PT_R26 + 1, 124 | [DWARF_PPC_R27] = PT_R27 + 1, 125 | [DWARF_PPC_R28] = PT_R28 + 1, 126 | [DWARF_PPC_R29] = PT_R29 + 1, 127 | [DWARF_PPC_R30] = PT_R30 + 1, 128 | [DWARF_PPC_R31] = PT_R31 + 1, 129 | [DWARF_PPC_LR] = PT_LNK + 1, 130 | [DWARF_PPC_CTR] = PT_CTR + 1, 131 | [DWARF_PPC_CR0] = PT_CCR + 1, 132 | [DWARF_PPC_CR1] = 0, 133 | [DWARF_PPC_CR2] = 0, 134 | [DWARF_PPC_CR3] = 0, 135 | [DWARF_PPC_CR4] = 0, 136 | [DWARF_PPC_XER] = PT_XER + 1, 137 | [DWARF_PPC_VR0] = 0, 138 | [DWARF_PPC_VRSAVE] = 0, 139 | [DWARF_PPC_VSCR] = 0, 140 | [DWARF_PPC_FPSCR] = 0, 141 | [DWARF_PPC_FRAME_POINTER] = 0, 142 | }; 143 | 144 | int dwarf_arch_init(struct dwarf_addr_space *as) 145 | { 146 | as->num_regs = ARRAY_SIZE(dwarf_to_regnum_map); 147 | 148 | as->ip_reg = as->num_regs; /* not in dwarf, invalid register */ 149 | as->ret_reg = DWARF_PPC_R1; 150 | 151 | return 0; 152 | } 153 | 154 | int dwarf_arch_init_unwind(struct dwarf_addr_space *as) 155 | { 156 | struct dwarf_cursor *c = &as->cursor; 157 | unsigned int i; 158 | 159 | for(i = DWARF_PPC_R0; i <= DWARF_PPC_R31; ++i) 160 | c->loc[i] = DWARF_REG_LOC(i); 161 | 162 | c->loc[DWARF_PPC_LR] = DWARF_REG_LOC(DWARF_PPC_LR); 163 | c->loc[DWARF_PPC_CTR] = DWARF_REG_LOC(DWARF_PPC_CTR); 164 | c->loc[DWARF_PPC_CR0] = DWARF_REG_LOC(DWARF_PPC_CR0); 165 | c->loc[DWARF_PPC_CR1] = DWARF_REG_LOC(DWARF_PPC_CR1); 166 | c->loc[DWARF_PPC_CR2] = DWARF_REG_LOC(DWARF_PPC_CR2); 167 | c->loc[DWARF_PPC_CR3] = DWARF_REG_LOC(DWARF_PPC_CR3); 168 | c->loc[DWARF_PPC_CR4] = DWARF_REG_LOC(DWARF_PPC_CR4); 169 | c->loc[DWARF_PPC_XER] = DWARF_REG_LOC(DWARF_PPC_XER); 170 | c->loc[DWARF_PPC_VR0] = DWARF_REG_LOC(DWARF_PPC_VR0); 171 | c->loc[DWARF_PPC_VRSAVE] = DWARF_REG_LOC(DWARF_PPC_VRSAVE); 172 | c->loc[DWARF_PPC_VSCR] = DWARF_REG_LOC(DWARF_PPC_VSCR); 173 | c->loc[DWARF_PPC_FPSCR] = DWARF_REG_LOC(DWARF_PPC_FPSCR); 174 | c->loc[DWARF_PPC_FRAME_POINTER] = DWARF_REG_LOC(DWARF_PPC_FRAME_POINTER); 175 | 176 | c->ip = fetch_reg(c->task, PT_LNK); 177 | c->cfa = fetch_reg(c->task, PT_R1); 178 | 179 | c->use_prev_instr = 0; 180 | 181 | return 0; 182 | } 183 | 184 | static int is_signal_frame(struct dwarf_cursor *c) 185 | { 186 | return c->dci.signal_frame; 187 | } 188 | 189 | #define BACK_CHAIN 0 190 | #define LR_SAVE 1 191 | 192 | int dwarf_arch_step(struct dwarf_addr_space *as) 193 | { 194 | struct dwarf_cursor *c = &as->cursor; 195 | arch_addr_t cfa; 196 | int ret; 197 | 198 | if (is_signal_frame(c)) 199 | return -DWARF_EBADFRAME; 200 | 201 | if ((ret = dwarf_get(as, DWARF_MEM_LOC(c->cfa + BACK_CHAIN * DWARF_ADDR_SIZE(as)), &cfa)) < 0) { 202 | debug(DEBUG_DWARF, "Unable to retrieve CFA from back chain in stack frame - %d", ret); 203 | return ret; 204 | } 205 | 206 | if (cfa <= c->cfa || cfa - c->cfa > 128 * 1024) 207 | return -DWARF_EBADFRAME; 208 | 209 | c->cfa = cfa; 210 | 211 | if ((ret = dwarf_get(as, DWARF_MEM_LOC(c->cfa + LR_SAVE * DWARF_ADDR_SIZE(as)), &c->ip)) < 0) { 212 | debug(DEBUG_DWARF, "Unable to retrieve IP from lr save in stack frame - %d", ret); 213 | return ret; 214 | } 215 | 216 | return 0; 217 | } 218 | 219 | int dwarf_arch_map_reg(struct dwarf_addr_space *as, unsigned int reg) 220 | { 221 | int regnum; 222 | 223 | if (reg >= ARRAY_SIZE(dwarf_to_regnum_map)) 224 | return -DWARF_EBADREG; 225 | 226 | regnum = dwarf_to_regnum_map[reg]; 227 | if (!regnum) 228 | return -DWARF_EBADREG; 229 | 230 | return regnum -1; 231 | } 232 | 233 | unsigned int dwarf_to_regnum(unsigned int num) 234 | { 235 | if (num < 32) 236 | return DWARF_PPC_R0 + num; 237 | 238 | switch(num) { 239 | case R_LR: 240 | return DWARF_PPC_LR; 241 | case R_CTR: 242 | return DWARF_PPC_CTR; 243 | case R_CR0: 244 | return DWARF_PPC_CR0; 245 | case R_CR1: 246 | return DWARF_PPC_CR1; 247 | case R_CR2: 248 | return DWARF_PPC_CR2; 249 | case R_CR3: 250 | return DWARF_PPC_CR3; 251 | case R_CR4: 252 | return DWARF_PPC_CR4; 253 | case R_XER: 254 | return DWARF_PPC_XER; 255 | case R_VR0: 256 | return DWARF_PPC_VR0; 257 | case R_VRSAVE: 258 | return DWARF_PPC_VRSAVE; 259 | case R_VSCR: 260 | return DWARF_PPC_VSCR; 261 | case R_SPEFSCR: 262 | return DWARF_PPC_FPSCR; 263 | case R_FRAME_POINTER: 264 | return DWARF_PPC_FRAME_POINTER; 265 | default: 266 | break; 267 | } 268 | return ~0; 269 | } 270 | 271 | int dwarf_arch_check_call(struct dwarf_addr_space *as, arch_addr_t ip) 272 | { 273 | return 1; 274 | } 275 | 276 | -------------------------------------------------------------------------------- /sysdeps/linux-gnu/ppc/regs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | #include "config.h" 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "backend.h" 31 | #include "task.h" 32 | #include "arch.h" 33 | 34 | #if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) 35 | #define PTRACE_PEEKUSER PTRACE_PEEKUSR 36 | #endif 37 | 38 | #if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) 39 | #define PTRACE_POKEUSER PTRACE_POKEUSR 40 | #endif 41 | 42 | static inline unsigned long fix_machine(struct task *task, unsigned long val) 43 | { 44 | if (!task_is_64bit(task)) 45 | val &= 0xffffffff; 46 | 47 | return val; 48 | } 49 | 50 | arch_addr_t get_instruction_pointer(struct task *task) 51 | { 52 | #ifdef __powerpc64__ 53 | return ARCH_ADDR_T(fix_machine(task, task->context.regs.nip)); 54 | #else 55 | return ARCH_ADDR_T(task->context.regs.nip); 56 | #endif 57 | } 58 | 59 | void set_instruction_pointer(struct task *task, arch_addr_t addr) 60 | { 61 | unsigned long val = (unsigned long)addr; 62 | 63 | #ifdef __powerpc64__ 64 | val = fix_machine(task, val); 65 | #endif 66 | if (task->context.regs.nip == val) 67 | return; 68 | 69 | task->context.regs.nip = val; 70 | 71 | if (ptrace(PTRACE_POKEUSER, task->pid, sizeof(unsigned long) * PT_NIP, val) == -1) { 72 | if (errno != ESRCH) 73 | fprintf(stderr, "pid=%d Couldn't set instruction pointer: %s\n", task->pid, strerror(errno)); 74 | } 75 | } 76 | 77 | unsigned int ip_reg_addr(void) 78 | { 79 | return sizeof(unsigned long) * PT_NIP; 80 | } 81 | 82 | arch_addr_t get_return_addr(struct task *task) 83 | { 84 | #ifdef __powerpc64__ 85 | return ARCH_ADDR_T(fix_machine(task, task->context.regs.link)); 86 | #endif 87 | return ARCH_ADDR_T(task->context.regs.link); 88 | } 89 | 90 | int fetch_context(struct task *task) 91 | { 92 | if (ptrace(PTRACE_GETREGS, task->pid, 0, &task->context.regs) == -1) { 93 | if (errno != ESRCH) 94 | fprintf(stderr, "pid=%d Couldn't fetch register context: %s\n", task->pid, strerror(errno)); 95 | 96 | memset(&task->context.regs, 0, sizeof(task->context.regs)); 97 | return -1; 98 | } 99 | return 0; 100 | } 101 | 102 | void save_param_context(struct task *task) 103 | { 104 | task->saved_context = task->context; 105 | } 106 | 107 | #ifdef __powerpc64__ 108 | static unsigned long fetch_stack_64(struct task *task, unsigned int param) 109 | { 110 | uint64_t val; 111 | 112 | copy_from_proc(task, (void *)task->saved_context.regs.gpr[PT_R1] + (param - 8 + 14) * sizeof(val), &val, sizeof(val)); 113 | 114 | return val; 115 | } 116 | #endif 117 | 118 | static unsigned long fetch_stack_32(struct task *task, unsigned int param) 119 | { 120 | uint32_t val; 121 | 122 | copy_from_proc(task, task->saved_context.regs.gpr[PT_R1] + (param - 8 + 2) * sizeof(val), &val, sizeof(val)); 123 | 124 | return val; 125 | } 126 | 127 | unsigned long fetch_param(struct task *task, unsigned int param) 128 | { 129 | unsigned long val; 130 | 131 | switch (param) { 132 | case 0: 133 | val = task->saved_context.regs.gpr[PT_R3]; 134 | break; 135 | case 1: 136 | val = task->saved_context.regs.gpr[PT_R4]; 137 | break; 138 | case 2: 139 | val = task->saved_context.regs.gpr[PT_R5]; 140 | break; 141 | case 3: 142 | val = task->saved_context.regs.gpr[PT_R6]; 143 | break; 144 | case 4: 145 | val = task->saved_context.regs.gpr[PT_R7]; 146 | break; 147 | case 5: 148 | val = task->saved_context.regs.gpr[PT_R8]; 149 | break; 150 | case 6: 151 | val = task->saved_context.regs.gpr[PT_R9]; 152 | break; 153 | case 7: 154 | val = task->saved_context.regs.gpr[PT_R10]; 155 | break; 156 | default: 157 | #ifdef __powerpc64__ 158 | if (task_is_64bit(task)) { 159 | val = fetch_stack_64(task, param); 160 | break; 161 | } 162 | #endif 163 | val = fetch_stack_32(task, param); 164 | break; 165 | } 166 | #ifdef __powerpc64__ 167 | val = fix_machine(task, val); 168 | #endif 169 | return val; 170 | } 171 | 172 | unsigned long fetch_retval(struct task *task) 173 | { 174 | #ifdef __powerpc64__ 175 | return fix_machine(task, task->context.regs.gpr[PT_R3]); 176 | #else 177 | return task->context.regs.gpr[PT_R3]; 178 | #endif 179 | } 180 | 181 | unsigned long fetch_reg(struct task *task, unsigned int reg) 182 | { 183 | unsigned long val; 184 | 185 | switch(reg) { 186 | case PT_R0: 187 | val = task->context.regs.gpr[PT_R0]; 188 | break; 189 | case PT_R1: 190 | val = task->context.regs.gpr[PT_R1]; 191 | break; 192 | case PT_R2: 193 | val = task->context.regs.gpr[PT_R2]; 194 | break; 195 | case PT_R3: 196 | val = task->context.regs.gpr[PT_R3]; 197 | break; 198 | case PT_R4: 199 | val = task->context.regs.gpr[PT_R4]; 200 | break; 201 | case PT_R5: 202 | val = task->context.regs.gpr[PT_R5]; 203 | break; 204 | case PT_R6: 205 | val = task->context.regs.gpr[PT_R6]; 206 | break; 207 | case PT_R7: 208 | val = task->context.regs.gpr[PT_R7]; 209 | break; 210 | case PT_R8: 211 | val = task->context.regs.gpr[PT_R8]; 212 | break; 213 | case PT_R9: 214 | val = task->context.regs.gpr[PT_R9]; 215 | break; 216 | case PT_R10: 217 | val = task->context.regs.gpr[PT_R10]; 218 | break; 219 | case PT_R11: 220 | val = task->context.regs.gpr[PT_R11]; 221 | break; 222 | case PT_R12: 223 | val = task->context.regs.gpr[PT_R12]; 224 | break; 225 | case PT_R13: 226 | val = task->context.regs.gpr[PT_R13]; 227 | break; 228 | case PT_R14: 229 | val = task->context.regs.gpr[PT_R14]; 230 | break; 231 | case PT_R15: 232 | val = task->context.regs.gpr[PT_R15]; 233 | break; 234 | case PT_R16: 235 | val = task->context.regs.gpr[PT_R16]; 236 | break; 237 | case PT_R17: 238 | val = task->context.regs.gpr[PT_R17]; 239 | break; 240 | case PT_R18: 241 | val = task->context.regs.gpr[PT_R18]; 242 | break; 243 | case PT_R19: 244 | val = task->context.regs.gpr[PT_R19]; 245 | break; 246 | case PT_R20: 247 | val = task->context.regs.gpr[PT_R20]; 248 | break; 249 | case PT_R21: 250 | val = task->context.regs.gpr[PT_R21]; 251 | break; 252 | case PT_R22: 253 | val = task->context.regs.gpr[PT_R22]; 254 | break; 255 | case PT_R23: 256 | val = task->context.regs.gpr[PT_R23]; 257 | break; 258 | case PT_R24: 259 | val = task->context.regs.gpr[PT_R24]; 260 | break; 261 | case PT_R25: 262 | val = task->context.regs.gpr[PT_R25]; 263 | break; 264 | case PT_R26: 265 | val = task->context.regs.gpr[PT_R26]; 266 | break; 267 | case PT_R27: 268 | val = task->context.regs.gpr[PT_R27]; 269 | break; 270 | case PT_R28: 271 | val = task->context.regs.gpr[PT_R28]; 272 | break; 273 | case PT_R29: 274 | val = task->context.regs.gpr[PT_R29]; 275 | break; 276 | case PT_R30: 277 | val = task->context.regs.gpr[PT_R30]; 278 | break; 279 | case PT_R31: 280 | val = task->context.regs.gpr[PT_R31]; 281 | break; 282 | case PT_NIP: 283 | val = task->context.regs.nip; 284 | break; 285 | case PT_MSR: 286 | val = task->context.regs.msr; 287 | break; 288 | case PT_ORIG_R3: 289 | val = task->context.regs.orig_gpr3; 290 | break; 291 | case PT_CTR: 292 | val = task->context.regs.ctr; 293 | break; 294 | case PT_LNK: 295 | val = task->context.regs.link; 296 | break; 297 | case PT_XER: 298 | val = task->context.regs.xer; 299 | break; 300 | case PT_CCR: 301 | val = task->context.regs.ccr; 302 | break; 303 | #ifndef __powerpc64__ 304 | case PT_MQ: 305 | val = task->context.regs.mq; 306 | break; 307 | #else 308 | case PT_SOFTE: 309 | val = task->context.regs.softe; 310 | break; 311 | #endif 312 | case PT_TRAP: 313 | val = task->context.regs.trap; 314 | break; 315 | case PT_DAR: 316 | val = task->context.regs.dar; 317 | break; 318 | case PT_DSISR: 319 | val = task->context.regs.dsisr; 320 | break; 321 | case PT_RESULT: 322 | val = task->context.regs.result; 323 | break; 324 | default: 325 | abort(); 326 | } 327 | return fix_machine(task, val); 328 | } 329 | 330 | -------------------------------------------------------------------------------- /sysdeps/linux-gnu/socket.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #define _GNU_SOURCE 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include "common.h" 39 | #include "socket.h" 40 | #include "memtrace.h" 41 | 42 | struct sock_u_descr { 43 | struct sockaddr_un addr; 44 | socklen_t addrlen; 45 | }; 46 | 47 | static const int const_int_1 = 1; 48 | 49 | ssize_t safe_read(int fd, void *dest, size_t n) 50 | { 51 | int off = 0; 52 | ssize_t ret; 53 | 54 | for(;;) { 55 | ret = TEMP_FAILURE_RETRY(read(fd, dest + off, n)); 56 | 57 | if (ret <= 0) 58 | return ret; 59 | 60 | if ((size_t)ret >= n) 61 | break; 62 | 63 | off += ret; 64 | n -= ret; 65 | } 66 | return off + n; 67 | } 68 | 69 | int sock_send_msg(int fd, enum mt_operation op, uint32_t pid, const void *payload, unsigned int payload_len) 70 | { 71 | struct mt_msg mt_msg; 72 | struct iovec io[2]; 73 | struct msghdr msghdr; 74 | int ret; 75 | 76 | if (fd == -1) 77 | return -1; 78 | 79 | msghdr.msg_name = NULL; 80 | msghdr.msg_namelen = 0; 81 | msghdr.msg_iov = io; 82 | msghdr.msg_iovlen = 1; 83 | msghdr.msg_control = 0; 84 | msghdr.msg_controllen = 0; 85 | msghdr.msg_flags = 0; 86 | 87 | io[0].iov_base = &mt_msg; 88 | io[0].iov_len = sizeof(mt_msg); 89 | 90 | if (payload_len) { 91 | io[msghdr.msg_iovlen].iov_base = (void *)payload; 92 | io[msghdr.msg_iovlen].iov_len = payload_len; 93 | 94 | msghdr.msg_iovlen++; 95 | } 96 | 97 | mt_msg.operation = op; 98 | 99 | if (op > 0xff) { 100 | mt_msg.pid = bswap_32(pid); 101 | mt_msg.payload_len = bswap_32(payload_len); 102 | } 103 | else { 104 | mt_msg.pid = pid; 105 | mt_msg.payload_len = payload_len; 106 | } 107 | 108 | ret = TEMP_FAILURE_RETRY(sendmsg(fd, &msghdr, MSG_NOSIGNAL)); 109 | 110 | if ((size_t)ret != sizeof(mt_msg) + payload_len) 111 | return -1; 112 | 113 | return ret; 114 | } 115 | 116 | static int sock_unix(const char *path, struct sock_u_descr *descr, int create) 117 | { 118 | struct stat statbuf; 119 | 120 | if (stat(path, &statbuf) >= 0) { 121 | if (!S_ISSOCK(statbuf.st_mode)) 122 | return -1; 123 | 124 | if (create) 125 | unlink(path); 126 | } 127 | 128 | descr->addr.sun_family = AF_UNIX; 129 | safe_strncpy(descr->addr.sun_path, path, sizeof(descr->addr.sun_path)); 130 | descr->addrlen = sizeof(descr->addr.sun_family) + strlen(descr->addr.sun_path); 131 | 132 | return socket(PF_UNIX, SOCK_STREAM, 0); 133 | } 134 | 135 | static struct addrinfo *sock_addr(const char *node, const char *service, int flags) 136 | { 137 | struct addrinfo *result; 138 | struct addrinfo hints; 139 | int ret; 140 | 141 | memset(&hints, 0, sizeof(struct addrinfo)); 142 | hints.ai_family = AF_UNSPEC; 143 | hints.ai_socktype = SOCK_STREAM; 144 | hints.ai_flags = flags; 145 | hints.ai_protocol = 0; 146 | hints.ai_canonname = NULL; 147 | hints.ai_addr = NULL; 148 | hints.ai_next = NULL; 149 | 150 | ret = getaddrinfo(node, service, &hints, &result); 151 | if (ret != 0) { 152 | fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret)); 153 | return NULL; 154 | } 155 | 156 | return result; 157 | } 158 | 159 | int connect_to(const char *node, const char *service) 160 | { 161 | int sfd; 162 | 163 | if (*node == '/' || *node == '.') { 164 | struct sock_u_descr descr; 165 | 166 | sfd = sock_unix(node, &descr, 0); 167 | if (sfd == -1) 168 | return -1; 169 | 170 | if (connect(sfd, &descr.addr, descr.addrlen) == -1) { 171 | close(sfd); 172 | return -1; 173 | } 174 | } 175 | else { 176 | struct addrinfo *rp; 177 | 178 | for (rp = sock_addr(node, service, 0); rp != NULL; rp = rp->ai_next) { 179 | sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); 180 | if (sfd == -1) 181 | continue; 182 | 183 | if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) 184 | break; 185 | 186 | close(sfd); 187 | } 188 | 189 | if (!rp) 190 | return -1; 191 | } 192 | return sfd; 193 | } 194 | 195 | int is_named(const char *node) 196 | { 197 | return node && (*node == '/' || *node == '.'); 198 | } 199 | 200 | int bind_to(const char *node, const char *service) 201 | { 202 | int sfd; 203 | 204 | if (is_named(node)) { 205 | struct sock_u_descr descr; 206 | 207 | sfd = sock_unix(node, &descr, 1); 208 | if (sfd == -1) 209 | return -1; 210 | 211 | if (bind(sfd, &descr.addr, descr.addrlen) < 0) { 212 | close(sfd); 213 | return -1; 214 | } 215 | } 216 | else { 217 | struct addrinfo *rp; 218 | int size = 10 * 1024 * 1024; 219 | static const int one = 1; 220 | 221 | for (rp = sock_addr(node, service, AI_PASSIVE); rp != NULL; rp = rp->ai_next) { 222 | sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); 223 | if (sfd == -1) 224 | continue; 225 | 226 | if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &const_int_1, sizeof(const_int_1))) 227 | fatal("setsockopt (%s)", strerror(errno)); 228 | 229 | if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) 230 | break; 231 | 232 | close(sfd); 233 | } 234 | 235 | if (!rp) 236 | return -1; 237 | 238 | if (setsockopt(sfd, SOL_TCP, TCP_NODELAY, &one, sizeof(one)) == -1) 239 | fatal("TCP_NODELAY: %s\n", strerror(errno)); 240 | 241 | if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) == -1) 242 | fatal("SO_SNDBUF: %s\n", strerror(errno)); 243 | } 244 | 245 | return sfd; 246 | } 247 | 248 | int create_socket_pair(int sv[2]) 249 | { 250 | if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sv) == -1) { 251 | perror("socketpair"); 252 | return -1; 253 | } 254 | return 0; 255 | } 256 | 257 | -------------------------------------------------------------------------------- /sysdeps/linux-gnu/socket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_SYSDEPS_LINUX_GNU_SOCKET_H 24 | #define _INC_SYSDEPS_LINUX_GNU_SOCKET_H 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "common.h" 33 | #include "memtrace.h" 34 | 35 | ssize_t safe_read(int fd, void *dest, size_t n); 36 | int connect_to(const char *node, const char *service); 37 | int bind_to(const char *node, const char *service); 38 | int sock_send_msg(int fd, enum mt_operation op, uint32_t pid, const void *payload, unsigned int payload_len); 39 | int create_socket_pair(int sv[2]); 40 | int is_named(const char *node); 41 | 42 | #endif 43 | 44 | -------------------------------------------------------------------------------- /sysdeps/linux-gnu/sysdeps.cmake: -------------------------------------------------------------------------------- 1 | list(APPEND C_SRCS 2 | sysdeps/${MT_OS}/ioevent.c 3 | sysdeps/${MT_OS}/os.c 4 | sysdeps/${MT_OS}/proc.c 5 | sysdeps/${MT_OS}/socket.c 6 | sysdeps/${MT_OS}/thread.c 7 | sysdeps/${MT_OS}/trace.c 8 | ) 9 | 10 | include_directories("${PROJECT_SOURCE_DIR}/sysdeps/${MT_OS}") 11 | include_directories("${PROJECT_SOURCE_DIR}/sysdeps/${MT_OS}/${MT_CPU}") 12 | 13 | include(${CMAKE_SOURCE_DIR}/sysdeps/${MT_OS}/${MT_CPU}/cpu.cmake) 14 | 15 | -------------------------------------------------------------------------------- /sysdeps/linux-gnu/thread.c: -------------------------------------------------------------------------------- 1 | /* 2 | * phtread thread wrapper 3 | * 4 | * This file is part of mtrace-ng. 5 | * Copyright (C) 2018 Stefani Seibold 6 | * 7 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 8 | * 9 | * This program is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU General Public License as 11 | * published by the Free Software Foundation; either version 2 of the 12 | * License, or (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, but 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 22 | * 02110-1301 USA 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "thread.h" 34 | 35 | struct thread { 36 | pthread_t thread; 37 | int running; 38 | pthread_attr_t attr; 39 | void *arg; 40 | void *(*start_routine)(void *); 41 | }; 42 | 43 | struct thread *thread_new(void) 44 | { 45 | int ret; 46 | 47 | struct thread *thread = malloc(sizeof(*thread)); 48 | 49 | if (!thread) 50 | return NULL; 51 | 52 | thread->running = 0; 53 | 54 | ret = pthread_attr_init(&thread->attr); 55 | if (ret) { 56 | fprintf(stderr, "pthread_attr_init failed: %s\n", strerror(ret)); 57 | goto fail1; 58 | } 59 | 60 | ret = pthread_attr_setdetachstate(&thread->attr, PTHREAD_CREATE_JOINABLE); 61 | if (ret) { 62 | fprintf(stderr, "pthread_attr_setdetachstate failed: %s\n", strerror(ret)); 63 | goto fail2; 64 | } 65 | 66 | ret = pthread_attr_setinheritsched(&thread->attr, PTHREAD_EXPLICIT_SCHED); 67 | if (ret) { 68 | fprintf(stderr, "pthread_attr_setinheritsched failed: %s\n", strerror(ret)); 69 | goto fail2; 70 | } 71 | 72 | return thread; 73 | fail2: 74 | pthread_attr_destroy(&thread->attr); 75 | fail1: 76 | free(thread); 77 | return NULL; 78 | } 79 | 80 | void thread_remove(struct thread *thread) 81 | { 82 | thread_join(thread); 83 | 84 | pthread_attr_destroy(&thread->attr); 85 | 86 | free(thread); 87 | } 88 | 89 | static void *thread_wrapper(void *instance) 90 | { 91 | struct thread *thread = instance; 92 | void *ret; 93 | 94 | pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); 95 | pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); 96 | 97 | ret = thread->start_routine(thread->arg); 98 | 99 | pthread_exit(ret); 100 | 101 | return ret; 102 | } 103 | 104 | int thread_start(struct thread *thread, void *(*start_routine)(void *), void *arg) 105 | { 106 | int ret; 107 | 108 | if (thread->running) 109 | return -1; 110 | 111 | thread->start_routine = start_routine; 112 | thread->arg = arg; 113 | 114 | ret = pthread_create(&thread->thread, &thread->attr, thread_wrapper, thread); 115 | 116 | if (!ret) 117 | thread->running = 1; 118 | 119 | return ret; 120 | } 121 | 122 | void thread_join(struct thread *thread) 123 | { 124 | if (thread->running) { 125 | pthread_join(thread->thread, 0); 126 | 127 | thread->running = 0; 128 | } 129 | } 130 | 131 | void thread_enable_cancel(void) 132 | { 133 | pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); 134 | } 135 | 136 | void thread_disable_cancel(void) 137 | { 138 | pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); 139 | } 140 | 141 | void thread_cancel(struct thread *thread) 142 | { 143 | if (thread->running) 144 | pthread_cancel(thread->thread); 145 | } 146 | 147 | -------------------------------------------------------------------------------- /sysdeps/linux-gnu/x86/arch.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "arch.h" 32 | #include "mtelf.h" 33 | #include "task.h" 34 | 35 | /* Breakpoint access modes */ 36 | #define BP_X 1 37 | #define BP_RW 2 38 | #define BP_W 4 39 | 40 | int get_hw_bp_state(struct task *task, unsigned int n) 41 | { 42 | long ret; 43 | 44 | errno = 0; 45 | ret = ptrace(PTRACE_PEEKUSER, task->pid, offsetof(struct user, u_debugreg[6]), 0); 46 | if (unlikely(ret == -1 && errno)) { 47 | if (errno != ESRCH) 48 | fprintf(stderr, "PTRACE_PEEKUSER u_debugreg[6] pid=%d %s\n", task->pid, strerror(errno)); 49 | 50 | return 0; 51 | } 52 | return (ret & (1 << n)) != 0; 53 | } 54 | 55 | static int _apply_hw_bp(struct task *task, uint32_t dr7) 56 | { 57 | long ret; 58 | 59 | task->arch.dr7 = dr7; 60 | 61 | ret = ptrace(PTRACE_POKEUSER, task->pid, offsetof(struct user, u_debugreg[7]), task->arch.dr7); 62 | if (unlikely(ret)) { 63 | if (errno != ESRCH) { 64 | fprintf(stderr, "PTRACE_POKEUSER u_debugreg[7] pid=%d %s\n", task->pid, strerror(errno)); 65 | return -1; 66 | } 67 | } 68 | return 0; 69 | } 70 | 71 | static inline int apply_hw_bp(struct task *task, uint32_t dr7) 72 | { 73 | if (dr7 == task->arch.dr7) 74 | return 0; 75 | 76 | return _apply_hw_bp(task, dr7); 77 | } 78 | 79 | static int set_breakpoint_addr(struct task *task, arch_addr_t addr, unsigned int n) 80 | { 81 | long ret; 82 | 83 | #ifdef __x86_64__ 84 | if (!task_is_64bit(task)) 85 | addr &= 0xffffffff; 86 | #endif 87 | 88 | if (task->arch.hw_bp[n] == addr) 89 | return 0; 90 | 91 | ret = ptrace(PTRACE_POKEUSER, task->pid, offsetof(struct user, u_debugreg[n]), addr); 92 | if (unlikely(ret)) { 93 | if (errno != ESRCH) { 94 | fprintf(stderr, "PTRACE_POKEUSER u_debugreg[%d] pid=%d %s\n", n, task->pid, strerror(errno)); 95 | return -1; 96 | } 97 | } 98 | 99 | task->arch.hw_bp[n] = addr; 100 | 101 | return 0; 102 | } 103 | 104 | static int set_breakpoint_mode(struct task *task, unsigned int n, int type, int len, int local, int global) 105 | { 106 | uint32_t mode; 107 | uint32_t dr7, mask; 108 | 109 | mask = (0b1111U << (16 + 4 * n)) | (0b11U << (2 * n)); 110 | 111 | switch(type) { 112 | case BP_X: 113 | mode = 0b0000U; 114 | break; 115 | case BP_W: 116 | mode = 0b0001U; 117 | break; 118 | case BP_RW: 119 | mode = 0b0011U; 120 | break; 121 | default: 122 | fprintf(stderr, "invalid hw breakpoint type\n"); 123 | return -1; 124 | } 125 | 126 | switch(len) { 127 | case 1: 128 | mode |= 0b0000U; 129 | break; 130 | case 2: 131 | mode |= 0b0100U; 132 | break; 133 | case 4: 134 | mode |= 0b1100U; 135 | break; 136 | case 8: 137 | mode |= 0b1000U; 138 | break; 139 | } 140 | 141 | dr7 = task->arch.dr7 & ~mask; 142 | 143 | dr7 |= mode << (16 + 4 * n); 144 | 145 | if (local) { 146 | dr7 |= 0b01U << (2 * n); 147 | dr7 |= 1 << 8; 148 | } 149 | else 150 | if (!(dr7 & 0b01010101U)) 151 | dr7 &= ~(1 << 8); 152 | 153 | if (global) { 154 | dr7 |= 0b10U << (2 * n); 155 | dr7 |= 1 << 9; 156 | } 157 | else 158 | if (!(dr7 & 0b10101010U)) 159 | dr7 &= ~(1 << 9); 160 | 161 | return apply_hw_bp(task, dr7); 162 | } 163 | 164 | int set_hw_bp(struct task *task, unsigned int n, arch_addr_t addr) 165 | { 166 | #if 0 167 | if (reset_hw_bp(task, n) == -1) 168 | return -1; 169 | #endif 170 | if (unlikely(set_breakpoint_addr(task, addr, n) == -1)) 171 | return -1; 172 | 173 | return set_breakpoint_mode(task, 174 | n, /* n */ 175 | BP_X, /* type */ 176 | 1, /* len */ 177 | 1, /* local */ 178 | 0 /* global */ 179 | ); 180 | } 181 | 182 | int reset_hw_bp(struct task *task, unsigned int n) 183 | { 184 | uint32_t dr7, mask; 185 | 186 | mask = (0b1111U << (16 + 4 * n)) | (0b11U << (2 * n)); 187 | 188 | dr7 = task->arch.dr7 & ~mask; 189 | 190 | if (!(dr7 & 0b01010101U)) 191 | dr7 &= ~(1 << 8); 192 | 193 | if (!(dr7 & 0b10101010U)) 194 | dr7 &= ~(1 << 9); 195 | 196 | return apply_hw_bp(task, dr7); 197 | } 198 | 199 | int reset_all_hw_bp(struct task *task) 200 | { 201 | return apply_hw_bp(task, 0); 202 | } 203 | 204 | int is_64bit(struct mt_elf *mte) 205 | { 206 | return !mte_cmp_machine(mte, EM_386); 207 | } 208 | 209 | int arch_task_init(struct task *task) 210 | { 211 | unsigned int i; 212 | 213 | for(i = 0; i != HW_BREAKPOINTS; ++i) 214 | task->arch.hw_bp[i] = 0; 215 | 216 | return _apply_hw_bp(task, 0); 217 | } 218 | 219 | void arch_task_destroy(struct task *task) 220 | { 221 | apply_hw_bp(task, 0); 222 | } 223 | 224 | int arch_task_clone(struct task *retp, struct task *task) 225 | { 226 | (void)retp; 227 | (void)task; 228 | 229 | return 0; 230 | } 231 | 232 | -------------------------------------------------------------------------------- /sysdeps/linux-gnu/x86/arch.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_SYSDEPS_LINUX_GNU_X86_ARCH_H 24 | #define _INC_SYSDEPS_LINUX_GNU_X86_ARCH_H 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #define BREAKPOINT_VALUE { 0xcc } 33 | #define BREAKPOINT_LENGTH 1 34 | #define DECR_PC_AFTER_BREAK 1 35 | #define ARCH_ENDIAN_LITTLE 36 | 37 | #define MT_ELFCLASS ELFCLASS32 38 | #define MT_ELF_MACHINE EM_386 39 | 40 | #ifdef __x86_64__ 41 | #define MT_ELFCLASS2 ELFCLASS64 42 | #define MT_ELF_MACHINE2 EM_X86_64 43 | 44 | #ifndef __NR_process_vm_readv 45 | #define __NR_process_vm_readv 310 46 | #endif 47 | 48 | #else /* __x86_64__ */ 49 | 50 | #ifndef __NR_process_vm_readv 51 | #define __NR_process_vm_readv 347 52 | #endif 53 | 54 | #endif /* __x86_64__ */ 55 | 56 | #define GUESS_CALLER 57 | 58 | #define HW_BREAKPOINTS 4 59 | 60 | #define TASK_HAVE_PROCESS_DATA 61 | 62 | struct context { 63 | struct user_regs_struct iregs; 64 | }; 65 | 66 | struct arch_task_data { 67 | unsigned long dr7; 68 | unsigned long hw_bp[HW_BREAKPOINTS]; 69 | }; 70 | 71 | #endif 72 | 73 | -------------------------------------------------------------------------------- /sysdeps/linux-gnu/x86/cpu.cmake: -------------------------------------------------------------------------------- 1 | list(APPEND C_SRCS 2 | sysdeps/${MT_OS}/${MT_CPU}/arch.c 3 | sysdeps/${MT_OS}/${MT_CPU}/dwarf-x86.c 4 | sysdeps/${MT_OS}/${MT_CPU}/regs.c 5 | ) 6 | 7 | -------------------------------------------------------------------------------- /sysdeps/sysdep.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_SYSDEP_MTRACE_H 24 | #define _INC_SYSDEP_MTRACE_H 25 | 26 | #include "arch.h" 27 | #include "os.h" 28 | 29 | #endif 30 | 31 | -------------------------------------------------------------------------------- /task.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_TASK_H 24 | #define _INC_TASK_H 25 | 26 | #include "config.h" 27 | 28 | #include 29 | #include 30 | 31 | #include "forward.h" 32 | #include "mtrace.h" 33 | #include "dict.h" 34 | #include "event.h" 35 | #include "sysdep.h" 36 | #include "arch.h" 37 | #include "list.h" 38 | #include "rbtree.h" 39 | #include "report.h" 40 | 41 | struct task { 42 | /* current pendig event */ 43 | struct event event; 44 | 45 | unsigned int is_64bit:1; 46 | unsigned int attached:1; 47 | unsigned int deleted:1; 48 | unsigned int about_exit:1; 49 | unsigned int stopped:1; 50 | unsigned int is_new:1; 51 | unsigned int bad:1; 52 | unsigned int bp_skipped:1; 53 | unsigned int in_realloc:1; 54 | 55 | struct breakpoint *breakpoint; 56 | struct library_symbol *libsym; 57 | struct context context; /* process context (registers, stack) */ 58 | struct context saved_context; /* context for fetch_param() */ 59 | 60 | /* arch specific task data */ 61 | #ifdef TASK_HAVE_PROCESS_DATA 62 | struct arch_task_data arch; 63 | #endif 64 | 65 | /* pointer to a breakpoint which was interrupt by a signal during skip */ 66 | struct breakpoint *skip_bp; 67 | 68 | #if HW_BREAKPOINTS > 0 69 | /* array of active hw breakpoints */ 70 | struct breakpoint *hw_bp[HW_BREAKPOINTS]; 71 | #endif 72 | 73 | /* process id */ 74 | pid_t pid; 75 | 76 | /* points to the leader thread */ 77 | struct task *leader; 78 | 79 | /* set in leader: number of stopped threads including the leader */ 80 | unsigned int threads_stopped; 81 | 82 | /* set in leader: dictionary of breakpoints */ 83 | struct dict *breakpoints; 84 | 85 | /* set in leader: backtrace pimpl */ 86 | void *backtrace; 87 | 88 | /* linked list of libraries, the first entry is the executable itself */ 89 | struct list_head libraries_list; 90 | 91 | /* red black tree of libraries */ 92 | struct rb_root libraries_tree; 93 | 94 | /* Thread chaining to leader */ 95 | struct list_head task_list; 96 | 97 | /* set in leader: number of threads including the leader */ 98 | unsigned int threads; 99 | 100 | /* struct task chaining. */ 101 | struct list_head leader_list; 102 | 103 | /* halt time for debugging purpose */ 104 | struct timespec halt_time; 105 | 106 | /* defered event function */ 107 | int (*defer_func)(struct task *task, void *data); 108 | 109 | /* defered event data */ 110 | void *defer_data; 111 | 112 | #if HW_BREAKPOINTS > 1 113 | /* set in leader: list of hw breakpoints */ 114 | struct list_head hw_bp_list; 115 | 116 | /* set in leader: number of registered hw breakpoints */ 117 | unsigned long hw_bp_num; 118 | #endif 119 | 120 | /* os specific task data */ 121 | #ifdef OS_HAVE_PROCESS_DATA 122 | struct os_task_data os; 123 | #endif 124 | }; 125 | 126 | int process_exec(struct task *task); 127 | 128 | struct task *task_new(pid_t pid); 129 | 130 | struct task *task_create(char **argv); 131 | 132 | void open_pid(pid_t pid); 133 | 134 | /* Clone the contents of a task */ 135 | int task_clone(struct task *task, struct task *newtask); 136 | 137 | /* Fork the contents of a task */ 138 | int task_fork(struct task *task, struct task *newtask); 139 | 140 | /* reset all breakpoints for task */ 141 | void task_reset_bp(struct task *task); 142 | 143 | /* Iterate through the leader tasks that mtrace-ng currently traces. */ 144 | void each_process(void (*cb)(struct task *task)); 145 | 146 | /* Iterate through list of tasks of a given leader task asks */ 147 | void each_task(struct task *leader, void (*cb)(struct task *task, void *data), void *data); 148 | 149 | /* Iterate through all allocated pids */ 150 | void each_pid(void (*cb)(struct task *task)); 151 | 152 | /* Remove task from the list of traced processes, drop any events in the event queue, destroy it and free memory. */ 153 | void remove_task(struct task *task); 154 | 155 | /* invalidate all breakpoints and call remove_proc */ 156 | void untrace_proc(struct task *leader); 157 | 158 | /* Remove all threads of the process from the list of traced processes, drop any events in the event queue, destroy it and free memory. */ 159 | void remove_proc(struct task *leader); 160 | 161 | /* halt a task */ 162 | void stop_task(struct task *task); 163 | 164 | /* return true if no more task is traced */ 165 | int task_list_empty(void); 166 | 167 | /* return true if task is 64 bit */ 168 | static inline int task_is_64bit(struct task *task) 169 | { 170 | return task->is_64bit; 171 | } 172 | 173 | struct pid_hash { 174 | unsigned int num; 175 | unsigned int size; 176 | struct task * tasks[0]; 177 | }; 178 | 179 | #define PID_HASH(pid) ((pid) % ARRAY_SIZE(pid_hash)) 180 | #define PID_HASH_SIZE 256 181 | 182 | extern struct pid_hash *pid_hash[PID_HASH_SIZE]; 183 | extern struct task *pid2task(pid_t pid); 184 | #endif 185 | 186 | -------------------------------------------------------------------------------- /thread.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_THREAD_H 24 | #define _INC_THREAD_H 25 | 26 | struct thread; 27 | 28 | /* create a thread object */ 29 | struct thread *thread_new(void); 30 | 31 | /* remove a thread object (wait if the thread is still running */ 32 | void thread_remove(struct thread *thread); 33 | 34 | /* start a thread with the given start routine and the pass the give arg pointer */ 35 | int thread_start(struct thread *thread, void *(*start_routine)(void *), void *arg); 36 | 37 | /* wait for termination of the thread */ 38 | void thread_join(struct thread *thread); 39 | 40 | /* enable cancelation of the current running thread */ 41 | void thread_enable_cancel(void); 42 | 43 | /* disable cancelation of the current running thread */ 44 | void thread_disable_cancel(void); 45 | 46 | /* cancel thread */ 47 | void thread_cancel(struct thread *thread); 48 | 49 | #endif 50 | 51 | -------------------------------------------------------------------------------- /timer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_TIMER_H 24 | #define _INC_TIMER_H 25 | 26 | #include 27 | #include 28 | 29 | struct mt_timer { 30 | unsigned int max; 31 | unsigned int count; 32 | unsigned long long culminate; 33 | }; 34 | 35 | static inline int start_time(struct timespec *ts) 36 | { 37 | return clock_gettime(CLOCK_THREAD_CPUTIME_ID, ts); 38 | } 39 | 40 | static inline int set_timer(struct timespec *start, struct mt_timer *p) 41 | { 42 | struct timespec now; 43 | unsigned int usec; 44 | 45 | if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now) == -1) 46 | return -1; 47 | 48 | usec = (now.tv_sec - start->tv_sec) * 1000000L + 49 | (now.tv_nsec - start->tv_nsec + 500L) / 1000; 50 | 51 | if (p->max < usec) 52 | p->max = usec; 53 | 54 | p->culminate += usec; 55 | 56 | ++p->count; 57 | 58 | return 0; 59 | } 60 | 61 | #endif 62 | 63 | -------------------------------------------------------------------------------- /trace.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #include "config.h" 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "backend.h" 36 | #include "breakpoint.h" 37 | #include "debug.h" 38 | #include "event.h" 39 | #include "options.h" 40 | #include "report.h" 41 | #include "task.h" 42 | #include "library.h" 43 | #include "main.h" 44 | 45 | int skip_breakpoint(struct task *task, struct breakpoint *bp) 46 | { 47 | debug(DEBUG_PROCESS, "pid=%d, addr=%#lx", task->pid, bp->addr); 48 | 49 | assert(task->event.type == EVENT_BREAKPOINT); 50 | assert(task->stopped); 51 | assert(task->skip_bp == NULL); 52 | 53 | if (bp->sw && bp->enabled) { 54 | int ret = 0; 55 | struct timespec start; 56 | 57 | if (task->skip_bp) { 58 | task->event.type = EVENT_NONE; 59 | return 1; 60 | } 61 | 62 | if (unlikely(options.verbose > 1)) 63 | start_time(&start); 64 | 65 | breakpoint_disable(task, bp); 66 | ret = do_singlestep(task, bp); 67 | breakpoint_enable(task, bp); 68 | 69 | if (unlikely(options.verbose > 1)) 70 | set_timer(&start, &skip_bp_time); 71 | 72 | if (unlikely(ret)) { 73 | task->skip_bp = breakpoint_get(bp); 74 | assert(task->skip_bp); 75 | return ret; 76 | } 77 | } 78 | 79 | continue_task(task, 0); 80 | return 0; 81 | } 82 | 83 | void fix_about_exit(struct task *task) 84 | { 85 | if (task->about_exit) { 86 | task->about_exit = 0; 87 | 88 | continue_task(task, 0); 89 | } 90 | } 91 | 92 | static void detach_cb(struct task *task, void *data) 93 | { 94 | (void)data; 95 | 96 | remove_task(task); 97 | } 98 | 99 | void detach_proc(struct task *leader) 100 | { 101 | assert(leader->leader == leader); 102 | 103 | breakpoint_disable_all(leader); 104 | 105 | if (unlikely(options.verbose > 1)) 106 | fprintf(stderr, "+++ process detach pid=%d\n", leader->pid); 107 | 108 | each_task(leader, &detach_cb, NULL); 109 | } 110 | 111 | -------------------------------------------------------------------------------- /trace.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of mtrace-ng. 3 | * Copyright (C) 2018 Stefani Seibold 4 | * 5 | * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA 21 | */ 22 | 23 | #ifndef _INC_TRACE_H 24 | #define _INC_TRACE_H 25 | 26 | #include "forward.h" 27 | 28 | void fix_about_exit(struct task *task); 29 | void detach_proc(struct task *leader); 30 | int skip_breakpoint(struct task *task, struct breakpoint *bp); 31 | 32 | #endif 33 | 34 | --------------------------------------------------------------------------------