From 0b0fd8d1ea55ac99a0ac4624c4aa8134de9a1960 Mon Sep 17 00:00:00 2001 From: "A.Olokhtonov" Date: Fri, 23 Jul 2021 23:07:24 +0300 Subject: [PATCH] backtrace ("bt") command works (only if frame pointer is not ommited!) --- command.c | 21 ++++++++++++ common.h | 39 +++++++++++------------ dwarf.c | 65 ++++++++++++++------------------------ main.c | 2 ++ res/004-scoped-variables.c | 39 +++++++++++++++++++---- util.c | 48 +++++++++++++++++++++------- 6 files changed, 135 insertions(+), 79 deletions(-) diff --git a/command.c b/command.c index 270ac14..8b5af75 100644 --- a/command.c +++ b/command.c @@ -126,4 +126,25 @@ static void command_kill(struct mi_process proc) { kill(proc.pid, SIGKILL); +} + +static void +command_backtrace(struct mi_process proc) +{ + struct mi_registers regs = get_process_registers(proc); + struct mi_function *func = get_function_around_pc(proc, regs.rip - proc.base_address); + + u64 fb = regs.rbp; + u64 return_address = ptrace(PTRACE_PEEKDATA, proc.pid, fb + 8, NULL); + + printf("%s: %#lx\n", func->name, regs.rip); + + for (int i = 0; i < 3; ++i) { + func = get_function_around_pc(proc, return_address - proc.base_address); + if (func) { + printf("%s: %#lx\n", func->name, regs.rip); + } + fb = ptrace(PTRACE_PEEKDATA, proc.pid, fb, NULL); + return_address = ptrace(PTRACE_PEEKDATA, proc.pid, fb + 8, NULL); + } } \ No newline at end of file diff --git a/common.h b/common.h index 44bc14d..256ad43 100644 --- a/common.h +++ b/common.h @@ -43,13 +43,6 @@ struct mi_sourcepoint { int file; }; -struct mi_function { - char *name; - int comp_unit; - u64 low_pc; - u64 high_pc; -}; - struct mi_sourcefile { char *filename; char *dir; @@ -61,18 +54,15 @@ struct mi_variable { s64 location; }; -struct mi_block { +struct mi_function { u64 low_pc; u64 high_pc; - - struct mi_variable variables[4]; // TODO - int var_count; + char *name; + int variables_from; + int variables_count; }; -struct mi_compunit { - u64 low_pc; - u64 high_pc; - +struct mi_sourceinfo { struct mi_sourcepoint *sp_table; int sp_count; @@ -83,17 +73,26 @@ struct mi_compunit { int source_dirs_count; char *comp_dir; +}; + +struct mi_compunit { + u64 low_pc; + u64 high_pc; + + struct mi_sourceinfo source; - struct mi_block blocks[4]; // TODO - int block_count; + int functions_from; + int functions_count; }; struct mi_debuginfo { - struct mi_compunit compilation_units[16]; // TODO - int cu_count; + struct mi_compunit compilation_units[16]; + struct mi_function functions[64]; + struct mi_variable variables[64]; - struct mi_function functions[64]; // TODO + int cu_count; int func_count; + int var_count; }; struct mi_process { diff --git a/dwarf.c b/dwarf.c index 7a22996..574517b 100644 --- a/dwarf.c +++ b/dwarf.c @@ -768,30 +768,16 @@ read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest, u32 depth = 0; u64 base_data_offset = data_offset - header_size; - int found_sr = 0; - - struct mi_function *func = dest->functions + dest->func_count; struct mi_compunit *comp_unit = dest->compilation_units + dest->cu_count; - struct mi_block *block = comp_unit->blocks; - struct mi_variable *variable = block->variables; - - enum dwarf_die_tag parent = 0; + struct mi_function *func = dest->functions + dest->func_count; + struct mi_variable *variable = dest->variables + dest->var_count; - // TODO: make this not bad + comp_unit->functions_from = dest->func_count; for (;;) { data_offset += decode_leb128(file + data_offset, &code); if (code == 0) { - // NOTE: finalize parent - if (parent == DW_TAG_lexical_block) { - block->high_pc = block->low_pc + block->high_pc; - ++block; - ++comp_unit->block_count; - variable = block->variables; - __builtin_trap(); - } - if (depth > 1) { --depth; continue; @@ -808,7 +794,6 @@ read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest, u32 has_children = file[schema_offset++]; if (has_children) { - parent = tag; ++depth; } @@ -828,7 +813,7 @@ read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest, } else if (attribute == DW_AT_high_pc) { comp_unit->high_pc = value; } else if (attribute == DW_AT_comp_dir) { - comp_unit->comp_dir = (char *) value; + comp_unit->source.comp_dir = (char *) value; } } else if (tag == DW_TAG_subprogram) { if (attribute == DW_AT_name) { @@ -838,12 +823,6 @@ read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest, } else if (attribute == DW_AT_high_pc) { func->high_pc = value; } - } else if (tag == DW_TAG_lexical_block) { - if (attribute == DW_AT_low_pc) { - block->low_pc = value; - } else if (attribute == DW_AT_high_pc) { - block->high_pc = value; - } } else if (tag == DW_TAG_variable) { if (attribute == DW_AT_name) { variable->name = (char *) value; @@ -853,16 +832,18 @@ read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest, } } while (attribute != 0 || form != 0); - if (parent == DW_TAG_variable) { - ++variable; - ++block->var_count; - } - - if (parent == DW_TAG_subprogram) { + // NOTE(aolo2): DIE completely processed, finish it up + if (tag == DW_TAG_subprogram) { func->high_pc = func->low_pc + func->high_pc; - func->comp_unit = dest->cu_count; - ++func; + func->variables_from = dest->var_count; + ++comp_unit->functions_count; ++dest->func_count; + ++func; + } else if (tag == DW_TAG_variable) { + struct mi_function *parent = func - 1; + ++parent->variables_count; + ++dest->var_count; + ++variable; } } @@ -900,14 +881,14 @@ parse_debug_info(u8 *file, struct mi_debuginfo *dest) static u64 read_debug_line_for_compilation_unit(u8 *file, u64 dl_offset, struct mi_compunit *unit) { - struct mi_sourcepoint *dest = unit->sp_table; - int *dest_size = &unit->sp_count; + struct mi_sourcepoint *dest = unit->source.sp_table; + int *dest_size = &unit->source.sp_count; - struct mi_sourcefile *dest_files = unit->source_files; - int *dest_files_size = &unit->source_file_count; + struct mi_sourcefile *dest_files = unit->source.source_files; + int *dest_files_size = &unit->source.source_file_count; - char **dest_directories = unit->source_directories; - int *dest_directories_size = &unit->source_dirs_count; + char **dest_directories = unit->source.source_directories; + int *dest_directories_size = &unit->source.source_dirs_count; struct dwarf_debug_line_header_v3_x32 header = { 0 }; memcpy(&header, file + dl_offset, 15); /* all fixed-size info */ @@ -1246,9 +1227,9 @@ parse_debug_line(u8 *file, struct mi_debuginfo *debug) // count for (;;) { u64 size = read_debug_line_for_compilation_unit(file, at, unit); - unit->sp_table = calloc(1, unit->sp_count * sizeof(struct mi_sourcepoint)); - unit->source_directories = calloc(1, unit->source_dirs_count * sizeof(char *)); - unit->source_files = calloc(1, unit->source_file_count * sizeof(struct mi_sourcefile)); + unit->source.sp_table = calloc(1, unit->source.sp_count * sizeof(struct mi_sourcepoint)); + unit->source.source_directories = calloc(1, unit->source.source_dirs_count * sizeof(char *)); + unit->source.source_files = calloc(1, unit->source.source_file_count * sizeof(struct mi_sourcefile)); read += size; at += size; ++unit; diff --git a/main.c b/main.c index e06ea7e..a88ecaa 100644 --- a/main.c +++ b/main.c @@ -55,6 +55,8 @@ main(int argc, char *argv[]) command_next(process); } else if (0 == strncmp(command, "line\n", command_length)) { command_list(process); + } else if (0 == strncmp(command, "bt\n", command_length)) { + command_backtrace(process); } else if (0 == strncmp(command, "cont\n", command_length)) { command_cont(process); wait = 1; diff --git a/res/004-scoped-variables.c b/res/004-scoped-variables.c index f9d9505..97974c7 100644 --- a/res/004-scoped-variables.c +++ b/res/004-scoped-variables.c @@ -1,11 +1,38 @@ +void f1(); +void f2(); +void f3(); + +void +f3() +{ + int a_f3 = 3; + f2(); +} + +void +f2() +{ + int a_f2 = 2; + { + int b_f2 = 22; + { + int c_f2 = 33; + } + } +} + +void +f1() +{ + int a_f1 = 1; + f2(); +} + int main(int argc, char **argv) { - int outer = 1; - if (outer > 0) { - char *inner = "INNER"; - int outer = -1; - outer += 10; - } + int a_main = 0; + f1(); + f3(); return(0); } diff --git a/util.c b/util.c index d257e62..0aeb232 100644 --- a/util.c +++ b/util.c @@ -1,4 +1,3 @@ - static struct mi_registers get_process_registers(struct mi_process proc) { @@ -114,11 +113,11 @@ pc_to_sourcepoint(struct mi_process proc, u64 pc, int *comp_unit) for (int c = 0; c < proc.debug.cu_count; ++c) { struct mi_compunit unit = proc.debug.compilation_units[c]; if (unit.low_pc <= pc && pc < unit.high_pc) { - for (int i = 0; i < unit.sp_count; ++i) { - struct mi_sourcepoint *point = unit.sp_table + i; + for (int i = 0; i < unit.source.sp_count; ++i) { + struct mi_sourcepoint *point = unit.source.sp_table + i; if (point->pc > pc) { *comp_unit = c; - return(unit.sp_table + i - 1); + return(unit.source.sp_table + i - 1); } } break; @@ -173,19 +172,19 @@ print_sourcepoint(struct mi_process proc, int comp_unit, struct mi_sourcepoint * struct mi_compunit unit = proc.debug.compilation_units[comp_unit]; // NOTE: sourcepoint file indices are 1-based - if (unit.source_files[sp->file - 1].file.data == 0) { - char *file_filename = unit.source_files[sp->file - 1].filename; - char *file_dirname = unit.source_files[sp->file - 1].dir; - char *comp_dir = unit.comp_dir; + if (unit.source.source_files[sp->file - 1].file.data == 0) { + char *file_filename = unit.source.source_files[sp->file - 1].filename; + char *file_dirname = unit.source.source_files[sp->file - 1].dir; + char *comp_dir = unit.source.comp_dir; char full_path[512] = { 0 }; snprintf(full_path, 511, "%s/%s/%s", comp_dir, file_dirname, file_filename); struct mi_buffer file = read_file_mmap(full_path); - unit.source_files[sp->file - 1].file = file; + unit.source.source_files[sp->file - 1].file = file; } - struct mi_buffer file = unit.source_files[sp->file - 1].file; + struct mi_buffer file = unit.source.source_files[sp->file - 1].file; char *source = (char *) file.data; u64 size = file.size; @@ -280,6 +279,7 @@ lookup_identifier_address(struct mi_process proc, char *ident, int len) struct mi_registers regs = get_process_registers(proc); u64 pc_local = regs.rip - proc.base_address; +#if 0 for (int c = 0; c < proc.debug.cu_count; ++c) { struct mi_compunit unit = proc.debug.compilation_units[c]; @@ -303,6 +303,32 @@ lookup_identifier_address(struct mi_process proc, char *ident, int len) } } +#endif return(0); -} \ No newline at end of file +} + +static struct mi_function * +get_function_around_pc(struct mi_process proc, u64 pc) +{ + struct mi_debuginfo debug = proc.debug; + + for (int c = 0; c < debug.cu_count; ++c) { + struct mi_compunit *unit = debug.compilation_units + c; + + if (unit->low_pc <= pc && pc < unit->high_pc) { + + for (int f = 0; f < unit->functions_count; ++f) { + struct mi_function *func = debug.functions + unit->functions_from + f; + + if (func->low_pc <= pc && pc < func->high_pc) { + return(func); + } + } + + break; + } + } + + return(0); +}