Expand tabs in addr2line.c

.git-blame-ignore-revs will be updated after this commit is merged.
This commit is contained in:
Peter Zhu 2024-11-27 13:16:49 -05:00
parent bd88cffd8c
commit 2da92388b9
Notes: git 2024-11-28 16:35:01 +00:00

View File

@ -56,11 +56,11 @@
# ifdef _AIX # ifdef _AIX
#pragma alloca #pragma alloca
# else # else
# ifndef alloca /* predefined by HP cc +Olibcalls */ # ifndef alloca /* predefined by HP cc +Olibcalls */
void *alloca(); void *alloca();
# endif # endif
# endif /* AIX */ # endif /* AIX */
# endif /* HAVE_ALLOCA_H */ # endif /* HAVE_ALLOCA_H */
# ifndef UNREACHABLE # ifndef UNREACHABLE
# define UNREACHABLE __builtin_unreachable() # define UNREACHABLE __builtin_unreachable()
# endif # endif
@ -220,13 +220,13 @@ uleb128(const char **p)
unsigned long r = 0; unsigned long r = 0;
int s = 0; int s = 0;
for (;;) { for (;;) {
unsigned char b = (unsigned char)*(*p)++; unsigned char b = (unsigned char)*(*p)++;
if (b < 0x80) { if (b < 0x80) {
r += (unsigned long)b << s; r += (unsigned long)b << s;
break; break;
} }
r += (b & 0x7f) << s; r += (b & 0x7f) << s;
s += 7; s += 7;
} }
return r; return r;
} }
@ -237,18 +237,18 @@ sleb128(const char **p)
long r = 0; long r = 0;
int s = 0; int s = 0;
for (;;) { for (;;) {
unsigned char b = (unsigned char)*(*p)++; unsigned char b = (unsigned char)*(*p)++;
if (b < 0x80) { if (b < 0x80) {
if (b & 0x40) { if (b & 0x40) {
r -= (0x80 - b) << s; r -= (0x80 - b) << s;
} }
else { else {
r += (b & 0x3f) << s; r += (b & 0x3f) << s;
} }
break; break;
} }
r += (b & 0x7f) << s; r += (b & 0x7f) << s;
s += 7; s += 7;
} }
return r; return r;
} }
@ -257,16 +257,16 @@ static const char *
get_nth_dirname(unsigned long dir, const char *p, FILE *errout) get_nth_dirname(unsigned long dir, const char *p, FILE *errout)
{ {
if (!dir--) { if (!dir--) {
return ""; return "";
} }
while (dir--) { while (dir--) {
while (*p) p++; while (*p) p++;
p++; p++;
if (!*p) { if (!*p) {
kprintf("Unexpected directory number %lu in %s\n", kprintf("Unexpected directory number %lu in %s\n",
dir, binary_filename); dir, binary_filename);
return ""; return "";
} }
} }
return p; return p;
} }
@ -319,19 +319,19 @@ fill_filename(int file, uint8_t format, uint16_t version, const char *include_di
static void static void
fill_line(int num_traces, void **traces, uintptr_t addr, int file, int line, fill_line(int num_traces, void **traces, uintptr_t addr, int file, int line,
uint8_t format, uint16_t version, const char *include_directories, const char *filenames, uint8_t format, uint16_t version, const char *include_directories, const char *filenames,
obj_info_t *obj, line_info_t *lines, int offset, FILE *errout) obj_info_t *obj, line_info_t *lines, int offset, FILE *errout)
{ {
int i; int i;
addr += obj->base_addr - obj->vmaddr; addr += obj->base_addr - obj->vmaddr;
for (i = offset; i < num_traces; i++) { for (i = offset; i < num_traces; i++) {
uintptr_t a = (uintptr_t)traces[i]; uintptr_t a = (uintptr_t)traces[i];
/* We assume one line code doesn't result >100 bytes of native code. /* We assume one line code doesn't result >100 bytes of native code.
We may want more reliable way eventually... */ We may want more reliable way eventually... */
if (addr < a && a < addr + 100) { if (addr < a && a < addr + 100) {
fill_filename(file, format, version, include_directories, filenames, &lines[i], obj, errout); fill_filename(file, format, version, include_directories, filenames, &lines[i], obj, errout);
lines[i].line = line; lines[i].line = line;
} }
} }
} }
@ -362,8 +362,8 @@ parse_debug_line_header(obj_info_t *obj, const char **pp, struct LineNumberProgr
header->format = 4; header->format = 4;
if (header->unit_length == 0xffffffff) { if (header->unit_length == 0xffffffff) {
header->unit_length = *(uint64_t *)p; header->unit_length = *(uint64_t *)p;
p += sizeof(uint64_t); p += sizeof(uint64_t);
header->format = 8; header->format = 8;
} }
@ -427,7 +427,7 @@ parse_debug_line_header(obj_info_t *obj, const char **pp, struct LineNumberProgr
static int static int
parse_debug_line_cu(int num_traces, void **traces, const char **debug_line, parse_debug_line_cu(int num_traces, void **traces, const char **debug_line,
obj_info_t *obj, line_info_t *lines, int offset, FILE *errout) obj_info_t *obj, line_info_t *lines, int offset, FILE *errout)
{ {
const char *p = (const char *)*debug_line; const char *p = (const char *)*debug_line;
struct LineNumberProgramHeader header; struct LineNumberProgramHeader header;
@ -448,105 +448,105 @@ parse_debug_line_cu(int num_traces, void **traces, const char **debug_line,
return -1; return -1;
is_stmt = header.default_is_stmt; is_stmt = header.default_is_stmt;
#define FILL_LINE() \ #define FILL_LINE() \
do { \ do { \
fill_line(num_traces, traces, addr, file, line, \ fill_line(num_traces, traces, addr, file, line, \
header.format, \ header.format, \
header.version, \ header.version, \
header.include_directories, \ header.include_directories, \
header.filenames, \ header.filenames, \
obj, lines, offset, errout); \ obj, lines, offset, errout); \
/*basic_block = prologue_end = epilogue_begin = 0;*/ \ /*basic_block = prologue_end = epilogue_begin = 0;*/ \
} while (0) } while (0)
while (p < header.cu_end) { while (p < header.cu_end) {
unsigned long a; unsigned long a;
unsigned char op = *p++; unsigned char op = *p++;
switch (op) { switch (op) {
case DW_LNS_copy: case DW_LNS_copy:
FILL_LINE(); FILL_LINE();
break; break;
case DW_LNS_advance_pc: case DW_LNS_advance_pc:
a = uleb128(&p) * header.minimum_instruction_length; a = uleb128(&p) * header.minimum_instruction_length;
addr += a; addr += a;
break; break;
case DW_LNS_advance_line: { case DW_LNS_advance_line: {
long a = sleb128(&p); long a = sleb128(&p);
line += a; line += a;
break; break;
} }
case DW_LNS_set_file: case DW_LNS_set_file:
file = (unsigned int)uleb128(&p); file = (unsigned int)uleb128(&p);
break; break;
case DW_LNS_set_column: case DW_LNS_set_column:
/*column = (unsigned int)*/(void)uleb128(&p); /*column = (unsigned int)*/(void)uleb128(&p);
break; break;
case DW_LNS_negate_stmt: case DW_LNS_negate_stmt:
is_stmt = !is_stmt; is_stmt = !is_stmt;
break; break;
case DW_LNS_set_basic_block: case DW_LNS_set_basic_block:
/*basic_block = 1; */ /*basic_block = 1; */
break; break;
case DW_LNS_const_add_pc: case DW_LNS_const_add_pc:
a = ((255UL - header.opcode_base) / header.line_range) * a = ((255UL - header.opcode_base) / header.line_range) *
header.minimum_instruction_length; header.minimum_instruction_length;
addr += a; addr += a;
break; break;
case DW_LNS_fixed_advance_pc: case DW_LNS_fixed_advance_pc:
a = *(uint16_t *)p; a = *(uint16_t *)p;
p += sizeof(uint16_t); p += sizeof(uint16_t);
addr += a; addr += a;
break; break;
case DW_LNS_set_prologue_end: case DW_LNS_set_prologue_end:
/* prologue_end = 1; */ /* prologue_end = 1; */
break; break;
case DW_LNS_set_epilogue_begin: case DW_LNS_set_epilogue_begin:
/* epilogue_begin = 1; */ /* epilogue_begin = 1; */
break; break;
case DW_LNS_set_isa: case DW_LNS_set_isa:
/* isa = (unsigned int)*/(void)uleb128(&p); /* isa = (unsigned int)*/(void)uleb128(&p);
break; break;
case 0: case 0:
a = uleb128(&p); a = uleb128(&p);
op = *p++; op = *p++;
switch (op) { switch (op) {
case DW_LNE_end_sequence: case DW_LNE_end_sequence:
/* end_sequence = 1; */ /* end_sequence = 1; */
FILL_LINE(); FILL_LINE();
addr = 0; addr = 0;
file = 1; file = 1;
line = 1; line = 1;
/* column = 0; */ /* column = 0; */
is_stmt = header.default_is_stmt; is_stmt = header.default_is_stmt;
/* end_sequence = 0; */ /* end_sequence = 0; */
/* isa = 0; */ /* isa = 0; */
break; break;
case DW_LNE_set_address: case DW_LNE_set_address:
addr = *(unsigned long *)p; addr = *(unsigned long *)p;
p += sizeof(unsigned long); p += sizeof(unsigned long);
break; break;
case DW_LNE_define_file: case DW_LNE_define_file:
kprintf("Unsupported operation in %s\n", kprintf("Unsupported operation in %s\n",
binary_filename); binary_filename);
break; break;
case DW_LNE_set_discriminator: case DW_LNE_set_discriminator:
/* TODO:currently ignore */ /* TODO:currently ignore */
uleb128(&p); uleb128(&p);
break; break;
default: default:
kprintf("Unknown extended opcode: %d in %s\n", kprintf("Unknown extended opcode: %d in %s\n",
op, binary_filename); op, binary_filename);
} }
break; break;
default: { default: {
uint8_t adjusted_opcode = op - header.opcode_base; uint8_t adjusted_opcode = op - header.opcode_base;
uint8_t operation_advance = adjusted_opcode / header.line_range; uint8_t operation_advance = adjusted_opcode / header.line_range;
/* NOTE: this code doesn't support VLIW */ /* NOTE: this code doesn't support VLIW */
addr += operation_advance * header.minimum_instruction_length; addr += operation_advance * header.minimum_instruction_length;
line += header.line_base + (adjusted_opcode % header.line_range); line += header.line_base + (adjusted_opcode % header.line_range);
FILL_LINE(); FILL_LINE();
} }
} }
} }
*debug_line = (char *)p; *debug_line = (char *)p;
return 0; return 0;
@ -554,17 +554,17 @@ parse_debug_line_cu(int num_traces, void **traces, const char **debug_line,
static int static int
parse_debug_line(int num_traces, void **traces, parse_debug_line(int num_traces, void **traces,
const char *debug_line, unsigned long size, const char *debug_line, unsigned long size,
obj_info_t *obj, line_info_t *lines, int offset, FILE *errout) obj_info_t *obj, line_info_t *lines, int offset, FILE *errout)
{ {
const char *debug_line_end = debug_line + size; const char *debug_line_end = debug_line + size;
while (debug_line < debug_line_end) { while (debug_line < debug_line_end) {
if (parse_debug_line_cu(num_traces, traces, &debug_line, obj, lines, offset, errout)) if (parse_debug_line_cu(num_traces, traces, &debug_line, obj, lines, offset, errout))
return -1; return -1;
} }
if (debug_line != debug_line_end) { if (debug_line != debug_line_end) {
kprintf("Unexpected size of .debug_line in %s\n", kprintf("Unexpected size of .debug_line in %s\n",
binary_filename); binary_filename);
} }
return 0; return 0;
} }
@ -572,7 +572,7 @@ parse_debug_line(int num_traces, void **traces,
/* read file and fill lines */ /* read file and fill lines */
static uintptr_t static uintptr_t
fill_lines(int num_traces, void **traces, int check_debuglink, fill_lines(int num_traces, void **traces, int check_debuglink,
obj_info_t **objp, line_info_t *lines, int offset, FILE *errout); obj_info_t **objp, line_info_t *lines, int offset, FILE *errout);
static void static void
append_obj(obj_info_t **objp) append_obj(obj_info_t **objp)
@ -600,7 +600,7 @@ append_obj(obj_info_t **objp)
// check the path pattern of "/usr/lib/debug/usr/bin/ruby.debug" // check the path pattern of "/usr/lib/debug/usr/bin/ruby.debug"
static void static void
follow_debuglink(const char *debuglink, int num_traces, void **traces, follow_debuglink(const char *debuglink, int num_traces, void **traces,
obj_info_t **objp, line_info_t *lines, int offset, FILE *errout) obj_info_t **objp, line_info_t *lines, int offset, FILE *errout)
{ {
static const char global_debug_dir[] = "/usr/lib/debug"; static const char global_debug_dir[] = "/usr/lib/debug";
const size_t global_debug_dir_len = sizeof(global_debug_dir) - 1; const size_t global_debug_dir_len = sizeof(global_debug_dir) - 1;
@ -610,13 +610,13 @@ follow_debuglink(const char *debuglink, int num_traces, void **traces,
p = strrchr(binary_filename, '/'); p = strrchr(binary_filename, '/');
if (!p) { if (!p) {
return; return;
} }
p[1] = '\0'; p[1] = '\0';
len = strlen(binary_filename); len = strlen(binary_filename);
if (len >= PATH_MAX - global_debug_dir_len) if (len >= PATH_MAX - global_debug_dir_len)
len = PATH_MAX - global_debug_dir_len - 1; len = PATH_MAX - global_debug_dir_len - 1;
memmove(binary_filename + global_debug_dir_len, binary_filename, len); memmove(binary_filename + global_debug_dir_len, binary_filename, len);
memcpy(binary_filename, global_debug_dir, global_debug_dir_len); memcpy(binary_filename, global_debug_dir, global_debug_dir_len);
len += global_debug_dir_len; len += global_debug_dir_len;
@ -2029,14 +2029,14 @@ uncompress_debug_section(ElfW(Shdr) *shdr, char *file, char **ptr)
int ret = 0; int ret = 0;
if (chdr->ch_type != ELFCOMPRESS_ZLIB) { if (chdr->ch_type != ELFCOMPRESS_ZLIB) {
/* unsupported compression type */ /* unsupported compression type */
return 0; return 0;
} }
*ptr = malloc(destsize); *ptr = malloc(destsize);
if (!*ptr) return 0; if (!*ptr) return 0;
ret = uncompress((Bytef *)*ptr, &destsize, ret = uncompress((Bytef *)*ptr, &destsize,
(const Bytef*)chdr + sizeof(ElfW(Chdr)), (const Bytef*)chdr + sizeof(ElfW(Chdr)),
shdr->sh_size - sizeof(ElfW(Chdr))); shdr->sh_size - sizeof(ElfW(Chdr)));
if (ret != Z_OK) goto fail; if (ret != Z_OK) goto fail;
return destsize; return destsize;
@ -2051,7 +2051,7 @@ fail:
/* read file and fill lines */ /* read file and fill lines */
static uintptr_t static uintptr_t
fill_lines(int num_traces, void **traces, int check_debuglink, fill_lines(int num_traces, void **traces, int check_debuglink,
obj_info_t **objp, line_info_t *lines, int offset, FILE *errout) obj_info_t **objp, line_info_t *lines, int offset, FILE *errout)
{ {
int i, j; int i, j;
char *shstr; char *shstr;
@ -2069,40 +2069,40 @@ fill_lines(int num_traces, void **traces, int check_debuglink,
fd = open(binary_filename, O_RDONLY); fd = open(binary_filename, O_RDONLY);
if (fd < 0) { if (fd < 0) {
goto fail; goto fail;
} }
filesize = lseek(fd, 0, SEEK_END); filesize = lseek(fd, 0, SEEK_END);
if (filesize < 0) { if (filesize < 0) {
int e = errno; int e = errno;
close(fd); close(fd);
kprintf("lseek: %s\n", strerror(e)); kprintf("lseek: %s\n", strerror(e));
goto fail; goto fail;
} }
#if SIZEOF_OFF_T > SIZEOF_SIZE_T #if SIZEOF_OFF_T > SIZEOF_SIZE_T
if (filesize > (off_t)SIZE_MAX) { if (filesize > (off_t)SIZE_MAX) {
close(fd); close(fd);
kprintf("Too large file %s\n", binary_filename); kprintf("Too large file %s\n", binary_filename);
goto fail; goto fail;
} }
#endif #endif
lseek(fd, 0, SEEK_SET); lseek(fd, 0, SEEK_SET);
/* async-signal unsafe */ /* async-signal unsafe */
file = (char *)mmap(NULL, (size_t)filesize, PROT_READ, MAP_SHARED, fd, 0); file = (char *)mmap(NULL, (size_t)filesize, PROT_READ, MAP_SHARED, fd, 0);
if (file == MAP_FAILED) { if (file == MAP_FAILED) {
int e = errno; int e = errno;
close(fd); close(fd);
kprintf("mmap: %s\n", strerror(e)); kprintf("mmap: %s\n", strerror(e));
goto fail; goto fail;
} }
close(fd); close(fd);
ehdr = (ElfW(Ehdr) *)file; ehdr = (ElfW(Ehdr) *)file;
if (memcmp(ehdr->e_ident, "\177ELF", 4) != 0) { if (memcmp(ehdr->e_ident, "\177ELF", 4) != 0) {
/* /*
* Huh? Maybe filename was overridden by setproctitle() and * Huh? Maybe filename was overridden by setproctitle() and
* it match non-elf file. * it match non-elf file.
*/ */
goto fail; goto fail;
} }
obj->mapped = file; obj->mapped = file;
obj->mapped_size = (size_t)filesize; obj->mapped_size = (size_t)filesize;
@ -2114,32 +2114,32 @@ fill_lines(int num_traces, void **traces, int check_debuglink,
for (i = 0; i < ehdr->e_shnum; i++) { for (i = 0; i < ehdr->e_shnum; i++) {
char *section_name = shstr + shdr[i].sh_name; char *section_name = shstr + shdr[i].sh_name;
switch (shdr[i].sh_type) { switch (shdr[i].sh_type) {
case SHT_STRTAB: case SHT_STRTAB:
if (!strcmp(section_name, ".strtab")) { if (!strcmp(section_name, ".strtab")) {
strtab_shdr = shdr + i; strtab_shdr = shdr + i;
} }
else if (!strcmp(section_name, ".dynstr")) { else if (!strcmp(section_name, ".dynstr")) {
dynstr_shdr = shdr + i; dynstr_shdr = shdr + i;
} }
break; break;
case SHT_SYMTAB: case SHT_SYMTAB:
/* if (!strcmp(section_name, ".symtab")) */ /* if (!strcmp(section_name, ".symtab")) */
symtab_shdr = shdr + i; symtab_shdr = shdr + i;
break; break;
case SHT_DYNSYM: case SHT_DYNSYM:
/* if (!strcmp(section_name, ".dynsym")) */ /* if (!strcmp(section_name, ".dynsym")) */
dynsym_shdr = shdr + i; dynsym_shdr = shdr + i;
break; break;
case SHT_NOTE: case SHT_NOTE:
if (!strcmp(section_name, ".note.gnu.build-id")) { if (!strcmp(section_name, ".note.gnu.build-id")) {
note_gnu_build_id = shdr + i; note_gnu_build_id = shdr + i;
} }
break; break;
case SHT_PROGBITS: case SHT_PROGBITS:
if (!strcmp(section_name, ".gnu_debuglink")) { if (!strcmp(section_name, ".gnu_debuglink")) {
gnu_debuglink_shdr = shdr + i; gnu_debuglink_shdr = shdr + i;
} }
else { else {
const char *debug_section_names[] = { const char *debug_section_names[] = {
".debug_abbrev", ".debug_abbrev",
@ -2169,17 +2169,17 @@ fill_lines(int num_traces, void **traces, int check_debuglink,
break; break;
} }
} }
break; break;
} }
} }
if (offset == -1) { if (offset == -1) {
/* main executable */ /* main executable */
offset = 0; offset = 0;
if (dynsym_shdr && dynstr_shdr) { if (dynsym_shdr && dynstr_shdr) {
char *strtab = file + dynstr_shdr->sh_offset; char *strtab = file + dynstr_shdr->sh_offset;
ElfW(Sym) *symtab = (ElfW(Sym) *)(file + dynsym_shdr->sh_offset); ElfW(Sym) *symtab = (ElfW(Sym) *)(file + dynsym_shdr->sh_offset);
int symtab_count = (int)(dynsym_shdr->sh_size / sizeof(ElfW(Sym))); int symtab_count = (int)(dynsym_shdr->sh_size / sizeof(ElfW(Sym)));
void *handle = dlopen(NULL, RTLD_NOW|RTLD_LOCAL); void *handle = dlopen(NULL, RTLD_NOW|RTLD_LOCAL);
if (handle) { if (handle) {
for (j = 0; j < symtab_count; j++) { for (j = 0; j < symtab_count; j++) {
@ -2196,14 +2196,14 @@ fill_lines(int num_traces, void **traces, int check_debuglink,
} }
dlclose(handle); dlclose(handle);
} }
if (ehdr->e_type == ET_EXEC) { if (ehdr->e_type == ET_EXEC) {
obj->base_addr = 0; obj->base_addr = 0;
} }
else { else {
/* PIE (position-independent executable) */ /* PIE (position-independent executable) */
obj->base_addr = dladdr_fbase; obj->base_addr = dladdr_fbase;
} }
} }
} }
if (obj->debug_info.ptr && obj->debug_abbrev.ptr) { if (obj->debug_info.ptr && obj->debug_abbrev.ptr) {
@ -2249,21 +2249,21 @@ use_symtab:
} }
if (!obj->debug_line.ptr) { if (!obj->debug_line.ptr) {
/* This file doesn't have .debug_line section, /* This file doesn't have .debug_line section,
let's check .gnu_debuglink section instead. */ let's check .gnu_debuglink section instead. */
if (gnu_debuglink_shdr && check_debuglink) { if (gnu_debuglink_shdr && check_debuglink) {
follow_debuglink(file + gnu_debuglink_shdr->sh_offset, follow_debuglink(file + gnu_debuglink_shdr->sh_offset,
num_traces, traces, num_traces, traces,
objp, lines, offset, errout); objp, lines, offset, errout);
} }
if (note_gnu_build_id && check_debuglink) { if (note_gnu_build_id && check_debuglink) {
ElfW(Nhdr) *nhdr = (ElfW(Nhdr)*) (file + note_gnu_build_id->sh_offset); ElfW(Nhdr) *nhdr = (ElfW(Nhdr)*) (file + note_gnu_build_id->sh_offset);
const char *build_id = (char *)(nhdr + 1) + nhdr->n_namesz; const char *build_id = (char *)(nhdr + 1) + nhdr->n_namesz;
follow_debuglink_build_id(build_id, nhdr->n_descsz, follow_debuglink_build_id(build_id, nhdr->n_descsz,
num_traces, traces, num_traces, traces,
objp, lines, offset, errout); objp, lines, offset, errout);
} }
goto finish; goto finish;
} }
if (parse_debug_line(num_traces, traces, if (parse_debug_line(num_traces, traces,
@ -2543,8 +2543,8 @@ main_exe_path(FILE *errout)
size_t len = PATH_MAX; size_t len = PATH_MAX;
int err = sysctl(mib, 4, binary_filename, &len, NULL, 0); int err = sysctl(mib, 4, binary_filename, &len, NULL, 0);
if (err) { if (err) {
kprintf("Can't get the path of ruby"); kprintf("Can't get the path of ruby");
return -1; return -1;
} }
len--; /* sysctl sets strlen+1 */ len--; /* sysctl sets strlen+1 */
return len; return len;
@ -2626,79 +2626,79 @@ rb_dump_backtrace_with_lines(int num_traces, void **traces, FILE *errout)
char *main_path = NULL; /* used on printing backtrace */ char *main_path = NULL; /* used on printing backtrace */
ssize_t len; ssize_t len;
if ((len = main_exe_path(errout)) > 0) { if ((len = main_exe_path(errout)) > 0) {
main_path = (char *)alloca(len + 1); main_path = (char *)alloca(len + 1);
if (main_path) { if (main_path) {
uintptr_t addr; uintptr_t addr;
memcpy(main_path, binary_filename, len+1); memcpy(main_path, binary_filename, len+1);
append_obj(&obj); append_obj(&obj);
obj->path = main_path; obj->path = main_path;
addr = fill_lines(num_traces, traces, 1, &obj, lines, 0, errout); addr = fill_lines(num_traces, traces, 1, &obj, lines, 0, errout);
if (addr != (uintptr_t)-1) { if (addr != (uintptr_t)-1) {
dladdr_fbases[0] = (void *)addr; dladdr_fbases[0] = (void *)addr;
} }
} }
} }
#endif #endif
/* fill source lines by reading dwarf */ /* fill source lines by reading dwarf */
for (i = 0; i < num_traces; i++) { for (i = 0; i < num_traces; i++) {
Dl_info info; Dl_info info;
if (lines[i].line) continue; if (lines[i].line) continue;
if (dladdr(traces[i], &info)) { if (dladdr(traces[i], &info)) {
const char *path; const char *path;
void **p; void **p;
/* skip symbols which is in already checked objects */ /* skip symbols which is in already checked objects */
/* if the binary is strip-ed, this may effect */ /* if the binary is strip-ed, this may effect */
for (p=dladdr_fbases; *p; p++) { for (p=dladdr_fbases; *p; p++) {
if (*p == info.dli_fbase) { if (*p == info.dli_fbase) {
if (info.dli_fname) lines[i].path = info.dli_fname; if (info.dli_fname) lines[i].path = info.dli_fname;
if (info.dli_sname) lines[i].sname = info.dli_sname; if (info.dli_sname) lines[i].sname = info.dli_sname;
goto next_line; goto next_line;
} }
} }
*p = info.dli_fbase; *p = info.dli_fbase;
append_obj(&obj); append_obj(&obj);
obj->base_addr = (uintptr_t)info.dli_fbase; obj->base_addr = (uintptr_t)info.dli_fbase;
path = info.dli_fname; path = info.dli_fname;
obj->path = path; obj->path = path;
if (path) lines[i].path = path; if (path) lines[i].path = path;
if (info.dli_sname) { if (info.dli_sname) {
lines[i].sname = info.dli_sname; lines[i].sname = info.dli_sname;
lines[i].saddr = (uintptr_t)info.dli_saddr; lines[i].saddr = (uintptr_t)info.dli_saddr;
} }
strlcpy(binary_filename, path, PATH_MAX); strlcpy(binary_filename, path, PATH_MAX);
if (fill_lines(num_traces, traces, 1, &obj, lines, i, errout) == (uintptr_t)-1) if (fill_lines(num_traces, traces, 1, &obj, lines, i, errout) == (uintptr_t)-1)
break; break;
} }
next_line: next_line:
continue; continue;
} }
/* output */ /* output */
for (i = 0; i < num_traces; i++) { for (i = 0; i < num_traces; i++) {
print_line(&lines[i], traces[i], errout); print_line(&lines[i], traces[i], errout);
/* FreeBSD's backtrace may show _start and so on */ /* FreeBSD's backtrace may show _start and so on */
if (lines[i].sname && strcmp("main", lines[i].sname) == 0) if (lines[i].sname && strcmp("main", lines[i].sname) == 0)
break; break;
} }
/* free */ /* free */
while (obj) { while (obj) {
obj_info_t *o = obj; obj_info_t *o = obj;
for (i=0; i < DWARF_SECTION_COUNT; i++) { for (i=0; i < DWARF_SECTION_COUNT; i++) {
struct dwarf_section *s = obj_dwarf_section_at(obj, i); struct dwarf_section *s = obj_dwarf_section_at(obj, i);
if (s->flags & SHF_COMPRESSED) { if (s->flags & SHF_COMPRESSED) {
free(s->ptr); free(s->ptr);
} }
} }
if (obj->mapped_size) { if (obj->mapped_size) {
munmap(obj->mapped, obj->mapped_size); munmap(obj->mapped, obj->mapped_size);
} }
obj = o->next; obj = o->next;
free(o); free(o);
} }
for (i = 0; i < num_traces; i++) { for (i = 0; i < num_traces; i++) {
line_info_t *line = lines[i].next; line_info_t *line = lines[i].next;