├── .gitignore ├── .gitmodules ├── LICENSE ├── Makefile ├── README.md └── source ├── breakpoint.cc ├── breakpoint.h ├── callsite.cc ├── callsite.h ├── disassembler.cc ├── disassembler.h ├── ltrace.cc └── ltrace.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | ltrace 35 | source/*.o 36 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "source/elf-parser"] 2 | path = source/elf-parser 3 | url = git@github.com:finixbit/elf-parser.git 4 | branch = master 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 finixbit 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | 3 | all: callsite disassembler breakpoint ltrace 4 | 5 | ltrace: source/ltrace.cc 6 | g++ -o ltrace source/ltrace.cc callsite.o disassembler.o breakpoint.o -std=gnu++11 -lcapstone 7 | 8 | breakpoint: source/breakpoint.cc 9 | g++ -o breakpoint.o -c source/breakpoint.cc -std=gnu++11 10 | 11 | callsite: source/callsite.cc 12 | g++ -o callsite.o -c source/callsite.cc -std=gnu++11 13 | 14 | disassembler: source/disassembler.cc 15 | g++ -o disassembler.o -c source/disassembler.cc -std=gnu++11 -lcapstone 16 | 17 | clean: 18 | rm -f ltrace disassembler.o callsite.o breakpoint.o -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ltrace 2 | Simple Library calls tracer 3 | 4 | # Required libraries 5 | capstone, finixbit/elf-parser 6 | 7 | # Installation 8 | 9 | ``` 10 | $ sudo apt-get install libcapstone-dev 11 | $ git clone --recursive https://github.com/finixbit/ltrace.git 12 | $ cd ltrace 13 | $ make 14 | ``` 15 | 16 | # Usage 17 | 18 | ``` 19 | ./ltrace 20 | ``` 21 | 22 | # Example 23 | ``` 24 | ./ltrace /bin/ps 25 | 26 | breakpoint[0x402c0b] call: __libc_start_main 27 | breakpoint[0x40350c] call: look_up_our_self 28 | breakpoint[0x403511] return: look_up_our_self 29 | breakpoint[0x403520] call: ioctl 30 | breakpoint[0x403525] return: ioctl 31 | breakpoint[0x40370f] call: ioctl 32 | breakpoint[0x403714] return: ioctl 33 | breakpoint[0x40355a] call: isatty 34 | breakpoint[0x40355f] return: isatty 35 | breakpoint[0x403572] call: getenv 36 | breakpoint[0x403577] return: getenv 37 | breakpoint[0x40358a] call: getenv 38 | breakpoint[0x40358f] return: getenv 39 | breakpoint[0x4030d6] call: getenv 40 | breakpoint[0x4030db] return: getenv 41 | breakpoint[0x4031bd] call: getenv 42 | breakpoint[0x4031c2] return: getenv 43 | breakpoint[0x4031e2] call: getenv 44 | breakpoint[0x4031e7] return: getenv 45 | breakpoint[0x40311b] call: __strncpy_chk 46 | breakpoint[0x403120] return: __strncpy_chk 47 | breakpoint[0x403127] call: __strdup 48 | breakpoint[0x40312c] return: __strdup 49 | ... 50 | ``` 51 | 52 | -------------------------------------------------------------------------------- /source/breakpoint.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include /* ptrace */ 3 | #include /* wait */ 4 | #include /* PRIx64 */ 5 | #include "breakpoint.h" 6 | #include "callsite.h" 7 | 8 | 9 | void Breakpoint::set_callsite_breakpoint( 10 | pid_t &child_pid, std::intptr_t &cs_address, std::intptr_t &cs_return_address) { 11 | 12 | if(m_breakpoints_map.count(cs_address)) { 13 | auto &bp = m_breakpoints_map[cs_address]; 14 | bp.m_is_cs_caller_address = true; 15 | bp.m_cs_caller_address = cs_address; 16 | 17 | } else { 18 | breakpoint_t bp; 19 | bp.m_bp_address = cs_address; 20 | bp.m_is_cs_caller_address = true; 21 | bp.m_cs_caller_address = cs_address; 22 | 23 | enable_breakpoint(child_pid, bp); 24 | m_breakpoints_map[cs_address] = bp; 25 | } 26 | 27 | if(m_breakpoints_map.count(cs_return_address)) { 28 | auto &bp = m_breakpoints_map[cs_return_address]; 29 | bp.m_is_cs_return_address = true; 30 | bp.m_cs_return_caller_address = cs_address; 31 | 32 | } else { 33 | breakpoint_t bp; 34 | bp.m_bp_address = cs_return_address; 35 | bp.m_is_cs_return_address = true; 36 | bp.m_cs_return_caller_address = cs_address; 37 | 38 | enable_breakpoint(child_pid, bp); 39 | m_breakpoints_map[cs_return_address] = bp; 40 | } 41 | } 42 | 43 | void Breakpoint::continue_execution(pid_t &child_pid) { 44 | while(1) { 45 | ptrace(PTRACE_CONT, child_pid, nullptr, nullptr); 46 | wait_for_signal(child_pid); 47 | step_over_breakpoint(child_pid); 48 | } 49 | } 50 | 51 | void Breakpoint::wait_for_signal(pid_t &child_pid) { 52 | int wait_status = 0; 53 | auto options = 0; 54 | auto i = waitpid(child_pid, &wait_status, options); 55 | 56 | if(WIFEXITED(wait_status) || (WIFSIGNALED(wait_status) && WTERMSIG(wait_status) == SIGKILL)) { 57 | std::cout << "[+] process " << child_pid << " terminated" << std::endl; 58 | return; 59 | } 60 | } 61 | 62 | void Breakpoint::step_over_breakpoint(pid_t &child_pid) { 63 | // - 1 because execution will go past the breakpoint 64 | auto possible_breakpoint_location = get_program_counter(child_pid) - 1; 65 | 66 | if (m_breakpoints_map.count(possible_breakpoint_location)) { 67 | auto& bp = m_breakpoints_map[possible_breakpoint_location]; 68 | 69 | if (bp.m_enabled) { 70 | printf("breakpoint[0x%" PRIx64 "] ", bp.m_bp_address); 71 | 72 | if(bp.m_is_cs_return_address) { 73 | auto &cs = Callsite::m_callsites_map[bp.m_cs_return_caller_address]; 74 | std::cout << "return: " << cs.m_cs_name << " "; 75 | } 76 | if(bp.m_is_cs_caller_address) { 77 | auto &cs = Callsite::m_callsites_map[bp.m_cs_caller_address]; 78 | std::cout << " call: " << cs.m_cs_name << " "; 79 | } 80 | printf("\n"); 81 | 82 | auto previous_instruction_address = possible_breakpoint_location; 83 | set_program_counter(child_pid, previous_instruction_address); 84 | 85 | disable_breakpoint(child_pid, bp); 86 | ptrace(PTRACE_SINGLESTEP, child_pid, nullptr, nullptr); 87 | wait_for_signal(child_pid); 88 | 89 | enable_breakpoint(child_pid, bp); 90 | } 91 | } 92 | } 93 | 94 | uint64_t Breakpoint::get_program_counter(pid_t &child_pid) { 95 | user_regs_struct regs = get_registers(child_pid); 96 | return (uint64_t)regs.rip; 97 | } 98 | 99 | void Breakpoint::set_program_counter(pid_t &child_pid, uint64_t &pc) { 100 | user_regs_struct regs = get_registers(child_pid); 101 | 102 | #ifdef __x86_64__ 103 | regs.rip = pc; 104 | #else 105 | regs.eip = pc; 106 | #endif 107 | ptrace(PTRACE_SETREGS, child_pid, nullptr, ®s); 108 | } 109 | 110 | user_regs_struct Breakpoint::get_registers(pid_t &child_pid) { 111 | struct user_regs_struct regs; 112 | long esp, eax, ebx, edx, ecx, esi, edi, eip; 113 | #ifdef __x86_64__ 114 | esp = regs.rsp; 115 | eip = regs.rip; 116 | eax = regs.rax; 117 | ebx = regs.rbx; 118 | ecx = regs.rcx; 119 | edx = regs.rdx; 120 | esi = regs.rsi; 121 | edi = regs.rdi; 122 | #else 123 | esp = regs.esp; 124 | eip = regs.eip; 125 | eax = regs.eax; 126 | ebx = regs.ebx; 127 | ecx = regs.ecx; 128 | edx = regs.edx; 129 | esi = regs.esi; 130 | edi = regs.edi; 131 | #endif 132 | if(ptrace(PTRACE_GETREGS, child_pid, nullptr, ®s) == -1) { 133 | std::cout << "Error: PTRACE_GETREGS" << std::endl; 134 | exit(1); 135 | }; 136 | return regs; 137 | } 138 | 139 | void Breakpoint::enable_breakpoint(pid_t &child_pid, breakpoint_t &bp) { 140 | auto data = ptrace(PTRACE_PEEKDATA, child_pid, bp.m_bp_address, nullptr); 141 | bp.m_original_data = static_cast(data & 0xff); //save bottom byte 142 | 143 | //set bottom byte to 0xcc 144 | uint64_t int3 = 0xcc; 145 | uint64_t data_with_int3 = ((data & ~0xff) | int3); 146 | ptrace(PTRACE_POKEDATA, child_pid, bp.m_bp_address, data_with_int3); 147 | 148 | bp.m_enabled = true; 149 | } 150 | 151 | void Breakpoint::disable_breakpoint(pid_t &child_pid, breakpoint_t &bp) { 152 | auto data = ptrace(PTRACE_PEEKDATA, child_pid, bp.m_bp_address, nullptr); 153 | 154 | //overwrite the low byte with the original data and write it back to memory. 155 | auto restored_data = ((data & ~0xff) | bp.m_original_data); 156 | ptrace(PTRACE_POKEDATA, child_pid, bp.m_bp_address, restored_data); 157 | 158 | bp.m_enabled = false; 159 | } 160 | 161 | 162 | -------------------------------------------------------------------------------- /source/breakpoint.h: -------------------------------------------------------------------------------- 1 | #ifndef _H_BREAKPOINT_ 2 | #define _H_BREAKPOINT_ 3 | 4 | #include // unordered_map 5 | #include /* user_regs_struct */ 6 | #include 7 | 8 | 9 | typedef struct { 10 | std::intptr_t m_bp_address = 0; 11 | uint8_t m_original_data = 0; 12 | bool m_enabled = false; 13 | 14 | bool m_is_cs_caller_address = false; 15 | std::intptr_t m_cs_caller_address = 0; 16 | 17 | bool m_is_cs_return_address = false; 18 | std::intptr_t m_cs_return_caller_address = 0; // m_cs_caller_address's address 19 | } breakpoint_t; 20 | 21 | class Breakpoint { 22 | public: 23 | void set_callsite_breakpoint( 24 | pid_t &child_pid, 25 | std::intptr_t &cs_address, std::intptr_t &cs_return_address); 26 | 27 | void continue_execution(pid_t &child_pid); 28 | void wait_for_signal(pid_t &child_pid); 29 | void step_over_breakpoint(pid_t &child_pid); 30 | 31 | uint64_t get_program_counter(pid_t &child_pid); 32 | void set_program_counter(pid_t &child_pid, uint64_t &pc); 33 | 34 | user_regs_struct get_registers(pid_t &child_pid); 35 | 36 | void enable_breakpoint(pid_t &child_pid, breakpoint_t &bp); 37 | void disable_breakpoint(pid_t &child_pid, breakpoint_t &bp); 38 | 39 | std::unordered_map m_breakpoints_map; 40 | 41 | private: 42 | pid_t m_child_pid; 43 | }; 44 | 45 | 46 | #endif -------------------------------------------------------------------------------- /source/callsite.cc: -------------------------------------------------------------------------------- 1 | #include "callsite.h" 2 | 3 | std::unordered_map Callsite::m_callsites_map; 4 | 5 | 6 | bool Callsite::get_callsite(std::intptr_t cs_address, Callsite &cs) { 7 | if(!Callsite::m_callsites_map.count(cs_address)) 8 | return false; 9 | 10 | cs = Callsite::m_callsites_map[cs_address]; 11 | return true; 12 | } 13 | 14 | intptr_t Callsite::string_to_intptr(std::string str) { 15 | return (intptr_t)std::stoi(str); 16 | } -------------------------------------------------------------------------------- /source/callsite.h: -------------------------------------------------------------------------------- 1 | #ifndef _H_CALLSITE_ 2 | #define _H_CALLSITE_ 3 | 4 | #include // vector 5 | #include // unordered_map 6 | 7 | 8 | class Callsite { 9 | public: 10 | static bool get_callsite(std::intptr_t cs_address, Callsite &cs); 11 | static intptr_t string_to_intptr(std::string str); 12 | 13 | // cs_address: call target 14 | std::intptr_t m_cs_address = 0; 15 | 16 | // cs_address: call target_address 17 | std::intptr_t m_cs_target_address = 0; 18 | 19 | // resolved (call symbol) 20 | // unresolved (call eax/%rbp+8) 21 | bool m_cs_target_resolved = false; 22 | 23 | // next instruction following cs_address 24 | std::intptr_t m_cs_return_address = 0; 25 | 26 | // target string 27 | std::string m_cs_name; 28 | 29 | static std::unordered_map m_callsites_map; 30 | }; 31 | 32 | 33 | #endif -------------------------------------------------------------------------------- /source/disassembler.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include // O_RDONLY 3 | #include /* For the size of the file. , fstat */ 4 | #include /* mmap, MAP_PRIVATE */ 5 | #include "disassembler.h" 6 | #include "callsite.h" 7 | 8 | 9 | void Disassembler::disassemble_callsites( 10 | uint8_t* code, int32_t code_size, std::intptr_t code_entry, bool print_ins = false) { 11 | 12 | csh capstone_handle; 13 | cs_insn *disassembled_ins; 14 | size_t count; 15 | 16 | if (cs_open(CS_ARCH_X86, CS_MODE_64, &capstone_handle) != CS_ERR_OK) { 17 | std::cout << "Initializing Capstone failed ..." << std::endl; 18 | exit(1); 19 | } 20 | 21 | count = cs_disasm( 22 | capstone_handle, code, code_size, code_entry, 0, &disassembled_ins); 23 | 24 | if (count > 0) { 25 | size_t j; 26 | for (j = 0; j < count; j++) { 27 | if(print_ins) 28 | print_disassembled_ins(disassembled_ins[j]); 29 | 30 | if(std::string(disassembled_ins[j].mnemonic) != "call") 31 | continue; 32 | 33 | auto addr = (std::intptr_t)disassembled_ins[j].address; 34 | if(!Callsite::m_callsites_map.count(addr)) { 35 | 36 | generate_callsite( 37 | disassembled_ins[j], disassembled_ins[j+1], false); 38 | } 39 | } 40 | cs_free(disassembled_ins, count); 41 | } else { 42 | std::cout << "ERROR: Failed to disassemble program ..." << std::endl; 43 | exit(1); 44 | } 45 | cs_close(&capstone_handle); 46 | } 47 | 48 | void Disassembler::disassemble_ins( 49 | uint8_t* code, int32_t code_size, std::intptr_t code_entry, bool print_ins = false) { 50 | 51 | csh capstone_handle; 52 | cs_insn *disassembled_ins; 53 | size_t count; 54 | 55 | if (cs_open(CS_ARCH_X86, CS_MODE_64, &capstone_handle) != CS_ERR_OK) { 56 | std::cout << "Initializing Capstone failed ..." << std::endl; 57 | exit(1); 58 | } 59 | 60 | count = cs_disasm( 61 | capstone_handle, code, code_size, code_entry, 0, &disassembled_ins); 62 | 63 | if (count > 0) { 64 | size_t j; 65 | for (j = 0; j < count; j++) { 66 | m_disassembled_ins[ 67 | disassembled_ins[j].address] = disassembled_ins[j]; 68 | 69 | if(print_ins) 70 | print_disassembled_ins(disassembled_ins[j]); 71 | } 72 | cs_free(disassembled_ins, count); 73 | } else { 74 | std::cout << "ERROR: Failed to disassemble program ..." << std::endl; 75 | } 76 | cs_close(&capstone_handle); 77 | } 78 | 79 | void Disassembler::print_disassembled_ins(cs_insn &disassembled_ins) { 80 | printf("0x%" PRIx64 ":\t%s\t\t%s\n", disassembled_ins.address, 81 | disassembled_ins.mnemonic, disassembled_ins.op_str); 82 | } 83 | 84 | void Disassembler::generate_callsite( 85 | cs_insn &insn, cs_insn &next_insn, bool print) { 86 | 87 | Callsite cs; 88 | cs.m_cs_address = insn.address; 89 | cs.m_cs_name = std::string(insn.op_str); 90 | cs.m_cs_target_resolved = false; 91 | 92 | try { 93 | std::intptr_t ptr = std::stol(std::string(insn.op_str), nullptr, 0); 94 | cs.m_cs_target_address = ptr; 95 | cs.m_cs_target_resolved = true; 96 | } catch(...) {} 97 | 98 | try { 99 | cs.m_cs_return_address = next_insn.address; 100 | } catch(...) {} 101 | 102 | Callsite::m_callsites_map[cs.m_cs_address] = cs; 103 | 104 | if(print) 105 | print_disassembled_ins(insn); 106 | } -------------------------------------------------------------------------------- /source/disassembler.h: -------------------------------------------------------------------------------- 1 | #ifndef _H_DISASSEMBER_ 2 | #define _H_DISASSEMBER_ 3 | 4 | #include // vector 5 | #include // map 6 | #include // unordered_map 7 | #include /* ElfW */ 8 | #include //cs_insn 9 | 10 | 11 | class Disassembler { 12 | public: 13 | void disassemble_callsites( 14 | uint8_t* code, int32_t size, std::intptr_t code_entry, bool print_ins); 15 | 16 | void disassemble_ins( 17 | uint8_t* code, int32_t size, std::intptr_t code_entry, bool print_ins); 18 | 19 | void generate_callsite( 20 | cs_insn &insn, cs_insn &next_insn, bool print); 21 | 22 | private: 23 | void print_disassembled_ins(cs_insn &disassembled_ins); 24 | std::map m_disassembled_ins; 25 | 26 | }; 27 | 28 | #endif -------------------------------------------------------------------------------- /source/ltrace.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include /* fork() / execvp */ 6 | #include // pid_t 7 | #include /* ptrace */ 8 | #include // prctl 9 | #include // SIGHUP 10 | #include "ltrace.h" 11 | #include "elf-parser/elf_parser.h" 12 | #include "callsite.h" 13 | using namespace elf_parser; 14 | 15 | 16 | int main(int argc, char* argv[]) { 17 | char usage_banner[] = "usage: ./sdb []\n"; 18 | if(argc < 2) { 19 | std::cerr << usage_banner; 20 | return -1; 21 | } 22 | 23 | std::string program = (std::string)argv[1]; 24 | Debugger sdb_debugger(program); 25 | 26 | auto child_pid = fork(); 27 | switch(child_pid) { 28 | case -1: 29 | std::cerr << "error forking\n"; 30 | break; 31 | case 0: 32 | sdb_debugger.run_debuggee(argv+1); 33 | break; 34 | default: 35 | sdb_debugger.run_debugger(child_pid); 36 | break; 37 | } 38 | return 0; 39 | } 40 | 41 | void Debugger::run_debuggee(char* cmd[]) { 42 | if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) { 43 | std::cerr << "Ptrace Error.\n"; 44 | return; 45 | } 46 | 47 | long ptrace_opts; 48 | ptrace_opts = PTRACE_O_TRACECLONE|PTRACE_O_TRACEFORK|PTRACE_O_TRACEEXEC|PTRACE_O_TRACEEXIT; 49 | ptrace(PTRACE_SETOPTIONS, 0, 0, ptrace_opts); 50 | 51 | prctl(PR_SET_PDEATHSIG, SIGHUP); 52 | execvp(cmd[0], cmd); 53 | } 54 | 55 | void Debugger::run_debugger(pid_t child_pid) { 56 | m_child_pid = child_pid; 57 | m_proc_program_path = "/proc/" + std::to_string(m_child_pid) + "/exe"; 58 | wait_for_signal(m_child_pid); 59 | 60 | auto relocs = get_relocations(); 61 | m_relocs = relocations_to_unordered_map(relocs); 62 | 63 | uint8_t* text_code; 64 | std::intptr_t text_code_entry; 65 | long text_code_size; 66 | 67 | Elf64_Ehdr *ehdr = (Elf64_Ehdr*)get_memory_map(); 68 | text_code_entry = ehdr->e_entry; 69 | 70 | auto segs = get_segments(); 71 | for(auto &seg: segs) { 72 | if(seg.segment_type == "LOAD") { 73 | text_code = &get_memory_map()[text_code_entry - seg.segment_virtaddr]; 74 | text_code_size = seg.segment_memsize; 75 | break; 76 | } 77 | } 78 | 79 | disassemble_callsites( 80 | text_code, text_code_size, text_code_entry, false); 81 | 82 | // set breakpoints 83 | for(auto &cs_map: Callsite::m_callsites_map) { 84 | auto &cs = cs_map.second; 85 | 86 | if((!cs.m_cs_target_resolved) || (cs.m_cs_target_address == 0)) 87 | continue; 88 | 89 | if(!m_relocs.count(cs.m_cs_target_address)) 90 | continue; 91 | else 92 | cs.m_cs_name = \ 93 | m_relocs[cs.m_cs_target_address].relocation_symbol_name; 94 | 95 | set_callsite_breakpoint( 96 | child_pid, cs.m_cs_address, cs.m_cs_return_address); 97 | } 98 | 99 | // continue program execution 100 | continue_execution(m_child_pid); 101 | } 102 | 103 | 104 | RELOC_MAP Debugger::relocations_to_unordered_map(std::vector &rels) { 105 | RELOC_MAP rmap; 106 | for(auto &rel: rels) { 107 | rmap[rel.relocation_plt_address] = rel; 108 | } 109 | return rmap; 110 | } -------------------------------------------------------------------------------- /source/ltrace.h: -------------------------------------------------------------------------------- 1 | #ifndef _H_LTRACE_ 2 | #define _H_LTRACE_ 3 | 4 | #include 5 | #include // pid_t 6 | #include "elf-parser/elf_parser.h" 7 | #include "disassembler.h" 8 | #include "breakpoint.h" 9 | using namespace elf_parser; 10 | 11 | typedef std::unordered_map RELOC_MAP; 12 | 13 | class Debugger: Elf_parser, Disassembler, Breakpoint { 14 | public: 15 | Debugger (std::string &program_path): 16 | m_program_path{program_path}, Elf_parser{program_path} { 17 | } 18 | void run_debuggee(char* cmd[]); 19 | void run_debugger(pid_t child_pid); 20 | 21 | RELOC_MAP m_relocs; 22 | 23 | private: 24 | std::string m_program_path; 25 | std::string m_program_argv; 26 | std::string m_proc_program_path; 27 | pid_t m_child_pid; 28 | 29 | RELOC_MAP relocations_to_unordered_map(std::vector &rels); 30 | }; 31 | 32 | #endif --------------------------------------------------------------------------------