Skip to content

Commit 3ae414b

Browse files
committed
runtime: Generate stack trace for compartment violations in permissive mode
1 parent 38765b1 commit 3ae414b

File tree

1 file changed

+39
-1
lines changed

1 file changed

+39
-1
lines changed

runtime/libia2/include/permissive_mode.h

+39-1
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ int pkru_offset(void) {
9494
* logging thread pops but there's not much benefit to this for debugging.
9595
*/
9696
#define QUEUE_SIZE 8192
97+
#define MAX_STACKTRACE 10
9798

9899
// The entries in the queue
99100
typedef struct mpk_err {
@@ -103,6 +104,7 @@ typedef struct mpk_err {
103104
uint64_t sp;
104105
uint64_t fp;
105106
uint32_t pkru;
107+
uint64_t ret_addrs[MAX_STACKTRACE];
106108
} mpk_err;
107109

108110
struct queue {
@@ -196,7 +198,24 @@ void permissive_mode_handler(int sig, siginfo_t *info, void *ctxt) {
196198
struct queue *q = get_queue();
197199
uint64_t val;
198200
memcpy(&val, info->si_addr, sizeof(uint64_t));
199-
mpk_err err = {.addr = (uint64_t)info->si_addr, .val = val, .pc = pc, .sp = sp, .fp = fp, .pkru = old_pkru};
201+
mpk_err err = {
202+
.addr = (uint64_t)info->si_addr,
203+
.val = val,
204+
.pc = pc,
205+
.sp = sp,
206+
.fp = fp,
207+
.pkru = old_pkru
208+
};
209+
for (int i = 0; i < MAX_STACKTRACE; i++) {
210+
// I thought the stopping condition was fp == 0 but it seems to be 1 so
211+
// just stop at any obviously bad address
212+
if (fp < PAGE_SIZE) {
213+
break;
214+
}
215+
uint64_t ra = *(uint64_t *)(fp + 8);
216+
err.ret_addrs[i] = ra;
217+
fp = *(uint64_t *)fp;
218+
}
200219
push_queue(q, err);
201220
release_queue(q);
202221
} else if (handling_trap) {
@@ -368,6 +387,25 @@ void flush_queue(FILE *log) {
368387
print_address(log, "sp", (void *)err.sp);
369388
print_address(log, "fp", (void *)err.fp);
370389
fprintf(log, "pkru: %x\n", err.pkru);
390+
391+
Dl_info dlinf = { 0 };
392+
const char *fn_name = "??";
393+
if (dladdr((void *)err.pc, &dlinf) != 0) {
394+
fn_name = dlinf.dli_sname;
395+
}
396+
fprintf(log, "#0 %p in %s ()\n", (void *)err.pc, fn_name);
397+
for (int i = 0; i < MAX_STACKTRACE; i++) {
398+
void *ra = (void *)err.ret_addrs[i];
399+
if (ra == NULL) {
400+
break;
401+
}
402+
if (dladdr(ra, &dlinf) != 0) {
403+
fn_name = dlinf.dli_sname;
404+
} else {
405+
fn_name = "??";
406+
}
407+
fprintf(log, "#%d %p in %s ()\n", i + 1, ra, fn_name);
408+
}
371409
}
372410
release_queue(q);
373411
}

0 commit comments

Comments
 (0)