/* Generic harness for single-stepping one of the benchmark functions under GDB. * Copies the raw bytes of funcNN.bin into an RWX buffer and calls through * a function pointer. GDB stepi from the call site drops you right into the * target function's first instruction. No QEMU needed — boltzmann is aarch64. * * Build: run `make` in this dir (native aarch64 only, for now). * Run: ./gdb_debug.elf {1|2|3} (1=memset 2=memcpy32 3=magic_memset) * * Under GDB: see README.md. */ #include #include #include #include #include extern uint8_t _binary_func_01_bin_start[], _binary_func_01_bin_end[]; extern uint8_t _binary_func_02_bin_start[], _binary_func_02_bin_end[]; extern uint8_t _binary_func_03_bin_start[], _binary_func_03_bin_end[]; typedef void (*f1_t)(void *, uint8_t, uint64_t); typedef void (*f2_t)(uint32_t *, const uint32_t *, uint64_t); typedef void (*f3_t)(void); static void *rwx_copy(const void *src, size_t len) { void *p = mmap(NULL, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (p == MAP_FAILED) { perror("mmap"); exit(1); } memcpy(p, src, len); __builtin___clear_cache(p, (char *)p + len); return p; } static void __attribute__((noinline)) call_func(void (*fn)(void), int which) { switch (which) { case 1: { char buf[64] = {0}; printf("pre: buf[10]=0x%02x\n", (uint8_t)buf[10]); ((f1_t)fn)(buf, 0xAB, 16); printf("post: buf[10]=0x%02x (expect 0xab)\n", (uint8_t)buf[10]); break; } case 2: { uint32_t dst[8] = {0}, src[8]; for (int i = 0; i < 8; i++) src[i] = 0xDEAD0000U | i; ((f2_t)fn)(dst, src, sizeof dst); printf("dst[3]=0x%08x (expect 0xdead0003)\n", dst[3]); break; } case 3: printf("calling magic_memset — SIGSEGVs on LDR of 0x1fe004 in user mode.\n"); ((f3_t)fn)(); break; } } int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "usage: %s {1|2|3}\n", argv[0]); return 2; } int which = atoi(argv[1]); void (*fn)(void); switch (which) { case 1: fn = rwx_copy(_binary_func_01_bin_start, _binary_func_01_bin_end - _binary_func_01_bin_start); break; case 2: fn = rwx_copy(_binary_func_02_bin_start, _binary_func_02_bin_end - _binary_func_02_bin_start); break; case 3: fn = rwx_copy(_binary_func_03_bin_start, _binary_func_03_bin_end - _binary_func_03_bin_start); break; default: fprintf(stderr, "unknown index %d\n", which); return 2; } printf("function %d loaded at %p\n", which, fn); call_func(fn, which); return 0; }