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 @@ @@ -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) @@ -15,15 +15,22 @@ command_regs(struct mi_process proc)
static void
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);
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_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
print_sourcepoint(proc, comp_unit, next_sp);
}
static void
@ -37,9 +44,10 @@ command_start(struct mi_process proc) @@ -37,9 +44,10 @@ command_start(struct mi_process proc)
static void
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;
do {
@ -63,23 +71,24 @@ command_next(struct mi_process proc) @@ -63,23 +71,24 @@ command_next(struct mi_process proc)
regs = get_process_registers(proc);
}
// TODO: skip call, repXXX
// TODO: repXXX
//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;
} while (next_sp->line == sp->line);
print_sourcepoint(proc, next_sp);
print_sourcepoint(proc, comp_unit, next_sp);
}
static void
command_list(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);
print_sourcepoint(proc, sp);
struct mi_sourcepoint *sp = pc_to_sourcepoint(proc, regs.rip - proc.base_address, &comp_unit);
print_sourcepoint(proc, comp_unit, sp);
}
static void

37
common.h

@ -45,23 +45,39 @@ struct mi_sourcepoint { @@ -45,23 +45,39 @@ struct mi_sourcepoint {
struct mi_function {
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;
int sp_count;
struct mi_function functions[64]; // TODO
int func_count;
int source_file_count;
struct mi_sourcefile *source_files;
char **source_directories;
int source_dirs_count;
char *comp_dir;
};
struct mi_sourcefile {
char *filename;
char *dir;
struct mi_buffer file;
struct mi_debuginfo {
struct mi_compunit compilation_units[16]; // TODO
int cu_count;
struct mi_function functions[64]; // TODO
int func_count;
};
struct mi_process {
@ -74,11 +90,6 @@ struct mi_process { @@ -74,11 +90,6 @@ struct mi_process {
u64 main_address;
struct mi_debuginfo debug;
int source_file_count;
int source_dirs_count;
struct mi_sourcefile *source_files;
char **source_directories;
};
struct mi_registers {

139
dwarf.c

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
static u64
get_section_offset(u8 *file, char *name)
static struct elf_section_table_entry_x64
get_section_entry(u8 *file, char *name)
{
struct elf_header_x64 header = { 0 };
memcpy(&header, file, sizeof(header));
@ -16,7 +16,8 @@ get_section_offset(u8 *file, char *name) @@ -16,7 +16,8 @@ get_section_offset(u8 *file, char *name)
memcpy(&shstrtab_header, file + shstrtab_header_offset, sizeof(shstrtab_header));
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) {
struct elf_section_table_entry_x64 section_entry = { 0 };
@ -25,12 +26,21 @@ get_section_offset(u8 *file, char *name) @@ -25,12 +26,21 @@ get_section_offset(u8 *file, char *name)
u64 section_name_offset = shstrtab_offset + section_entry.name_offset;
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
@ -232,18 +242,10 @@ read_actual_debug_data(u8 *file, u64 string_offset, u32 address_size, u64 base_d @@ -232,18 +242,10 @@ read_actual_debug_data(u8 *file, u64 string_offset, u32 address_size, u64 base_d
return(increment);
}
static void
parse_debug_info(u8 *file, struct mi_debuginfo *dest)
static u64
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 };
u32 header_size = sizeof(di_header);
memcpy(&di_header, file + debug_info_offset, header_size);
@ -258,7 +260,8 @@ parse_debug_info(u8 *file, struct mi_debuginfo *dest) @@ -258,7 +260,8 @@ parse_debug_info(u8 *file, struct mi_debuginfo *dest)
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 (;;) {
data_offset += decode_leb128(file + data_offset, &code);
@ -294,31 +297,77 @@ parse_debug_info(u8 *file, struct mi_debuginfo *dest) @@ -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);
if (tag == DW_TAG_compile_unit) {
if (attribute == DW_AT_comp_dir) {
dest->comp_dir = (char *) value;
if (attribute == DW_AT_low_pc) {
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) {
if (attribute == DW_AT_name) {
func->name = (char *) value;
} 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);
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) {
func->high_pc = func->low_pc + func->high_pc;
func->comp_unit = dest->cu_count;
++func;
++dest->func_count;
}
}
return(di_header.length + 4);
}
static void
parse_debug_line(u8 *file,
struct mi_sourcepoint *dest, struct mi_sourcefile *dest_files, char **dest_directories,
int *dest_size, int *dest_files_size, int *dest_directories_size)
parse_debug_info(u8 *file, struct mi_debuginfo *dest)
{
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 };
memcpy(&header, file + dl_offset, 15); /* all fixed-size info */
@ -640,6 +689,48 @@ is followed by a single null byte." */ @@ -640,6 +689,48 @@ is followed by a single null byte." */
if (dest_directories_size) {
*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

6
main.c

@ -31,11 +31,7 @@ main(int argc, char *argv[]) @@ -31,11 +31,7 @@ main(int argc, char *argv[])
printf("> ");
fflush(stdout);
parse_debug_line(process.elf, 0, 0, 0, &process.debug.sp_count, &process.source_file_count, &process.source_dirs_count);
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);
parse_debug_line(process.elf, &process.debug);
while ((command_length = getline(&command, &max_command_length, stdin))) {
if (command_length == 1) {

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

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

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

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

@ -0,0 +1,8 @@ @@ -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 @@ @@ -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 @@ @@ -0,0 +1 @@
int foo(int arg);

3
res/Makefile

@ -0,0 +1,3 @@ @@ -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) @@ -98,7 +98,7 @@ get_address_of_subroutine(struct mi_process proc, char *sr)
for (int i = 0; i < proc.debug.func_count; ++i) {
struct mi_function *func = proc.debug.functions + i;
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) @@ -106,14 +106,21 @@ get_address_of_subroutine(struct mi_process proc, char *sr)
}
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
// 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) {
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) @@ -155,27 +162,29 @@ read_file_mmap(char *path)
}
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) {
printf("Unknown location\n");
return;
}
struct mi_compunit unit = proc.debug.compilation_units[comp_unit];
// NOTE: sourcepoint file indices are 1-based
if (proc.source_files[sp->file - 1].file.data == 0) {
char *file_filename = proc.source_files[sp->file - 1].filename;
char *file_dirname = proc.source_files[sp->file - 1].dir;
char *comp_dir = proc.debug.comp_dir;
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;
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);
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;
u64 size = file.size;

Loading…
Cancel
Save