Browse Source

Multiple compilation units

master
aolo2 3 years ago
parent
commit
7c1fa37da2
  1. 4
      .gitignore
  2. 35
      command.c
  3. 37
      common.h
  4. 139
      dwarf.c
  5. 6
      main.c
  6. 0
      res/001-simple-inc.c
  7. 2
      res/001-simple.c
  8. 8
      res/002-compilation-units-impl.c
  9. 9
      res/002-compilation-units.c
  10. 1
      res/002-compilation-units.h
  11. 3
      res/Makefile
  12. BIN
      res/traceme
  13. 33
      util.c

4
.gitignore vendored

@ -0,0 +1,4 @@
.gdb_history
build/
res/001-simple
res/002-compilation-units

35
command.c

@ -15,15 +15,22 @@ command_regs(struct mi_process proc)
static void static void
command_step(struct mi_process proc) command_step(struct mi_process proc)
{ {
int comp_unit;
struct mi_registers regs = get_process_registers(proc);
struct mi_sourcepoint *sp = pc_to_sourcepoint(proc, regs.rip - proc.base_address, &comp_unit);
struct mi_sourcepoint *next_sp;
do {
ptrace(PTRACE_SINGLESTEP, proc.pid, 0, 0); ptrace(PTRACE_SINGLESTEP, proc.pid, 0, 0);
waitpid(proc.pid, 0, 0); waitpid(proc.pid, 0, 0);
regs = get_process_registers(proc);
long instruction = ptrace(PTRACE_PEEKDATA, proc.pid, regs.rip, NULL);
next_sp = pc_to_sourcepoint(proc, regs.rip - proc.base_address, &comp_unit);
if (!next_sp) break;
} while (next_sp->line == sp->line);
#if 1 print_sourcepoint(proc, comp_unit, next_sp);
print_current_instruction(proc);
struct mi_registers regs = get_process_registers(proc);
struct mi_sourcepoint *sp = pc_to_sourcepoint(proc, regs.rip - proc.base_address);
print_sourcepoint(proc, sp);
#endif
} }
static void static void
@ -37,9 +44,10 @@ command_start(struct mi_process proc)
static void static void
command_next(struct mi_process proc) command_next(struct mi_process proc)
{ {
struct mi_registers regs = get_process_registers(proc); int comp_unit;
struct mi_sourcepoint *sp = pc_to_sourcepoint(proc, regs.rip - proc.base_address); struct mi_registers regs = get_process_registers(proc);
struct mi_sourcepoint *sp = pc_to_sourcepoint(proc, regs.rip - proc.base_address, &comp_unit);
struct mi_sourcepoint *next_sp; struct mi_sourcepoint *next_sp;
do { do {
@ -63,23 +71,24 @@ command_next(struct mi_process proc)
regs = get_process_registers(proc); regs = get_process_registers(proc);
} }
// TODO: skip call, repXXX // TODO: repXXX
//printf("%#lx\n", regs.rip - proc.base_address); //printf("%#lx\n", regs.rip - proc.base_address);
next_sp = pc_to_sourcepoint(proc, regs.rip - proc.base_address); next_sp = pc_to_sourcepoint(proc, regs.rip - proc.base_address, &comp_unit);
if (!next_sp) break; if (!next_sp) break;
} while (next_sp->line == sp->line); } while (next_sp->line == sp->line);
print_sourcepoint(proc, next_sp); print_sourcepoint(proc, comp_unit, next_sp);
} }
static void static void
command_list(struct mi_process proc) command_list(struct mi_process proc)
{ {
int comp_unit;
struct mi_registers regs = get_process_registers(proc); struct mi_registers regs = get_process_registers(proc);
struct mi_sourcepoint *sp = pc_to_sourcepoint(proc, regs.rip - proc.base_address); struct mi_sourcepoint *sp = pc_to_sourcepoint(proc, regs.rip - proc.base_address, &comp_unit);
print_sourcepoint(proc, sp); print_sourcepoint(proc, comp_unit, sp);
} }
static void static void

37
common.h

@ -45,23 +45,39 @@ struct mi_sourcepoint {
struct mi_function { struct mi_function {
char *name; char *name;
u64 offset; int comp_unit;
u64 low_pc;
u64 high_pc;
}; };
struct mi_debuginfo { struct mi_sourcefile {
char *filename;
char *dir;
struct mi_buffer file;
};
struct mi_compunit {
u64 low_pc;
u64 high_pc;
struct mi_sourcepoint *sp_table; struct mi_sourcepoint *sp_table;
int sp_count; int sp_count;
struct mi_function functions[64]; // TODO int source_file_count;
int func_count; struct mi_sourcefile *source_files;
char **source_directories;
int source_dirs_count;
char *comp_dir; char *comp_dir;
}; };
struct mi_sourcefile { struct mi_debuginfo {
char *filename; struct mi_compunit compilation_units[16]; // TODO
char *dir; int cu_count;
struct mi_buffer file;
struct mi_function functions[64]; // TODO
int func_count;
}; };
struct mi_process { struct mi_process {
@ -74,11 +90,6 @@ struct mi_process {
u64 main_address; u64 main_address;
struct mi_debuginfo debug; struct mi_debuginfo debug;
int source_file_count;
int source_dirs_count;
struct mi_sourcefile *source_files;
char **source_directories;
}; };
struct mi_registers { struct mi_registers {

139
dwarf.c

@ -1,5 +1,5 @@
static u64 static struct elf_section_table_entry_x64
get_section_offset(u8 *file, char *name) get_section_entry(u8 *file, char *name)
{ {
struct elf_header_x64 header = { 0 }; struct elf_header_x64 header = { 0 };
memcpy(&header, file, sizeof(header)); memcpy(&header, file, sizeof(header));
@ -16,7 +16,8 @@ get_section_offset(u8 *file, char *name)
memcpy(&shstrtab_header, file + shstrtab_header_offset, sizeof(shstrtab_header)); memcpy(&shstrtab_header, file + shstrtab_header_offset, sizeof(shstrtab_header));
u64 shstrtab_offset = shstrtab_header.offset_in_file; u64 shstrtab_offset = shstrtab_header.offset_in_file;
u64 debug_info_offset = 0;
struct elf_section_table_entry_x64 result = { 0 };
for (int i = 0; i < header.section_table_entry_count; ++i) { for (int i = 0; i < header.section_table_entry_count; ++i) {
struct elf_section_table_entry_x64 section_entry = { 0 }; struct elf_section_table_entry_x64 section_entry = { 0 };
@ -25,12 +26,21 @@ get_section_offset(u8 *file, char *name)
u64 section_name_offset = shstrtab_offset + section_entry.name_offset; u64 section_name_offset = shstrtab_offset + section_entry.name_offset;
if (strncmp((char *) file + section_name_offset, name, strlen(name) + 1) == 0) { if (strncmp((char *) file + section_name_offset, name, strlen(name) + 1) == 0) {
debug_info_offset = section_entry.offset_in_file; result = section_entry;
break;
} }
} }
return(debug_info_offset); return(result);
}
static u64
get_section_offset(u8 *file, char *name)
{
struct elf_section_table_entry_x64 entry = get_section_entry(file, name);
u64 result = entry.offset_in_file;
return(result);
} }
static int static int
@ -232,18 +242,10 @@ read_actual_debug_data(u8 *file, u64 string_offset, u32 address_size, u64 base_d
return(increment); return(increment);
} }
static void static u64
parse_debug_info(u8 *file, struct mi_debuginfo *dest) read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest,
u64 debug_info_offset, u64 debug_abbrev_offset, u64 debug_str_offset)
{ {
u64 debug_info_offset = get_section_offset(file, ".debug_info");
printf("Found .debug_info at offset %#lx\n", debug_info_offset);
u64 debug_abbrev_offset = get_section_offset(file, ".debug_abbrev");
printf("Found .debug_abbrev at offset %#lx\n", debug_abbrev_offset);
u64 debug_str_offset = get_section_offset(file, ".debug_str");
printf("Found .debug_str at offset %#lx\n", debug_str_offset);
struct dwarf_debug_info_header_x32 di_header = { 0 }; struct dwarf_debug_info_header_x32 di_header = { 0 };
u32 header_size = sizeof(di_header); u32 header_size = sizeof(di_header);
memcpy(&di_header, file + debug_info_offset, header_size); memcpy(&di_header, file + debug_info_offset, header_size);
@ -258,7 +260,8 @@ parse_debug_info(u8 *file, struct mi_debuginfo *dest)
int found_sr = 0; int found_sr = 0;
struct mi_function *func = dest->functions; struct mi_function *func = dest->functions + dest->func_count;
struct mi_compunit *comp_unit = dest->compilation_units + dest->cu_count;
for (;;) { for (;;) {
data_offset += decode_leb128(file + data_offset, &code); data_offset += decode_leb128(file + data_offset, &code);
@ -294,31 +297,77 @@ parse_debug_info(u8 *file, struct mi_debuginfo *dest)
data_offset += read_actual_debug_data(file, debug_str_offset, di_header.address_size, base_data_offset, form, data_offset, &value); data_offset += read_actual_debug_data(file, debug_str_offset, di_header.address_size, base_data_offset, form, data_offset, &value);
if (tag == DW_TAG_compile_unit) { if (tag == DW_TAG_compile_unit) {
if (attribute == DW_AT_comp_dir) { if (attribute == DW_AT_low_pc) {
dest->comp_dir = (char *) value; comp_unit->low_pc = value;
} 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;
} }
} else if (tag == DW_TAG_subprogram) { } else if (tag == DW_TAG_subprogram) {
if (attribute == DW_AT_name) { if (attribute == DW_AT_name) {
func->name = (char *) value; func->name = (char *) value;
} else if (attribute == DW_AT_low_pc) { } else if (attribute == DW_AT_low_pc) {
func->offset = value; func->low_pc = value;
} else if (attribute == DW_AT_high_pc) {
func->high_pc = value;
} }
} }
} while (attribute != 0 || form != 0); } while (attribute != 0 || form != 0);
if (tag == DW_TAG_compile_unit) {
comp_unit->high_pc = comp_unit->low_pc + comp_unit->high_pc;
++comp_unit;
++dest->cu_count;
}
if (tag == DW_TAG_subprogram) { if (tag == DW_TAG_subprogram) {
func->high_pc = func->low_pc + func->high_pc;
func->comp_unit = dest->cu_count;
++func; ++func;
++dest->func_count; ++dest->func_count;
} }
} }
return(di_header.length + 4);
} }
static void static void
parse_debug_line(u8 *file, parse_debug_info(u8 *file, struct mi_debuginfo *dest)
struct mi_sourcepoint *dest, struct mi_sourcefile *dest_files, char **dest_directories, {
int *dest_size, int *dest_files_size, int *dest_directories_size) struct elf_section_table_entry_x64 debug_info = get_section_entry(file, ".debug_info");
printf("Found .debug_info at offset %#lx\n", debug_info.offset_in_file);
u64 debug_abbrev_offset = get_section_offset(file, ".debug_abbrev");
printf("Found .debug_abbrev at offset %#lx\n", debug_abbrev_offset);
u64 debug_str_offset = get_section_offset(file, ".debug_str");
printf("Found .debug_str at offset %#lx\n", debug_str_offset);
u64 at = debug_info.offset_in_file;
u64 read = 0;
for (;;) {
u64 size = read_debug_info_for_compilation_unit(file, dest, at, debug_abbrev_offset, debug_str_offset);
read += size;
at += size;
if (read >= debug_info.size) {
break;
}
}
}
static u64
read_debug_line_for_compilation_unit(u8 *file, u64 dl_offset, struct mi_compunit *unit)
{ {
u64 dl_offset = get_section_offset(file, ".debug_line"); struct mi_sourcepoint *dest = unit->sp_table;
int *dest_size = &unit->sp_count;
struct mi_sourcefile *dest_files = unit->source_files;
int *dest_files_size = &unit->source_file_count;
char **dest_directories = unit->source_directories;
int *dest_directories_size = &unit->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 */
@ -640,6 +689,48 @@ is followed by a single null byte." */
if (dest_directories_size) { if (dest_directories_size) {
*dest_directories_size = ndirs; *dest_directories_size = ndirs;
} }
return(header.length + 4);
}
static void
parse_debug_line(u8 *file, struct mi_debuginfo *debug)
{
struct elf_section_table_entry_x64 debug_line = get_section_entry(file, ".debug_line");
u64 at = debug_line.offset_in_file;
u64 read = 0;
struct mi_compunit *unit = debug->compilation_units;
// 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));
read += size;
at += size;
++unit;
if (read >= debug_line.size) {
break;
}
}
unit = debug->compilation_units;
at = debug_line.offset_in_file;
read = 0;
// fill
for (;;) {
u64 size = read_debug_line_for_compilation_unit(file, at, unit);
read += size;
at += size;
++unit;
if (read >= debug_line.size) {
break;
}
}
} }
static u64 static u64

6
main.c

@ -31,11 +31,7 @@ main(int argc, char *argv[])
printf("> "); printf("> ");
fflush(stdout); fflush(stdout);
parse_debug_line(process.elf, 0, 0, 0, &process.debug.sp_count, &process.source_file_count, &process.source_dirs_count); parse_debug_line(process.elf, &process.debug);
process.debug.sp_table = calloc(1, process.debug.sp_count * sizeof(struct mi_sourcepoint));
process.source_directories = calloc(1, process.source_dirs_count * sizeof(char *));
process.source_files = calloc(1, process.source_file_count * sizeof(struct mi_sourcefile));
parse_debug_line(process.elf, process.debug.sp_table, process.source_files, process.source_directories, 0, 0, 0);
while ((command_length = getline(&command, &max_command_length, stdin))) { while ((command_length = getline(&command, &max_command_length, stdin))) {
if (command_length == 1) { if (command_length == 1) {

0
trace_include.c → res/001-simple-inc.c

2
traceme.c → res/001-simple.c

@ -1,7 +1,7 @@
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include "trace_include.c" #include "001-simple-inc.c"
int main() int main()
{ {

8
res/002-compilation-units-impl.c

@ -0,0 +1,8 @@
#include "002-compilation-units.h"
int foo(int arg)
{
int sq = arg * arg;
int sq2 = sq * 2;
return(sq2);
}

9
res/002-compilation-units.c

@ -0,0 +1,9 @@
#include "002-compilation-units.h"
int
main(void)
{
int a = 3;
int b = foo(a);
return(b);
}

1
res/002-compilation-units.h

@ -0,0 +1 @@
int foo(int arg);

3
res/Makefile

@ -0,0 +1,3 @@
all:
gcc -g -o 001-simple 001-simple.c
gcc -g -o 002-compilation-units 002-compilation-units.c 002-compilation-units-impl.c

BIN
res/traceme

Binary file not shown.

33
util.c

@ -98,7 +98,7 @@ get_address_of_subroutine(struct mi_process proc, char *sr)
for (int i = 0; i < proc.debug.func_count; ++i) { for (int i = 0; i < proc.debug.func_count; ++i) {
struct mi_function *func = proc.debug.functions + i; struct mi_function *func = proc.debug.functions + i;
if (0 == strcmp(func->name, sr)) { if (0 == strcmp(func->name, sr)) {
return(func->offset); return(func->low_pc);
} }
} }
@ -106,14 +106,21 @@ get_address_of_subroutine(struct mi_process proc, char *sr)
} }
static struct mi_sourcepoint * static struct mi_sourcepoint *
pc_to_sourcepoint(struct mi_process proc, u64 pc) pc_to_sourcepoint(struct mi_process proc, u64 pc, int *comp_unit)
{ {
// NOTE: find first point BIGGER that pc, return the sourcepoint just before that // NOTE: find first point BIGGER that pc, return the sourcepoint just before that
// TODO: binary search // TODO: binary search
for (int i = 0; i < proc.debug.sp_count; ++i) {
struct mi_sourcepoint *point = proc.debug.sp_table + i; 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;
if (point->pc > pc) { if (point->pc > pc) {
return(proc.debug.sp_table + i - 1); *comp_unit = c;
return(unit.sp_table + i - 1);
}
}
} }
} }
@ -155,27 +162,29 @@ read_file_mmap(char *path)
} }
static void static void
print_sourcepoint(struct mi_process proc, struct mi_sourcepoint *sp) print_sourcepoint(struct mi_process proc, int comp_unit, struct mi_sourcepoint *sp)
{ {
if (!sp) { if (!sp) {
printf("Unknown location\n"); printf("Unknown location\n");
return; return;
} }
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 (proc.source_files[sp->file - 1].file.data == 0) { if (unit.source_files[sp->file - 1].file.data == 0) {
char *file_filename = proc.source_files[sp->file - 1].filename; char *file_filename = unit.source_files[sp->file - 1].filename;
char *file_dirname = proc.source_files[sp->file - 1].dir; char *file_dirname = unit.source_files[sp->file - 1].dir;
char *comp_dir = proc.debug.comp_dir; char *comp_dir = unit.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);
proc.source_files[sp->file - 1].file = file; unit.source_files[sp->file - 1].file = file;
} }
struct mi_buffer file = proc.source_files[sp->file - 1].file; struct mi_buffer file = unit.source_files[sp->file - 1].file;
char *source = (char *) file.data; char *source = (char *) file.data;
u64 size = file.size; u64 size = file.size;

Loading…
Cancel
Save