Skip to content

Commit

Permalink
#29/#1: Add support for caller symbol resolution (closes #29)
Browse files Browse the repository at this point in the history
  • Loading branch information
Arinerron committed Oct 20, 2021
1 parent ad6b9c7 commit 0ce1641
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 31 deletions.
5 changes: 4 additions & 1 deletion inc/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,12 @@ typedef struct HeaptraceContext {
uint should_map_syms;

char *between_pre_and_post;
ProcELFType ret_ptr_section_type;

UBPWhen h_when;
ProcessState h_state;
uint64_t h_rip;
uint64_t h_ret_ptr;
ProcELFType h_ret_ptr_section_type;

size_t h_size;
uint64_t h_ptr;
Expand Down Expand Up @@ -84,6 +85,8 @@ typedef struct HeaptraceFile {
uint is_dynamic;
uint is_stripped;
SymbolEntry *se_head;
SymbolEntry *all_static_se_head; // all static symbols
ProcMapsEntry *pme;
} HeaptraceFile;

void *free_ctx(HeaptraceContext *ctx);
Expand Down
11 changes: 6 additions & 5 deletions inc/logging.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,18 @@ extern FILE *output_fd;
#define fatal(fmt, ...) { fprintf(output_fd, (COLOR_ERROR_BOLD "heaptrace error: " fmt COLOR_RESET), ##__VA_ARGS__); }
#define fatal2(f_, fmt, ...) { fprintf((f_), (COLOR_ERROR_BOLD "heaptrace error: " fmt COLOR_RESET), ##__VA_ARGS__); }

#define U64T "0x%" PRIx64

#define SYM COLOR_SYMBOL_BOLD "#" COLOR_SYMBOL "%lu" COLOR_LOG
#define SYM_IT COLOR_SYMBOL_ITALIC "#%lu" COLOR_LOG
#define SZ COLOR_LOG_BOLD "0x%02lx" COLOR_LOG
#define SZ_ERR COLOR_ERROR_BOLD "0x%02lx" COLOR_ERROR
#define SZ_ARG(sz) ((long unsigned int)(sz))
#define CNT COLOR_LOG_BOLD "%lu" COLOR_LOG
#define PTR COLOR_LOG_BOLD "0x%llx" COLOR_LOG
#define PTR_ERR COLOR_ERROR_BOLD "0x%llx" COLOR_ERROR
#define PTR_IT COLOR_LOG_ITALIC "0x%llx" COLOR_LOG
#define PTR_ARG(ptr) ((long long unsigned int)(ptr))
#define PTR COLOR_LOG_BOLD U64T COLOR_LOG
#define PTR_ERR COLOR_ERROR_BOLD U64T COLOR_ERROR
#define PTR_IT COLOR_LOG_ITALIC U64T COLOR_LOG
#define PTR_ARG(ptr) ((long unsigned int)(ptr))

#define log_heap(fmt, ...) { fprintf(output_fd, (COLOR_LOG fmt COLOR_RESET), ##__VA_ARGS__); }
#define verbose_heap(fmt, ...) { if (OPT_VERBOSE) { fprintf(output_fd, (COLOR_LOG "\t^-- " COLOR_LOG_ITALIC fmt COLOR_RESET "\n"), ##__VA_ARGS__); } }
Expand All @@ -62,4 +64,3 @@ extern FILE *output_fd;

void describe_symbol(void *ptr);

#define U64T "0x%" PRIx64
7 changes: 7 additions & 0 deletions inc/symbol.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
typedef struct SymbolEntry {
char *name;
uint64_t offset;
uint64_t size;
int section;
int type; // SE_TYPE_STATIC, SE_TYPE_DYNAMIC, SE_TYPE_DYNAMIC_PLT

Expand All @@ -39,4 +40,10 @@ int all_se_type(SymbolEntry *se_head, int type);
SymbolEntry *find_se_name(SymbolEntry *se_head, char *name);
void free_se_list(SymbolEntry *se_head);

SymbolEntry *find_symbol_by_address(HeaptraceFile *hf, uint64_t addr);
HeaptraceFile *find_heaptrace_file_by_address(HeaptraceContext *ctx, uint64_t addr);
char *find_symbol_name_by_address(HeaptraceContext *ctx, uint64_t addr);

char *get_source_function(HeaptraceContext *ctx);

#endif
4 changes: 3 additions & 1 deletion src/context.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ HeaptraceFile *alloc_file(HeaptraceContext *ctx) {

HeaptraceContext *alloc_ctx() {
HeaptraceContext *ctx = (HeaptraceContext *)calloc(1, sizeof(HeaptraceContext));
ctx->ret_ptr_section_type = PROCELF_TYPE_UNKNOWN;
ctx->h_ret_ptr_section_type = PROCELF_TYPE_UNKNOWN;
ctx->target = alloc_file(ctx);
ctx->libc = alloc_file(ctx);
return ctx;
Expand All @@ -28,7 +28,9 @@ void *free_ctx(HeaptraceContext *ctx) {
free(ctx->se_names);

free_se_list(ctx->target->se_head);
free_se_list(ctx->target->all_static_se_head);
free_se_list(ctx->libc->se_head);
free_se_list(ctx->libc->all_static_se_head);
free(ctx->target);
free(ctx->libc);

Expand Down
5 changes: 4 additions & 1 deletion src/debugger.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ void _check_breakpoints(HeaptraceContext *ctx) {
if (OPT_VERBOSE) {
ProcMapsEntry *pme = pme_find_addr(ctx->pme_head, val_at_reg_rsp);
if (pme) {
ctx->ret_ptr_section_type = pme->pet;
ctx->h_ret_ptr_section_type = pme->pet;
ctx->h_ret_ptr = val_at_reg_rsp;
}
}

Expand Down Expand Up @@ -410,6 +411,8 @@ uint map_syms(HeaptraceContext *ctx) {
if (!ctx->pme_head) ctx->pme_head = build_pme_list(ctx->pid); // already built if attaching
ProcMapsEntry *bin_pme = pme_walk(ctx->pme_head, PROCELF_TYPE_BINARY);
ProcMapsEntry *libc_pme = pme_walk(ctx->pme_head, PROCELF_TYPE_LIBC);
ctx->target->pme = bin_pme;
ctx->libc->pme = libc_pme;

// quick debug info about addresses/paths we found
ASSERT(bin_pme, "failed to find target binary in process mapping (!bin_pme). Please report this!");
Expand Down
25 changes: 5 additions & 20 deletions src/handlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,8 @@
#include "options.h"
#include "user-breakpoint.h"

static inline char *_get_source_section(HeaptraceContext *ctx) {
if (OPT_VERBOSE) {
switch (ctx->ret_ptr_section_type) {
case PROCELF_TYPE_LIBC:
return "caller: libc";
break;
case PROCELF_TYPE_UNKNOWN:
return "caller: a library";
break;
case PROCELF_TYPE_BINARY:
return "caller: binary";
break;
}
}

return "caller: (unknown)";
}
#define PRINT_SOURCE() { if (OPT_VERBOSE) { char *SRC_FUNC = get_source_function(ctx); verbose_heap("called by: " COLOR_LOG_BOLD "%s" COLOR_LOG "; returns to " PTR, SRC_FUNC, ctx->h_ret_ptr); free(SRC_FUNC); } }


// check if pointer is in stack, libc, or binary, and error if so
Expand Down Expand Up @@ -54,7 +39,7 @@ void pre_calloc(HeaptraceContext *ctx, uint64_t nmemb, uint64_t isize) {

void post_calloc(HeaptraceContext *ctx, uint64_t ptr) {
log_heap("= " PTR "\n", PTR_ARG(ptr));
verbose_heap("%s", _get_source_section(ctx));
PRINT_SOURCE()

// store meta info
Chunk *chunk = alloc_chunk(ctx, ptr);
Expand Down Expand Up @@ -101,7 +86,7 @@ void pre_malloc(HeaptraceContext *ctx, uint64_t isize) {

void post_malloc(HeaptraceContext *ctx, uint64_t ptr) {
log_heap("= " PTR "\n", PTR_ARG(ptr));
verbose_heap("%s", _get_source_section(ctx));
PRINT_SOURCE()

// store meta info
Chunk *chunk = alloc_chunk(ctx, ptr);
Expand Down Expand Up @@ -179,7 +164,7 @@ void pre_free(HeaptraceContext *ctx, uint64_t iptr) {
void post_free(HeaptraceContext *ctx, uint64_t retval) {
ctx->between_pre_and_post = 0;
log(COLOR_RESET);
verbose_heap("%s", _get_source_section(ctx));
PRINT_SOURCE()
}


Expand Down Expand Up @@ -246,7 +231,7 @@ static inline void _post_realloc(HeaptraceContext *ctx, int _type, uint64_t new_
log("\t%s(" SYM_IT "=" PTR_IT ")", COLOR_LOG_ITALIC, ctx->h_orig_chunk->ops[STATE_MALLOC], PTR_ARG(ctx->h_ptr));
}
log_heap("\n");
verbose_heap("%s", _get_source_section(ctx));
PRINT_SOURCE()
//warn("this code is untested; please report any issues you come across @ https://github.com/Arinerron/heaptrace/issues/new/choose");

Chunk *new_chunk = alloc_chunk(ctx, new_ptr);
Expand Down
99 changes: 96 additions & 3 deletions src/symbol.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ void lookup_symbols(HeaptraceFile *hf, char *names[]) {
}

// resolve static symbols
SymbolEntry *all_static_se_head = 0;
if (strtab_off && symtab_off) {
for (size_t j = 0; j * sizeof(Elf64_Sym) < symtab_sz; j++) {
Elf64_Sym sym;
Expand All @@ -271,30 +272,87 @@ void lookup_symbols(HeaptraceFile *hf, char *names[]) {
_CHECK_BOUNDS(name, "static: name");
size_t n = strlen(name);

uint64_t offset = (uint64_t)(sym.st_value);
// XXX: for some reason libc has a load addr of 0x40 that's throwing stuff off. This is a stopgap solution for that.
if (!is_dynamic) offset -= load_addr;

SymbolEntry *cse = se_head;
while (1) {
if (!cse) break;
if (((!cse->offset && sym.st_value) || cse->type == SE_TYPE_UNRESOLVED) && strcmp(cse->name, name) == 0) {
debug("tab: st_name: %s @ " U64T "\n", name, (uint64_t)sym.st_value);
cse->type = SE_TYPE_STATIC;
//cse->offset = (uint64_t)(sym.st_value);
cse->offset = (uint64_t)(sym.st_value) - load_addr;
cse->_sub_offset = load_addr; // XXX: for some reason libc has a load addr of 0x40 that's throwing stuff off. This is a stopgap solution for that.
cse->offset = offset;
cse->_sub_offset = 0;
cse->size = sym.st_size;
cse->section = sym.st_shndx;
if (sym.st_value) is_stripped = 0;
}
cse = cse->_next;
}

// now add to all_static_se_head
SymbolEntry *_cur_static_se = (SymbolEntry *)calloc(1, sizeof(SymbolEntry));
_cur_static_se->_next = all_static_se_head;
all_static_se_head = _cur_static_se;

_cur_static_se->name = strdup(name);
_cur_static_se->offset = offset;
_cur_static_se->size = sym.st_size;
_cur_static_se->_sub_offset = 0;
_cur_static_se->type = SE_TYPE_STATIC;
_cur_static_se->section = sym.st_shndx;

//printf("%s\toffset=%p, size=%p\n", _cur_static_se->name, _cur_static_se->offset, _cur_static_se->size);
}
}
}

hf->all_static_se_head = all_static_se_head;
hf->se_head = se_head;
hf->is_stripped = is_stripped;
hf->is_dynamic = is_dynamic;
}


SymbolEntry *find_symbol_by_address(HeaptraceFile *hf, uint64_t addr) {
if (!(hf->pme) || addr < hf->pme->base || addr >= hf->pme->end) return 0; // not in bounds
addr -= hf->pme->base;

SymbolEntry *cur_se = hf->all_static_se_head;
while(cur_se) {
//printf("... %s\taddr=%p, offset=%p, offset+size=%p\n", cur_se->name, addr, cur_se->offset, cur_se->offset + cur_se->size);
if (addr >= cur_se->offset && addr < cur_se->offset + cur_se->size) return cur_se;
cur_se = cur_se->_next;
}

return 0;
}


HeaptraceFile *find_heaptrace_file_by_address(HeaptraceContext *ctx, uint64_t addr) {
HeaptraceFile *hfs[] = {ctx->target, ctx->libc};
HeaptraceFile *cur_hf;
for (int i = 0; i < sizeof(hfs) / sizeof(hfs[0]); i++) {
cur_hf = hfs[i];
if (cur_hf->pme && addr >= cur_hf->pme->base && addr < cur_hf->pme->end) {
return cur_hf;
}
}
return 0;
}


char *find_symbol_name_by_address(HeaptraceContext *ctx, uint64_t addr) {
HeaptraceFile *hf = find_heaptrace_file_by_address(ctx, addr);
if (!hf) return 0;
SymbolEntry *se = find_symbol_by_address(hf, addr);
if (!se) return 0;
return se->name;
}



SymbolEntry *any_se_type(SymbolEntry *se_head, int type) {
SymbolEntry *cse = se_head;
while (cse) {
Expand Down Expand Up @@ -341,3 +399,38 @@ void free_se_list(SymbolEntry *se_head) {
cse = next_cse;
}
}


char *get_source_function(HeaptraceContext *ctx) {
char *section = "<unknown>";
if (OPT_VERBOSE) {
switch (ctx->h_ret_ptr_section_type) {
case PROCELF_TYPE_LIBC:
section = "libc";
break;
case PROCELF_TYPE_UNKNOWN:
section = "<library>";
break;
case PROCELF_TYPE_BINARY:
section = 0;
break;
}
}

char *symbol_name = find_symbol_name_by_address(ctx, ctx->h_ret_ptr);
size_t buf_size = 2;
if (symbol_name) buf_size += strlen(symbol_name);
if (section) buf_size += 1 + strlen(section);

char *buf = calloc(1, buf_size);
if (symbol_name) strcat(buf, symbol_name);
if (symbol_name && section) strcat(buf, "@");
if (section) strcat(buf, section);

if (!strlen(buf)) {
free(buf);
buf = strdup("binary"); // this is the only way `section` can be NULL
}

return buf;
}

0 comments on commit 0ce1641

Please # to comment.