summaryrefslogtreecommitdiffstats
path: root/src/stack_walk.c
diff options
context:
space:
mode:
authorQuentin LADEVIE <qladevie@wanadev.fr>2025-04-30 00:17:19 +0200
committerQuentin LADEVIE <qladevie@wanadev.fr>2025-04-30 00:17:19 +0200
commit0ad788465c7505bdadff64c2f3af3ad5edf71cc3 (patch)
tree96bbcf64de7bd2ee7c99ad9a133182ea62a1db0e /src/stack_walk.c
parentf8c92cfa9eeb82a608d409cac70d9d2533ab79d8 (diff)
Compiles files one by one
Diffstat (limited to 'src/stack_walk.c')
-rw-r--r--src/stack_walk.c298
1 files changed, 298 insertions, 0 deletions
diff --git a/src/stack_walk.c b/src/stack_walk.c
new file mode 100644
index 0000000..88a21db
--- /dev/null
+++ b/src/stack_walk.c
@@ -0,0 +1,298 @@
+#include "stack_walk.h"
+
+#include <Windows.h>
+
+#include "module.h"
+#include "utils.h"
+
+// enum UNWIND_INFO_FLAGS {
+// UNW_FLAG_EHANDLER,
+// UNW_FLAG_UHANDLER,
+// UNW_FLAG_CHAININFO,
+// };
+
+enum UNWIND_OP_TYPE {
+ UWOP_PUSH_NONVOL,
+ UWOP_ALLOC_LARGE,
+ UWOP_ALLOC_SMALL,
+ UWOP_SET_FPREG,
+ UWOP_SAVE_NONVOL,
+ UWOP_SAVE_NONVOL_FAR,
+ UWOP_SAVE_XMM128 = 8U,
+ UWOP_SAVE_XMM128_FAR,
+ UWOP_PUSH_MACHFRAME,
+};
+
+struct UNWIND_CODE {
+ u8 offset_in_prolog;
+ u8 unwind_operation_code : 4;
+ u8 op_info : 4;
+};
+
+struct UNWIND_INFO {
+ u8 version : 3;
+ u8 flags : 5;
+ u8 size_of_prolog;
+ u8 count_of_unwind_codes;
+ u8 frame_register : 4;
+ u8 frame_register_offset : 4;
+ struct UNWIND_CODE unwind_code[1U];
+ // Optional Exception handler of chained unwind info
+ //
+ // Exception handler
+ // ULONG address_of_exception_handler;
+ // language specific handler data;
+ //
+ // Chained unwind info
+ // ULONG function_start;
+ // ULONG function_end;
+ // ULONG unwind_info_address;
+};
+
+enum UNWIND_OP_INFO_TYPE {
+ RAX,
+ RCX,
+ RDX,
+ RBX,
+ RSP,
+ RBP,
+ RSI,
+ RDI,
+ R8,
+ R9,
+ R10,
+ R11,
+ R12,
+ R13,
+ R14,
+ R15,
+};
+
+struct module* get_addr_module(u64 addr) {
+ for (u8 index = 0U; index < 64U; index++) {
+ if (((1ULL << index) & modules_list) != 0U) {
+ continue;
+ }
+
+ struct module* module = &modules[index];
+ u64 offset = addr - (u64)module->base_addr;
+ if (0U <= offset && offset < module->nt_header.OptionalHeader.SizeOfImage) {
+ return module;
+ }
+ }
+
+ return NULL;
+}
+
+void print_reg(enum UNWIND_OP_INFO_TYPE op_info) {
+ switch (op_info) {
+ case RAX:
+ print("RAX\n");
+ break;
+ case RCX:
+ print("RCX\n");
+ break;
+ case RDX:
+ print("RDX\n");
+ break;
+ case RBX:
+ print("RBX\n");
+ break;
+ case RSP:
+ print("RSP\n");
+ break;
+ case RBP:
+ print("RBP\n");
+ break;
+ case RSI:
+ print("RSI\n");
+ break;
+ case RDI:
+ print("RDI\n");
+ break;
+ case R8:
+ print("R8\n");
+ break;
+ case R9:
+ print("R9\n");
+ break;
+ case R10:
+ print("R10\n");
+ break;
+ case R11:
+ print("R11\n");
+ break;
+ case R12:
+ print("R12\n");
+ break;
+ case R13:
+ print("R13\n");
+ break;
+ case R14:
+ print("R14\n");
+ break;
+ case R15:
+ print("R15\n");
+ break;
+ }
+}
+
+void walk_stack(void* ctx) {
+ u64 addr = ((CONTEXT*)ctx)->Rip;
+ u64 rsp = ((CONTEXT*)ctx)->Rsp;
+ u64 rbp = ((CONTEXT*)ctx)->Rbp;
+ struct module* module = NULL;
+ struct UNWIND_INFO* u_info = VirtualAlloc(NULL, 4096U, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+ while (addr) {
+ module = get_addr_module(addr);
+
+ if (module == NULL) {
+ print("Module not found!\n");
+ return;
+ }
+ // print("Module name %s\n", module->name);
+ // print("Module address %xu\n", (u64)module->base_addr);
+ // print("Module size %xu\n", module->nt_header.OptionalHeader.SizeOfImage);
+ // print("Module code address %xu\n", (u64)module->base_addr + module->nt_header.OptionalHeader.BaseOfCode);
+ // print("Module code size %xu\n", module->nt_header.OptionalHeader.SizeOfCode);
+ // print("Function address %xu\n", addr);
+ // print("Function offset in module %xu\n", addr - (u64)module->base_addr);
+
+#ifdef HASHMAP
+ struct element* sym = find_function(module, (u32)(addr - (u64)module->base_addr));
+ if (sym == NULL) {
+#else
+ u32 sym_index = find_function(module, addr - (u64)module->base_addr);
+ if (sym_index == (u32)-1) {
+#endif
+ print("No symbol found at address %xu\n", addr);
+
+ addr = *(u64*)rsp;
+ continue;
+ }
+#ifdef HASHMAP
+ void* name = (void*)sym->name;
+ u64 unwind_offset = sym->unwind_offset;
+ u32 start = sym->start;
+
+ u8 buffer[4096U];
+ read_memory(name, buffer, 4096U);
+ print("Buffer is %s!%s\n", module->name, buffer);
+#else
+ u8* name = module->functions_name[sym_index];
+ u64 unwind_offset = module->functions_unwind[sym_index];
+ u32 start = module->functions_start[sym_index];
+#endif
+ print("%s!%s\n", module->name, name);
+ // print("rsp value is %xu\n", rsp);
+ // print("rbp value is %xu\n", rbp);
+
+ if (!read_memory((const void*)((u64)module->base_addr + unwind_offset), (void*)u_info, 4096U)) {
+ print("Cannot read unwind info in for function %s\n", name);
+ continue;
+ }
+
+ size_t total_size = sizeof(*u_info) + (u_info->count_of_unwind_codes - 1U) * sizeof(struct UNWIND_CODE);
+ assert(total_size < 4096U);
+
+ // TODO: Do this once for the first function
+ if (start <= addr && addr < u_info->size_of_prolog) {
+ // print("RIP is in prolog\n");
+ } else if (1) {
+ // print("RIP is in epilog\n");
+ // u8* byte_code = (u8*)addr;
+ addr = (u64)module->base_addr + start + u_info->size_of_prolog;
+ } else {
+ // print("RIP is in body\n");
+ }
+
+ for (u32 code_index = 0U; code_index < u_info->count_of_unwind_codes;) {
+ struct UNWIND_CODE* cur_code = &u_info->unwind_code[code_index];
+ switch (cur_code->unwind_operation_code) {
+ case UWOP_PUSH_NONVOL:
+ // print("push non volatile\n");
+ // print("push ");
+ // print_reg(cur_code->op_info);
+ rsp += 8U;
+ code_index++;
+ break;
+ case UWOP_ALLOC_LARGE:
+ // print("alloc large\n");
+ if (cur_code->op_info == 0U) {
+ u16 size = *(u16*)&u_info->unwind_code[code_index + 1U];
+ if (u_info->frame_register) {
+ // print("sub rbp %xu\n", size);
+ rbp += size;
+ } else {
+ // print("sub rsp %xu\n", size);
+ rsp += size;
+ }
+ code_index += 2U;
+ } else {
+ u32 size = *(u32*)&u_info->unwind_code[code_index + 1U];
+ if (u_info->frame_register) {
+ // print("sub rbp %xu\n", size);
+ rbp += size;
+ } else {
+ // print("sub rsp %xu\n", size);
+ rsp += size;
+ }
+ code_index += 3U;
+ }
+ break;
+ case UWOP_ALLOC_SMALL:
+ // print("alloc small\n");
+ u32 size = cur_code->op_info * 8U + 8U;
+ if (u_info->frame_register) {
+ // print("sub rbp %xu\n", size);
+ rbp += size;
+ } else {
+ // print("sub rsp %xu\n", size);
+ rsp += size;
+ }
+ code_index++;
+ break;
+ case UWOP_SET_FPREG:
+ // print("set frame point reg\n");
+ // print("mov rbp rsp - %xu\n", u_info->frame_register_offset * 16U);
+ code_index++;
+ break;
+ case UWOP_SAVE_NONVOL:
+ // print("save non volatile\n");
+ if (u_info->frame_register) {
+ // print("mov rbp ");
+ } else {
+ // print("mov rsp ");
+ }
+ // print_reg(cur_code->op_info);
+ code_index += 2U;
+ break;
+ case UWOP_SAVE_NONVOL_FAR:
+ // print("save non volatile far\n");
+ code_index += 3U;
+ break;
+ case UWOP_SAVE_XMM128:
+ // print("save xmm128\n");
+ code_index += 2U;
+ break;
+ case UWOP_SAVE_XMM128_FAR:
+ // print("save xmm128 far\n");
+ code_index += 3U;
+ break;
+ case UWOP_PUSH_MACHFRAME:
+ // print("push mach frame\n");
+ code_index++;
+ break;
+ default:
+ // print("bad operation code\n");
+ code_index++;
+ }
+ }
+ u64 val;
+ read_memory((void*)rsp, &val, sizeof(u64));
+ rsp += 8U;
+ // print("called address is %xu\n", val);
+ addr = val;
+ }
+ VirtualFree(u_info, 4096U, MEM_RELEASE);
+}