Debugger: Support FUNC debug information

It is used to print function names in backtrace.
This commit is contained in:
kichikuou
2021-07-24 17:27:10 +09:00
parent 5283a0aa5d
commit 21e43b5cc7
3 changed files with 61 additions and 6 deletions
+49
View File
@@ -41,12 +41,21 @@ typedef struct {
Mapping *mappings;
} SrcInfo;
typedef struct {
char *name;
int page;
int addr;
boolean is_local;
} FuncInfo;
struct debug_symbols {
int version;
int nr_srcs;
SrcInfo *srcs;
int nr_vars;
char **variables;
int nr_funcs;
FuncInfo *functions;
};
const char *fget4cc(FILE *fp) {
@@ -161,6 +170,21 @@ static boolean load_vari(struct debug_symbols *dsym, char *buf) {
return true;
}
static boolean load_func(struct debug_symbols *dsym, char *buf) {
dsym->nr_funcs = LittleEndian_getDW(buf, 0);
dsym->functions = calloc(dsym->nr_funcs, sizeof(FuncInfo));
char *p = buf + 4;
for (int i = 0; i < dsym->nr_funcs; i++) {
dsym->functions[i].name = p;
p += strlen(p) + 1;
dsym->functions[i].page = LittleEndian_getW(p, 0);
dsym->functions[i].addr = LittleEndian_getDW(p, 2);
dsym->functions[i].is_local = p[6];
p += 7;
}
return true;
}
struct debug_symbols *dsym_load(const char *path) {
FILE *fp = fopen(path, "rb");
if (!fp) {
@@ -206,6 +230,8 @@ struct debug_symbols *dsym_load(const char *path) {
ok = load_line(dsym, section_content);
} else if (!strcmp(tag, "VARI")) {
ok = load_vari(dsym, section_content);
} else if (!strcmp(tag, "FUNC")) {
ok = load_func(dsym, section_content);
} else {
WARNING("%s: unrecognized section %s\n", path, tag);
}
@@ -304,3 +330,26 @@ int dsym_lookup_variable(struct debug_symbols *dsym, const char *name) {
}
return -1;
}
const char *dsym_addr2func(struct debug_symbols *dsym, int page, int addr) {
if (!dsym)
return NULL;
// Binary search.
int left = 0, right = dsym->nr_funcs;
while (left < right) {
int mid = (left + right) / 2;
FuncInfo *f = &dsym->functions[mid];
if (f->page < page || (f->page == page && f->addr <= addr))
left = mid + 1;
else
right = mid;
}
if (left == 0)
return NULL;
FuncInfo *f = &dsym->functions[left - 1];
if (f->page != page)
return NULL;
assert(f->addr <= addr);
return f->name;
}
+1
View File
@@ -31,5 +31,6 @@ int dsym_line2addr(struct debug_symbols *dsym, int page, int line);
int dsym_addr2line(struct debug_symbols *dsym, int page, int addr);
const char *dsym_source_line(struct debug_symbols *dsym, int page, int line);
int dsym_lookup_variable(struct debug_symbols *dsym, const char *name);
const char *dsym_addr2func(struct debug_symbols *dsym, int page, int addr);
#endif // __DEBUG_SYMBOL_H__
+11 -6
View File
@@ -53,17 +53,22 @@ static Breakpoint *internal_breakpoint;
static const char whitespaces[] = " \t\r\n";
static const char *format_address(int page, int addr, boolean is_return_addr) {
static char buf[120];
static char buf[100];
const char *src = dsym_page2src(symbols, page);
// For return addresses, search with (addr - 1) so that the function call's
// line number will be printed.
int line = dsym_addr2line(symbols, page, is_return_addr ? addr - 1 : addr);
const char *func = dsym_addr2func(symbols, page, is_return_addr ? addr - 1 : addr);
if (src && line > 0)
sprintf(buf, "%.100s:%d", src, line); // TODO: print function name
else
sprintf(buf, "%d:0x%x", page, addr);
if (src && line > 0) {
if (func)
snprintf(buf, sizeof(buf), "%s:%d in %s", src, line, func);
else
snprintf(buf, sizeof(buf), "%s:%d", src, line);
} else {
snprintf(buf, sizeof(buf), "%d:0x%x", page, addr);
}
return buf;
}
@@ -364,7 +369,7 @@ void dbg_repl(void) {
}
char buf[256];
while (printf("dbg> "), fgets(buf, sizeof(buf), stdin)) {
while (printf("dbg> "), fflush(stdout), fgets(buf, sizeof(buf), stdin)) {
char *cmd = strtok(buf, whitespaces);
if (!cmd) {
// TODO: repeat last command