#include #include #define _POSIX_C_SOURCE 200809L #include #include #include #include #include #include #include #include #include #include struct segment { size_t start, end; const char *description; }; #define LINE_LEN 0x10 /* Number of bytes in a line */ #define LINENO_DIGITS 8 /* length of line numbers */ #define LINENO_WIDTH (LINENO_DIGITS + 2) /* for padding */ #define INFO_HEIGHT 10 /* Height of the info panel */ // int screen_height, screen_width; struct screen { WINDOW *lineno, *hex, *chr, *info; int top_address; void *mem; size_t mem_len; int hx, hy; } screen = { .hx = -1, .hy = -1, }; void draw_lines() { for (int y = 0; y < LINES; y++) { mvwprintw(screen.lineno, y, 0, "%08x:", screen.top_address + y * LINE_LEN); wrefresh(screen.lineno); } } void draw_hex(struct segment *current) { for (int y = 0; y < LINES; y++) { for (int x = 0; x < LINE_LEN; x++) { size_t addr = screen.top_address + y * LINE_LEN + x; if (addr < 0 || addr >= screen.mem_len) continue; if (current->start <= addr && addr < current->end) { wattron(screen.hex, COLOR_PAIR(1)); } if (screen.hy == y && screen.hx == x) { wattron(screen.hex, A_REVERSE); } mvwprintw(screen.hex, y, x * 2 + (x/2), "%02x", 0xFF & ((char*) screen.mem)[addr]); if (screen.hy == y && screen.hx == x) { wattroff(screen.hex, A_REVERSE); } if (current->start <= addr && addr < current->end) { wattroff(screen.hex, COLOR_PAIR(1)); } } wrefresh(screen.hex); } } void draw_chr(struct segment *current) { for (int y = 0; y < LINES; y++) { for (int x = 0; x < LINE_LEN; x++) { size_t addr = screen.top_address + y * LINE_LEN + x; if (addr < 0 || addr >= screen.mem_len) continue; if (current->start <= addr && addr < current->end) { wattron(screen.chr, COLOR_PAIR(1)); } if (screen.hy == y && screen.hx == x) { wattron(screen.chr, A_REVERSE); } char c = ((char*) screen.mem)[addr]; mvwprintw(screen.chr, y, x, "%c", isprint(c) ? c : '.'); if (screen.hy == y && screen.hx == x) { wattroff(screen.chr, A_REVERSE); } if (current->start <= addr && addr < current->end) { wattroff(screen.chr, COLOR_PAIR(1)); } } wrefresh(screen.chr); } } void draw_info(struct segment *current) { werase(screen.info); wmove(screen.info, 0, 0); whline(screen.info, '-', COLS); // size_t mem_addr = screen.top_address + screen.hy * LINE_LEN + screen.hx; mvwprintw(screen.info, 1, 0, "%s", current->description); wrefresh(screen.info); } void draw_screen(sexp ctx, sexp bv) { sexp_gc_var3(proc_name, addr, ret); sexp_gc_preserve3(ctx, proc_name, addr, ret); proc_name = sexp_intern(ctx, "get-segment", -1); size_t c_addr = screen.top_address + screen.hy * LINE_LEN + screen.hx; addr = sexp_make_fixnum(c_addr); struct segment current; if (c_addr < 0 || c_addr >= screen.mem_len) { current = (struct segment) { .start = -1, .end = -1, .description = "No Segment", }; } else { ret = sexp_eval(ctx, sexp_list3(ctx, proc_name, bv, addr), NULL); if (! sexp_vectorp(ret)) { endwin(); fprintf(stderr, "get-segment[%lu] failed\n", c_addr); sexp_debug(ctx, "addr = ", addr); if (sexp_exceptionp(ret)) { printf("An exception was thrown\n"); sexp_print_exception(ctx, ret, sexp_current_output_port(ctx)); } else { sexp_debug(ctx, "Unexpecetd return value: ", ret); } exit(1); } current = (struct segment) { .start = sexp_unbox_fixnum(sexp_vector_ref(ret, SEXP_ZERO)), .end = sexp_unbox_fixnum(sexp_vector_ref(ret, SEXP_ONE)), .description = sexp_string_data(sexp_vector_ref(ret, SEXP_TWO)) }; } draw_lines(); draw_hex(¤t); draw_chr(¤t); draw_info(¤t); /* TODO end at end of file */ sexp_gc_release3(ctx); } int main(int argc, char *argv[]) { char *errmsg = NULL; int errcode = 0; /* Terminal supporting mouse movements */ setenv("TERM", "xterm-1003", true); sexp_scheme_init(); sexp ctx = sexp_make_eval_context(NULL, NULL, NULL, 0, 0); sexp_load_standard_env(ctx, NULL, SEXP_SEVEN); sexp_load_standard_ports(ctx, NULL, NULL, stdout, stderr, 1); sexp_gc_var2(obj1, bv); sexp_gc_preserve2(ctx, obj1, bv); obj1 = sexp_c_string(ctx, "gz.scm", -1); sexp_load(ctx, obj1, NULL); // sexp_eval_string(ctx, "(display \"Hello, from Scheme!\n\")", -1, NULL); initscr(); clear(); noecho(); cbreak(); curs_set(0); start_color(); init_pair(1, COLOR_RED, COLOR_BLACK); keypad(stdscr, true); const int HEX_WIDTH = (int) ceil(LINE_LEN * 2.5); { int h = LINES - INFO_HEIGHT; screen.lineno = newwin(h, LINENO_WIDTH, 0, 0); screen.hex = newwin(h, HEX_WIDTH, 0, LINENO_WIDTH); screen.chr = newwin(h, LINE_LEN, 0, LINENO_WIDTH + HEX_WIDTH); screen.info = newwin(0, 0, h, 0); } char *filename; if (argc == 1) { filename = "payload.gz"; } else { filename = argv[1]; } int fd = open(filename, O_RDONLY); if (fd == -1) { errmsg = "Failed to open file"; errcode = errno; goto end; } struct stat statbuf; if (fstat(fd, &statbuf) == -1) { errmsg = "Failed to stat file"; errcode = errno; goto end; } uint8_t *mem = mmap(NULL, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0); close(fd); screen.mem_len = statbuf.st_size; screen.mem = mem; bv = sexp_make_bytes(ctx, sexp_make_fixnum(statbuf.st_size), SEXP_ZERO); for (int i = 0; i < statbuf.st_size; i++) { sexp_bytes_set(bv, sexp_make_fixnum(i), sexp_make_fixnum(mem[i])); } mousemask(ALL_MOUSE_EVENTS|REPORT_MOUSE_POSITION, NULL); refresh(); draw_screen(ctx, bv); int ch; MEVENT event; while (true) { ch = wgetch(stdscr); switch (ch) { case KEY_MOUSE: // wmove(stdscr, 0, 0); switch (getmouse(&event)) { case OK: if (event.bstate & BUTTON4_PRESSED) { screen.top_address -= LINE_LEN; } if (event.bstate & BUTTON5_PRESSED) { screen.top_address += LINE_LEN; } if (event.y >= 0 && event.y < LINES - INFO_HEIGHT) { if (event.x >= LINENO_WIDTH && event.x < LINENO_WIDTH + HEX_WIDTH) { screen.hx = (int) ((event.x - LINENO_WIDTH) / 2.5); screen.hy = event.y; } else if (event.x >= LINENO_WIDTH + HEX_WIDTH && event.x < HEX_WIDTH + LINENO_WIDTH + LINE_LEN) { screen.hx = event.x - (LINENO_WIDTH + HEX_WIDTH); screen.hy = event.y; } else { screen.hx = -1; screen.hy = -1; } } else { screen.hx = -1; screen.hy = -1; } draw_screen(ctx, bv); break; case ERR: // wprintw(win, "err"); break; } draw_screen(ctx, bv); refresh(); break; case KEY_RESIZE: wresize(screen.lineno, LINES - INFO_HEIGHT, 0); wresize(screen.hex, LINES - INFO_HEIGHT, 0); wresize(screen.chr, LINES - INFO_HEIGHT, 0); draw_screen(ctx, bv); // mvprintw(0, 0, "%ix%i", COLS, LINES); // refresh(); break; case 'j': screen.top_address += LINE_LEN; draw_screen(ctx, bv); refresh(); break; case 'k': screen.top_address -= LINE_LEN; draw_screen(ctx, bv); refresh(); break; case '/': { echo(); nocbreak(); char *s = malloc(100); mvprintw(LINES - 1, 0, "/"); refresh(); getnstr(s, 99); cbreak(); noecho(); char *ptr = memmem((char*)screen.mem, screen.mem_len, s, strlen(s)); if (ptr != NULL) { size_t target = ptr - (char*) screen.mem; screen.top_address = LINE_LEN * (target / LINE_LEN); } draw_screen(ctx, bv); refresh(); } break; case KEY_ENTER: goto end; } } end: munmap(screen.mem, 0); delwin(screen.lineno); delwin(screen.hex); delwin(screen.chr); delwin(screen.info); endwin(); if (errcode) { printf("%s: %s\n", errmsg, strerror(errcode)); } return 0; }