Browse Source

backtrace ("bt") command works (only if frame pointer is not ommited!)

master
A.Olokhtonov 3 years ago
parent
commit
0b0fd8d1ea
  1. 21
      command.c
  2. 39
      common.h
  3. 65
      dwarf.c
  4. 2
      main.c
  5. 39
      res/004-scoped-variables.c
  6. 46
      util.c

21
command.c

@ -127,3 +127,24 @@ command_kill(struct mi_process proc)
{ {
kill(proc.pid, SIGKILL); 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);
}
}

39
common.h

@ -43,13 +43,6 @@ struct mi_sourcepoint {
int file; int file;
}; };
struct mi_function {
char *name;
int comp_unit;
u64 low_pc;
u64 high_pc;
};
struct mi_sourcefile { struct mi_sourcefile {
char *filename; char *filename;
char *dir; char *dir;
@ -61,18 +54,15 @@ struct mi_variable {
s64 location; s64 location;
}; };
struct mi_block { struct mi_function {
u64 low_pc; u64 low_pc;
u64 high_pc; u64 high_pc;
char *name;
struct mi_variable variables[4]; // TODO int variables_from;
int var_count; int variables_count;
}; };
struct mi_compunit { struct mi_sourceinfo {
u64 low_pc;
u64 high_pc;
struct mi_sourcepoint *sp_table; struct mi_sourcepoint *sp_table;
int sp_count; int sp_count;
@ -83,17 +73,26 @@ struct mi_compunit {
int source_dirs_count; int source_dirs_count;
char *comp_dir; char *comp_dir;
};
struct mi_block blocks[4]; // TODO struct mi_compunit {
int block_count; u64 low_pc;
u64 high_pc;
struct mi_sourceinfo source;
int functions_from;
int functions_count;
}; };
struct mi_debuginfo { struct mi_debuginfo {
struct mi_compunit compilation_units[16]; // TODO struct mi_compunit compilation_units[16];
int cu_count; struct mi_function functions[64];
struct mi_variable variables[64];
struct mi_function functions[64]; // TODO int cu_count;
int func_count; int func_count;
int var_count;
}; };
struct mi_process { struct mi_process {

65
dwarf.c

@ -768,30 +768,16 @@ read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest,
u32 depth = 0; u32 depth = 0;
u64 base_data_offset = data_offset - header_size; 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_compunit *comp_unit = dest->compilation_units + dest->cu_count;
struct mi_block *block = comp_unit->blocks; struct mi_function *func = dest->functions + dest->func_count;
struct mi_variable *variable = block->variables; struct mi_variable *variable = dest->variables + dest->var_count;
enum dwarf_die_tag parent = 0;
// TODO: make this not bad comp_unit->functions_from = dest->func_count;
for (;;) { for (;;) {
data_offset += decode_leb128(file + data_offset, &code); data_offset += decode_leb128(file + data_offset, &code);
if (code == 0) { 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) { if (depth > 1) {
--depth; --depth;
continue; continue;
@ -808,7 +794,6 @@ read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest,
u32 has_children = file[schema_offset++]; u32 has_children = file[schema_offset++];
if (has_children) { if (has_children) {
parent = tag;
++depth; ++depth;
} }
@ -828,7 +813,7 @@ read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest,
} else if (attribute == DW_AT_high_pc) { } else if (attribute == DW_AT_high_pc) {
comp_unit->high_pc = value; comp_unit->high_pc = value;
} else if (attribute == DW_AT_comp_dir) { } 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) { } else if (tag == DW_TAG_subprogram) {
if (attribute == DW_AT_name) { 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) { } else if (attribute == DW_AT_high_pc) {
func->high_pc = value; 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) { } else if (tag == DW_TAG_variable) {
if (attribute == DW_AT_name) { if (attribute == DW_AT_name) {
variable->name = (char *) value; 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); } while (attribute != 0 || form != 0);
if (parent == DW_TAG_variable) { // NOTE(aolo2): DIE completely processed, finish it up
++variable; if (tag == DW_TAG_subprogram) {
++block->var_count;
}
if (parent == DW_TAG_subprogram) {
func->high_pc = func->low_pc + func->high_pc; func->high_pc = func->low_pc + func->high_pc;
func->comp_unit = dest->cu_count; func->variables_from = dest->var_count;
++func; ++comp_unit->functions_count;
++dest->func_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 static u64
read_debug_line_for_compilation_unit(u8 *file, u64 dl_offset, struct mi_compunit *unit) read_debug_line_for_compilation_unit(u8 *file, u64 dl_offset, struct mi_compunit *unit)
{ {
struct mi_sourcepoint *dest = unit->sp_table; struct mi_sourcepoint *dest = unit->source.sp_table;
int *dest_size = &unit->sp_count; int *dest_size = &unit->source.sp_count;
struct mi_sourcefile *dest_files = unit->source_files; struct mi_sourcefile *dest_files = unit->source.source_files;
int *dest_files_size = &unit->source_file_count; int *dest_files_size = &unit->source.source_file_count;
char **dest_directories = unit->source_directories; char **dest_directories = unit->source.source_directories;
int *dest_directories_size = &unit->source_dirs_count; int *dest_directories_size = &unit->source.source_dirs_count;
struct dwarf_debug_line_header_v3_x32 header = { 0 }; struct dwarf_debug_line_header_v3_x32 header = { 0 };
memcpy(&header, file + dl_offset, 15); /* all fixed-size info */ memcpy(&header, file + dl_offset, 15); /* all fixed-size info */
@ -1246,9 +1227,9 @@ parse_debug_line(u8 *file, struct mi_debuginfo *debug)
// count // count
for (;;) { for (;;) {
u64 size = read_debug_line_for_compilation_unit(file, at, unit); 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.sp_table = calloc(1, unit->source.sp_count * sizeof(struct mi_sourcepoint));
unit->source_directories = calloc(1, unit->source_dirs_count * sizeof(char *)); unit->source.source_directories = calloc(1, unit->source.source_dirs_count * sizeof(char *));
unit->source_files = calloc(1, unit->source_file_count * sizeof(struct mi_sourcefile)); unit->source.source_files = calloc(1, unit->source.source_file_count * sizeof(struct mi_sourcefile));
read += size; read += size;
at += size; at += size;
++unit; ++unit;

2
main.c

@ -55,6 +55,8 @@ main(int argc, char *argv[])
command_next(process); command_next(process);
} else if (0 == strncmp(command, "line\n", command_length)) { } else if (0 == strncmp(command, "line\n", command_length)) {
command_list(process); command_list(process);
} else if (0 == strncmp(command, "bt\n", command_length)) {
command_backtrace(process);
} else if (0 == strncmp(command, "cont\n", command_length)) { } else if (0 == strncmp(command, "cont\n", command_length)) {
command_cont(process); command_cont(process);
wait = 1; wait = 1;

39
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 int
main(int argc, char **argv) main(int argc, char **argv)
{ {
int outer = 1; int a_main = 0;
if (outer > 0) { f1();
char *inner = "INNER"; f3();
int outer = -1;
outer += 10;
}
return(0); return(0);
} }

46
util.c

@ -1,4 +1,3 @@
static struct mi_registers static struct mi_registers
get_process_registers(struct mi_process proc) 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) { for (int c = 0; c < proc.debug.cu_count; ++c) {
struct mi_compunit unit = proc.debug.compilation_units[c]; struct mi_compunit unit = proc.debug.compilation_units[c];
if (unit.low_pc <= pc && pc < unit.high_pc) { if (unit.low_pc <= pc && pc < unit.high_pc) {
for (int i = 0; i < unit.sp_count; ++i) { for (int i = 0; i < unit.source.sp_count; ++i) {
struct mi_sourcepoint *point = unit.sp_table + i; struct mi_sourcepoint *point = unit.source.sp_table + i;
if (point->pc > pc) { if (point->pc > pc) {
*comp_unit = c; *comp_unit = c;
return(unit.sp_table + i - 1); return(unit.source.sp_table + i - 1);
} }
} }
break; 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]; struct mi_compunit unit = proc.debug.compilation_units[comp_unit];
// NOTE: sourcepoint file indices are 1-based // NOTE: sourcepoint file indices are 1-based
if (unit.source_files[sp->file - 1].file.data == 0) { if (unit.source.source_files[sp->file - 1].file.data == 0) {
char *file_filename = unit.source_files[sp->file - 1].filename; char *file_filename = unit.source.source_files[sp->file - 1].filename;
char *file_dirname = unit.source_files[sp->file - 1].dir; char *file_dirname = unit.source.source_files[sp->file - 1].dir;
char *comp_dir = unit.comp_dir; char *comp_dir = unit.source.comp_dir;
char full_path[512] = { 0 }; char full_path[512] = { 0 };
snprintf(full_path, 511, "%s/%s/%s", comp_dir, file_dirname, file_filename); snprintf(full_path, 511, "%s/%s/%s", comp_dir, file_dirname, file_filename);
struct mi_buffer file = read_file_mmap(full_path); 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; char *source = (char *) file.data;
u64 size = file.size; 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); struct mi_registers regs = get_process_registers(proc);
u64 pc_local = regs.rip - proc.base_address; u64 pc_local = regs.rip - proc.base_address;
#if 0
for (int c = 0; c < proc.debug.cu_count; ++c) { for (int c = 0; c < proc.debug.cu_count; ++c) {
struct mi_compunit unit = proc.debug.compilation_units[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);
}
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); return(0);
} }
Loading…
Cancel
Save