2020-08-25 11:23:25 +00:00
|
|
|
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
|
|
|
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
|
|
|
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
|
|
|
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
|
|
|
|
│ │
|
|
|
|
|
│ This program is free software; you can redistribute it and/or modify │
|
|
|
|
|
│ it under the terms of the GNU General Public License as published by │
|
|
|
|
|
│ the Free Software Foundation; version 2 of the License. │
|
|
|
|
|
│ │
|
|
|
|
|
│ This program is distributed in the hope that it will be useful, but │
|
|
|
|
|
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
|
|
|
|
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
|
|
|
|
│ General Public License for more details. │
|
|
|
|
|
│ │
|
|
|
|
|
│ You should have received a copy of the GNU General Public License │
|
|
|
|
|
│ along with this program; if not, write to the Free Software │
|
|
|
|
|
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
|
|
|
|
│ 02110-1301 USA │
|
|
|
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
|
|
|
|
#include "dsp/tty/tty.h"
|
|
|
|
|
#include "libc/alg/arraylist2.h"
|
|
|
|
|
#include "libc/bits/safemacros.h"
|
|
|
|
|
#include "libc/calls/calls.h"
|
2020-08-27 06:08:08 +00:00
|
|
|
|
#include "libc/calls/ioctl.h"
|
2020-08-25 11:23:25 +00:00
|
|
|
|
#include "libc/calls/struct/sigaction.h"
|
|
|
|
|
#include "libc/calls/struct/stat.h"
|
|
|
|
|
#include "libc/calls/struct/termios.h"
|
|
|
|
|
#include "libc/calls/struct/winsize.h"
|
|
|
|
|
#include "libc/calls/termios.h"
|
|
|
|
|
#include "libc/conv/conv.h"
|
|
|
|
|
#include "libc/conv/itoa.h"
|
|
|
|
|
#include "libc/errno.h"
|
|
|
|
|
#include "libc/fmt/bing.h"
|
|
|
|
|
#include "libc/fmt/fmt.h"
|
|
|
|
|
#include "libc/log/check.h"
|
|
|
|
|
#include "libc/log/log.h"
|
|
|
|
|
#include "libc/macros.h"
|
|
|
|
|
#include "libc/math.h"
|
|
|
|
|
#include "libc/mem/mem.h"
|
|
|
|
|
#include "libc/runtime/gc.h"
|
|
|
|
|
#include "libc/runtime/runtime.h"
|
|
|
|
|
#include "libc/sock/sock.h"
|
|
|
|
|
#include "libc/stdio/stdio.h"
|
|
|
|
|
#include "libc/str/str.h"
|
|
|
|
|
#include "libc/str/tpdecode.h"
|
|
|
|
|
#include "libc/str/tpencode.h"
|
|
|
|
|
#include "libc/sysv/consts/auxv.h"
|
|
|
|
|
#include "libc/sysv/consts/ex.h"
|
|
|
|
|
#include "libc/sysv/consts/exit.h"
|
|
|
|
|
#include "libc/sysv/consts/fileno.h"
|
|
|
|
|
#include "libc/sysv/consts/map.h"
|
|
|
|
|
#include "libc/sysv/consts/o.h"
|
|
|
|
|
#include "libc/sysv/consts/poll.h"
|
|
|
|
|
#include "libc/sysv/consts/prot.h"
|
2020-08-27 06:08:08 +00:00
|
|
|
|
#include "libc/sysv/consts/sa.h"
|
2020-08-25 11:23:25 +00:00
|
|
|
|
#include "libc/sysv/consts/sig.h"
|
|
|
|
|
#include "libc/sysv/consts/termios.h"
|
|
|
|
|
#include "libc/unicode/unicode.h"
|
|
|
|
|
#include "libc/x/x.h"
|
|
|
|
|
#include "third_party/dtoa/dtoa.h"
|
|
|
|
|
#include "third_party/getopt/getopt.h"
|
|
|
|
|
#include "tool/build/lib/breakpoint.h"
|
|
|
|
|
#include "tool/build/lib/case.h"
|
|
|
|
|
#include "tool/build/lib/dis.h"
|
|
|
|
|
#include "tool/build/lib/endian.h"
|
2020-08-27 06:08:08 +00:00
|
|
|
|
#include "tool/build/lib/fds.h"
|
2020-08-25 11:23:25 +00:00
|
|
|
|
#include "tool/build/lib/flags.h"
|
|
|
|
|
#include "tool/build/lib/fpu.h"
|
|
|
|
|
#include "tool/build/lib/loader.h"
|
|
|
|
|
#include "tool/build/lib/machine.h"
|
|
|
|
|
#include "tool/build/lib/memory.h"
|
|
|
|
|
#include "tool/build/lib/modrm.h"
|
|
|
|
|
#include "tool/build/lib/panel.h"
|
|
|
|
|
#include "tool/build/lib/pml4t.h"
|
2020-08-27 06:08:08 +00:00
|
|
|
|
#include "tool/build/lib/pty.h"
|
2020-08-25 11:23:25 +00:00
|
|
|
|
#include "tool/build/lib/stats.h"
|
|
|
|
|
#include "tool/build/lib/throw.h"
|
|
|
|
|
|
|
|
|
|
STATIC_YOINK("die");
|
|
|
|
|
|
|
|
|
|
#define USAGE \
|
|
|
|
|
" [-?Hhrstv] [ROM] [ARGS...]\n\
|
|
|
|
|
\n\
|
|
|
|
|
DESCRIPTION\n\
|
|
|
|
|
\n\
|
|
|
|
|
NexGen32e Userspace Emulator w/ Debugger\n\
|
|
|
|
|
\n\
|
|
|
|
|
FLAGS\n\
|
|
|
|
|
\n\
|
|
|
|
|
-h\n\
|
|
|
|
|
-? help\n\
|
|
|
|
|
-v verbosity\n\
|
|
|
|
|
-s statistics\n\
|
|
|
|
|
-H disable highlight\n\
|
|
|
|
|
-t tui debugger mode\n\
|
|
|
|
|
-r reactive tui mode\n\
|
|
|
|
|
-b ADDR push a breakpoint\n\
|
|
|
|
|
-L PATH log file location\n\
|
|
|
|
|
\n\
|
|
|
|
|
ARGUMENTS\n\
|
|
|
|
|
\n\
|
|
|
|
|
ROM files can be ELF or a flat αcτµαlly pδrταblε εxεcµταblε.\n\
|
|
|
|
|
It should use x86_64 in accordance with the System Five ABI.\n\
|
|
|
|
|
The SYSCALL ABI is defined as it is written in Linux Kernel.\n\
|
|
|
|
|
\n\
|
|
|
|
|
PERFORMANCE\n\
|
|
|
|
|
\n\
|
2020-08-31 12:17:31 +00:00
|
|
|
|
1000 MIPS w/ NOP loop\n\
|
2020-08-25 11:23:25 +00:00
|
|
|
|
Over 9000 MIPS w/ SIMD & Algorithms\n\
|
2020-08-27 06:08:08 +00:00
|
|
|
|
\n\
|
2020-08-31 12:17:31 +00:00
|
|
|
|
COMPLETENESS\n\
|
2020-08-27 06:08:08 +00:00
|
|
|
|
\n\
|
2020-08-31 12:17:31 +00:00
|
|
|
|
Long user mode is supported in addition to SSE3 and SSSE3.\n\
|
|
|
|
|
Integer ops are implemented rigorously with lots of tests.\n\
|
|
|
|
|
Floating point instructions are yolo, and tunable more so.\n\
|
|
|
|
|
Loading, virtual memory management, and syscall need work.\n\
|
2020-08-25 11:23:25 +00:00
|
|
|
|
\n"
|
|
|
|
|
|
|
|
|
|
#define DUMPWIDTH 64
|
|
|
|
|
|
|
|
|
|
#define RESTART 0x001
|
|
|
|
|
#define REDRAW 0x002
|
|
|
|
|
#define CONTINUE 0x004
|
|
|
|
|
#define STEP 0x008
|
|
|
|
|
#define NEXT 0x010
|
|
|
|
|
#define FINISH 0x020
|
|
|
|
|
#define FAILURE 0x040
|
|
|
|
|
#define WINCHED 0x080
|
2020-08-27 06:08:08 +00:00
|
|
|
|
#define INT 0x100
|
2020-08-25 11:23:25 +00:00
|
|
|
|
#define QUIT 0x200
|
2020-08-27 06:08:08 +00:00
|
|
|
|
#define EXIT 0x400
|
2020-08-25 11:23:25 +00:00
|
|
|
|
|
|
|
|
|
#define CTRL(C) ((C) ^ 0100)
|
|
|
|
|
#define ALT(C) (('\e' << 010) | (C))
|
|
|
|
|
|
|
|
|
|
struct Panels {
|
|
|
|
|
union {
|
|
|
|
|
struct {
|
|
|
|
|
struct Panel disassembly;
|
|
|
|
|
struct Panel breakpointshr;
|
|
|
|
|
struct Panel breakpoints;
|
|
|
|
|
struct Panel mapshr;
|
|
|
|
|
struct Panel maps;
|
|
|
|
|
struct Panel tracehr;
|
|
|
|
|
struct Panel trace;
|
2020-08-27 06:08:08 +00:00
|
|
|
|
struct Panel terminalhr;
|
|
|
|
|
struct Panel terminal;
|
2020-08-25 11:23:25 +00:00
|
|
|
|
struct Panel registers;
|
|
|
|
|
struct Panel ssehr;
|
|
|
|
|
struct Panel sse;
|
|
|
|
|
struct Panel codehr;
|
|
|
|
|
struct Panel code;
|
|
|
|
|
struct Panel readhr;
|
|
|
|
|
struct Panel readdata;
|
|
|
|
|
struct Panel writehr;
|
|
|
|
|
struct Panel writedata;
|
|
|
|
|
struct Panel stackhr;
|
|
|
|
|
struct Panel stack;
|
|
|
|
|
};
|
2020-08-27 06:08:08 +00:00
|
|
|
|
struct Panel p[20];
|
2020-08-25 11:23:25 +00:00
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const char kRegisterNames[16][4] = {
|
|
|
|
|
"RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI",
|
|
|
|
|
"R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int tyn;
|
|
|
|
|
static int txn;
|
|
|
|
|
static int ttyfd;
|
|
|
|
|
static bool react;
|
|
|
|
|
static bool ssehex;
|
|
|
|
|
static int exitcode;
|
|
|
|
|
static bool tuimode;
|
|
|
|
|
static long rombase;
|
|
|
|
|
static bool colorize;
|
|
|
|
|
static long codesize;
|
|
|
|
|
static long ssewidth;
|
|
|
|
|
static char *codepath;
|
2020-08-27 06:08:08 +00:00
|
|
|
|
static void *onbusted;
|
2020-08-25 11:23:25 +00:00
|
|
|
|
static unsigned focus;
|
|
|
|
|
static unsigned opline;
|
|
|
|
|
static bool printstats;
|
|
|
|
|
static unsigned action;
|
|
|
|
|
static int64_t opstart;
|
|
|
|
|
static int64_t memstart;
|
|
|
|
|
static struct Elf elf[1];
|
|
|
|
|
static struct Dis dis[1];
|
|
|
|
|
static struct Panels pan;
|
|
|
|
|
static int64_t readstart;
|
|
|
|
|
static int64_t writestart;
|
|
|
|
|
static int64_t stackstart;
|
|
|
|
|
static struct DisHigh high;
|
|
|
|
|
static struct Machine m[2];
|
2020-08-27 06:08:08 +00:00
|
|
|
|
static struct MachinePty *pty;
|
2020-08-25 11:23:25 +00:00
|
|
|
|
static char logpath[PATH_MAX];
|
|
|
|
|
static char systemfailure[128];
|
|
|
|
|
static struct sigaction oldsig[4];
|
|
|
|
|
static struct Breakpoints breakpoints;
|
|
|
|
|
|
2020-08-27 06:08:08 +00:00
|
|
|
|
static void SetupDraw(void);
|
|
|
|
|
static void Redraw(void);
|
|
|
|
|
|
2020-08-25 11:23:25 +00:00
|
|
|
|
static uint64_t SignExtend(uint64_t x, uint8_t b) {
|
|
|
|
|
uint64_t s;
|
|
|
|
|
s = 1;
|
|
|
|
|
b -= 1;
|
|
|
|
|
b &= 63;
|
|
|
|
|
s <<= b;
|
|
|
|
|
if (x & s) x |= ~(s - 1);
|
|
|
|
|
return x;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *FormatDouble(char *b, double x) {
|
|
|
|
|
return g_fmt(b, x);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool IsCall(void) {
|
|
|
|
|
return m->xedd->op.map == XED_ILD_MAP0 &&
|
|
|
|
|
(m->xedd->op.opcode == 0xE8 ||
|
|
|
|
|
(m->xedd->op.opcode == 0xFF && m->xedd->op.reg == 2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool IsDebugBreak(void) {
|
|
|
|
|
return m->xedd->op.map == XED_ILD_MAP0 && m->xedd->op.opcode == 0xCC;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool IsRet(void) {
|
|
|
|
|
if (m->xedd->op.map == XED_ILD_MAP0) {
|
|
|
|
|
switch (m->xedd->op.opcode) {
|
|
|
|
|
case 0xC2:
|
|
|
|
|
case 0xC3:
|
|
|
|
|
case 0xCA:
|
|
|
|
|
case 0xCB:
|
|
|
|
|
case 0xCF:
|
|
|
|
|
return true;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static uint8_t CycleSseType(uint8_t t) {
|
|
|
|
|
switch (t) {
|
|
|
|
|
case kXmmIntegral:
|
|
|
|
|
return kXmmFloat;
|
|
|
|
|
case kXmmFloat:
|
|
|
|
|
return kXmmDouble;
|
|
|
|
|
case kXmmDouble:
|
|
|
|
|
return kXmmIntegral;
|
|
|
|
|
default:
|
|
|
|
|
unreachable;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static uint8_t CycleSseWidth(uint8_t w) {
|
|
|
|
|
switch (w) {
|
|
|
|
|
case 1:
|
|
|
|
|
return 2;
|
|
|
|
|
case 2:
|
|
|
|
|
return 4;
|
|
|
|
|
case 4:
|
|
|
|
|
return 8;
|
|
|
|
|
case 8:
|
|
|
|
|
return 1;
|
|
|
|
|
default:
|
|
|
|
|
unreachable;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-27 06:08:08 +00:00
|
|
|
|
static void OnBusted(void) {
|
|
|
|
|
CHECK(onbusted);
|
|
|
|
|
longjmp(onbusted, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int VirtualBing(int64_t v) {
|
|
|
|
|
int rc;
|
2020-08-25 11:23:25 +00:00
|
|
|
|
uint8_t *p;
|
2020-08-27 06:08:08 +00:00
|
|
|
|
jmp_buf busted;
|
|
|
|
|
onbusted = busted;
|
2020-08-25 11:23:25 +00:00
|
|
|
|
if ((p = FindReal(m, v))) {
|
2020-08-27 06:08:08 +00:00
|
|
|
|
if (!setjmp(busted)) {
|
|
|
|
|
rc = bing(p[0], 0);
|
|
|
|
|
} else {
|
|
|
|
|
rc = u'≀';
|
|
|
|
|
}
|
2020-08-25 11:23:25 +00:00
|
|
|
|
} else {
|
2020-08-27 06:08:08 +00:00
|
|
|
|
rc = u'⋅';
|
2020-08-25 11:23:25 +00:00
|
|
|
|
}
|
2020-08-27 06:08:08 +00:00
|
|
|
|
onbusted = NULL;
|
|
|
|
|
return rc;
|
2020-08-25 11:23:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ScrollOp(struct Panel *p, long op) {
|
|
|
|
|
long n;
|
|
|
|
|
opline = op;
|
|
|
|
|
if ((n = p->bottom - p->top) > 1) {
|
|
|
|
|
if (!(opstart + 1 <= op && op < opstart + n)) {
|
|
|
|
|
opstart = MIN(MAX(0, op - n / 8), MAX(0, dis->ops.i - n));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void GetTtySize(void) {
|
|
|
|
|
struct winsize wsize;
|
|
|
|
|
wsize.ws_row = 25;
|
|
|
|
|
wsize.ws_col = 80;
|
|
|
|
|
getttysize(ttyfd, &wsize);
|
|
|
|
|
tyn = wsize.ws_row;
|
|
|
|
|
txn = wsize.ws_col;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void TuiRejuvinate(void) {
|
|
|
|
|
GetTtySize();
|
|
|
|
|
ttyhidecursor(STDOUT_FILENO);
|
2020-08-27 06:08:08 +00:00
|
|
|
|
ttyraw(0);
|
|
|
|
|
xsigaction(SIGBUS, OnBusted, SA_NODEFER, 0, NULL);
|
2020-08-25 11:23:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnCtrlC(void) {
|
2020-08-27 06:08:08 +00:00
|
|
|
|
LOGF("OnCtrlC");
|
|
|
|
|
action |= INT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnQ(void) {
|
|
|
|
|
LOGF("OnQ");
|
|
|
|
|
action |= INT;
|
|
|
|
|
breakpoints.i = 0;
|
2020-08-25 11:23:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnWinch(void) {
|
2020-08-27 06:08:08 +00:00
|
|
|
|
LOGF("OnWinch");
|
2020-08-25 11:23:25 +00:00
|
|
|
|
action |= WINCHED;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-27 06:08:08 +00:00
|
|
|
|
static void OnCont(void) {
|
|
|
|
|
LOGF("OnCont");
|
2020-08-25 11:23:25 +00:00
|
|
|
|
TuiRejuvinate();
|
2020-08-27 06:08:08 +00:00
|
|
|
|
SetupDraw();
|
|
|
|
|
Redraw();
|
2020-08-25 11:23:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void TuiCleanup(void) {
|
|
|
|
|
sigaction(SIGWINCH, oldsig + 0, NULL);
|
|
|
|
|
sigaction(SIGCONT, oldsig + 2, NULL);
|
|
|
|
|
ttyraw((enum TtyRawFlags)(-1u));
|
|
|
|
|
ttyshowcursor(STDOUT_FILENO);
|
|
|
|
|
CHECK_NE(-1, close(ttyfd));
|
|
|
|
|
tuimode = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ResolveBreakpoints(void) {
|
|
|
|
|
long i, sym;
|
|
|
|
|
for (i = 0; i < breakpoints.i; ++i) {
|
|
|
|
|
if (breakpoints.p[i].symbol && !breakpoints.p[i].addr) {
|
|
|
|
|
if ((sym = DisFindSymByName(dis, breakpoints.p[i].symbol)) != -1) {
|
|
|
|
|
breakpoints.p[i].addr = dis->syms.p[sym].addr;
|
|
|
|
|
} else {
|
|
|
|
|
fprintf(stderr, "error: breakpoint not found: %s\n",
|
|
|
|
|
breakpoints.p[i].symbol);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void BreakAtNextInstruction(void) {
|
|
|
|
|
struct Breakpoint b = {.addr = m->ip + m->xedd->length, .oneshot = true};
|
2020-08-27 06:08:08 +00:00
|
|
|
|
PushBreakpoint(&breakpoints, &b);
|
2020-08-25 11:23:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void LoadSyms(void) {
|
|
|
|
|
LoadDebugSymbols(elf);
|
|
|
|
|
DisLoadElf(dis, elf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void TuiSetup(void) {
|
|
|
|
|
static bool once;
|
|
|
|
|
if (!once) {
|
|
|
|
|
LOGF("loaded program %s\n%s", codepath, gc(FormatPml4t(m->cr3)));
|
|
|
|
|
LoadSyms();
|
|
|
|
|
ResolveBreakpoints();
|
|
|
|
|
Dis(dis, m, elf->base);
|
|
|
|
|
once = true;
|
|
|
|
|
}
|
|
|
|
|
CHECK_NE(-1, (ttyfd = open("/dev/tty", O_RDWR)));
|
2020-08-27 06:08:08 +00:00
|
|
|
|
xsigaction(SIGWINCH, OnWinch, 0, 0, oldsig + 0);
|
|
|
|
|
xsigaction(SIGCONT, OnCont, SA_RESTART, 0, oldsig + 2);
|
2020-08-25 11:23:25 +00:00
|
|
|
|
memcpy(&m[1], &m[0], sizeof(m[0]));
|
|
|
|
|
TuiRejuvinate();
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-27 06:08:08 +00:00
|
|
|
|
static void ExecSetup(void) {
|
|
|
|
|
static bool once;
|
|
|
|
|
if (!once) {
|
|
|
|
|
if (breakpoints.i) {
|
|
|
|
|
LoadSyms();
|
|
|
|
|
ResolveBreakpoints();
|
|
|
|
|
}
|
|
|
|
|
once = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-25 11:23:25 +00:00
|
|
|
|
static void AppendPanel(struct Panel *p, long line, const char *s) {
|
|
|
|
|
if (0 <= line && line < p->bottom - p->top) {
|
|
|
|
|
AppendStr(&p->lines[line], s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool IsXmmNonZero(long start, long end) {
|
|
|
|
|
long i, j;
|
|
|
|
|
for (i = start; i < end; ++i) {
|
|
|
|
|
for (j = 0; j < 16; ++j) {
|
|
|
|
|
if (m->xmm[i / 8][i % 8][j]) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int PickNumberOfXmmRegistersToShow(void) {
|
|
|
|
|
if (IsXmmNonZero(0, 8) || IsXmmNonZero(8, 16)) {
|
|
|
|
|
if (IsXmmNonZero(8, 16)) {
|
|
|
|
|
return 16;
|
|
|
|
|
} else {
|
|
|
|
|
return 8;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-27 06:08:08 +00:00
|
|
|
|
static void SetupDraw(void) {
|
|
|
|
|
int i, j, n, a, b, cpuy, ssey, dx[2], c2y[3], c3y[5];
|
2020-08-25 11:23:25 +00:00
|
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAYLEN(pan.p); ++i) {
|
|
|
|
|
n = pan.p[i].bottom - pan.p[i].top;
|
|
|
|
|
for (j = 0; j < n; ++j) {
|
|
|
|
|
free(pan.p[i].lines[j].p);
|
|
|
|
|
}
|
|
|
|
|
free(pan.p[i].lines);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cpuy = 9;
|
|
|
|
|
ssey = PickNumberOfXmmRegistersToShow();
|
|
|
|
|
if (ssey) ++ssey;
|
|
|
|
|
|
|
|
|
|
a = 12 + 1 + DUMPWIDTH;
|
|
|
|
|
b = DUMPWIDTH;
|
|
|
|
|
dx[1] = txn >= a + b ? txn - a : txn;
|
|
|
|
|
dx[0] = txn >= a + b + b ? txn - a - b : dx[1];
|
|
|
|
|
|
2020-08-27 06:08:08 +00:00
|
|
|
|
a = 1 / 8. * tyn;
|
|
|
|
|
b = 3 / 8. * tyn;
|
2020-08-25 11:23:25 +00:00
|
|
|
|
c2y[0] = a;
|
|
|
|
|
c2y[1] = a * 2;
|
2020-08-27 06:08:08 +00:00
|
|
|
|
c2y[2] = a * 2 + b;
|
2020-08-25 11:23:25 +00:00
|
|
|
|
|
|
|
|
|
a = (tyn - (cpuy + ssey) - 3) / 4;
|
|
|
|
|
c3y[0] = cpuy;
|
|
|
|
|
c3y[1] = cpuy + ssey;
|
|
|
|
|
c3y[2] = cpuy + ssey + 1 + 1 + a * 1;
|
|
|
|
|
c3y[3] = cpuy + ssey + 1 + 1 + a * 2 + 1;
|
|
|
|
|
c3y[4] = cpuy + ssey + 1 + 1 + 1 + a * 3 + 1;
|
|
|
|
|
|
|
|
|
|
/* COLUMN #1: DISASSEMBLY */
|
|
|
|
|
|
|
|
|
|
pan.disassembly.top = 0;
|
|
|
|
|
pan.disassembly.left = 0;
|
|
|
|
|
pan.disassembly.bottom = tyn;
|
|
|
|
|
pan.disassembly.right = dx[0];
|
|
|
|
|
|
2020-08-27 06:08:08 +00:00
|
|
|
|
/* COLUMN #2: BREAKPOINTS, MEMORY MAPS, BACKTRACE, TERMINAL */
|
2020-08-25 11:23:25 +00:00
|
|
|
|
|
|
|
|
|
pan.breakpointshr.top = 0;
|
|
|
|
|
pan.breakpointshr.left = dx[0];
|
|
|
|
|
pan.breakpointshr.bottom = 1;
|
|
|
|
|
pan.breakpointshr.right = dx[1] - 1;
|
|
|
|
|
|
|
|
|
|
pan.breakpoints.top = 1;
|
|
|
|
|
pan.breakpoints.left = dx[0];
|
|
|
|
|
pan.breakpoints.bottom = c2y[0];
|
|
|
|
|
pan.breakpoints.right = dx[1] - 1;
|
|
|
|
|
|
|
|
|
|
pan.mapshr.top = c2y[0];
|
|
|
|
|
pan.mapshr.left = dx[0];
|
|
|
|
|
pan.mapshr.bottom = c2y[0] + 1;
|
|
|
|
|
pan.mapshr.right = dx[1] - 1;
|
|
|
|
|
|
|
|
|
|
pan.maps.top = c2y[0] + 1;
|
|
|
|
|
pan.maps.left = dx[0];
|
|
|
|
|
pan.maps.bottom = c2y[1];
|
|
|
|
|
pan.maps.right = dx[1] - 1;
|
|
|
|
|
|
|
|
|
|
pan.tracehr.top = c2y[1];
|
|
|
|
|
pan.tracehr.left = dx[0];
|
|
|
|
|
pan.tracehr.bottom = c2y[1] + 1;
|
|
|
|
|
pan.tracehr.right = dx[1] - 1;
|
|
|
|
|
|
|
|
|
|
pan.trace.top = c2y[1] + 1;
|
|
|
|
|
pan.trace.left = dx[0];
|
2020-08-27 06:08:08 +00:00
|
|
|
|
pan.trace.bottom = c2y[2];
|
2020-08-25 11:23:25 +00:00
|
|
|
|
pan.trace.right = dx[1] - 1;
|
|
|
|
|
|
2020-08-27 06:08:08 +00:00
|
|
|
|
pan.terminalhr.top = c2y[2];
|
|
|
|
|
pan.terminalhr.left = dx[0];
|
|
|
|
|
pan.terminalhr.bottom = c2y[2] + 1;
|
|
|
|
|
pan.terminalhr.right = dx[1] - 1;
|
|
|
|
|
|
|
|
|
|
pan.terminal.top = c2y[2] + 1;
|
|
|
|
|
pan.terminal.left = dx[0];
|
|
|
|
|
pan.terminal.bottom = tyn;
|
|
|
|
|
pan.terminal.right = dx[1] - 1;
|
|
|
|
|
|
2020-08-25 11:23:25 +00:00
|
|
|
|
/* COLUMN #3: REGISTERS, VECTORS, CODE, MEMORY READS, MEMORY WRITES, STACK */
|
|
|
|
|
|
|
|
|
|
pan.registers.top = 0;
|
|
|
|
|
pan.registers.left = dx[1];
|
|
|
|
|
pan.registers.bottom = c3y[0];
|
|
|
|
|
pan.registers.right = txn;
|
|
|
|
|
|
|
|
|
|
pan.ssehr.top = c3y[0];
|
|
|
|
|
pan.ssehr.left = dx[1];
|
|
|
|
|
pan.ssehr.bottom = c3y[0] + (ssey ? 1 : 0);
|
|
|
|
|
pan.ssehr.right = txn;
|
|
|
|
|
|
|
|
|
|
pan.sse.top = c3y[0] + (ssey ? 1 : 0);
|
|
|
|
|
pan.sse.left = dx[1];
|
|
|
|
|
pan.sse.bottom = c3y[1];
|
|
|
|
|
pan.sse.right = txn;
|
|
|
|
|
|
|
|
|
|
pan.codehr.top = c3y[1];
|
|
|
|
|
pan.codehr.left = dx[1];
|
|
|
|
|
pan.codehr.bottom = c3y[1] + 1;
|
|
|
|
|
pan.codehr.right = txn;
|
|
|
|
|
|
|
|
|
|
pan.code.top = c3y[1] + 1;
|
|
|
|
|
pan.code.left = dx[1];
|
|
|
|
|
pan.code.bottom = c3y[2];
|
|
|
|
|
pan.code.right = txn;
|
|
|
|
|
|
|
|
|
|
pan.readhr.top = c3y[2];
|
|
|
|
|
pan.readhr.left = dx[1];
|
|
|
|
|
pan.readhr.bottom = c3y[2] + 1;
|
|
|
|
|
pan.readhr.right = txn;
|
|
|
|
|
|
|
|
|
|
pan.readdata.top = c3y[2] + 1;
|
|
|
|
|
pan.readdata.left = dx[1];
|
|
|
|
|
pan.readdata.bottom = c3y[3];
|
|
|
|
|
pan.readdata.right = txn;
|
|
|
|
|
|
|
|
|
|
pan.writehr.top = c3y[3];
|
|
|
|
|
pan.writehr.left = dx[1];
|
|
|
|
|
pan.writehr.bottom = c3y[3] + 1;
|
|
|
|
|
pan.writehr.right = txn;
|
|
|
|
|
|
|
|
|
|
pan.writedata.top = c3y[3] + 1;
|
|
|
|
|
pan.writedata.left = dx[1];
|
|
|
|
|
pan.writedata.bottom = c3y[4];
|
|
|
|
|
pan.writedata.right = txn;
|
|
|
|
|
|
|
|
|
|
pan.stackhr.top = c3y[4];
|
|
|
|
|
pan.stackhr.left = dx[1];
|
|
|
|
|
pan.stackhr.bottom = c3y[4] + 1;
|
|
|
|
|
pan.stackhr.right = txn;
|
|
|
|
|
|
|
|
|
|
pan.stack.top = c3y[4] + 1;
|
|
|
|
|
pan.stack.left = dx[1];
|
|
|
|
|
pan.stack.bottom = tyn;
|
|
|
|
|
pan.stack.right = txn;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAYLEN(pan.p); ++i) {
|
|
|
|
|
if (pan.p[i].top > pan.p[i].bottom) pan.p[i].top = pan.p[i].bottom = 0;
|
|
|
|
|
if (pan.p[i].left > pan.p[i].right) pan.p[i].left = pan.p[i].right = 0;
|
|
|
|
|
pan.p[i].lines =
|
|
|
|
|
xcalloc(pan.p[i].bottom - pan.p[i].top, sizeof(struct Buffer));
|
|
|
|
|
}
|
2020-08-27 06:08:08 +00:00
|
|
|
|
|
|
|
|
|
if (pty->yn != pan.terminal.bottom - pan.terminal.top ||
|
|
|
|
|
pty->xn != pan.terminal.right - pan.terminal.left) {
|
|
|
|
|
LOGF("MachinePtyNew");
|
|
|
|
|
MachinePtyFree(pty);
|
|
|
|
|
pty = MachinePtyNew(pan.terminal.bottom - pan.terminal.top,
|
|
|
|
|
pan.terminal.right - pan.terminal.left);
|
|
|
|
|
}
|
2020-08-25 11:23:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static long GetDisIndex(int64_t addr) {
|
|
|
|
|
long i;
|
|
|
|
|
if ((i = DisFind(dis, m->ip)) == -1) {
|
|
|
|
|
Dis(dis, m, m->ip);
|
|
|
|
|
CHECK_NE(-1, (i = DisFind(dis, m->ip)));
|
|
|
|
|
}
|
|
|
|
|
while (i + 1 < dis->ops.i && !dis->ops.p[i].size) ++i;
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void DrawDisassembly(struct Panel *p) {
|
|
|
|
|
long i, j;
|
|
|
|
|
for (i = 0; i < p->bottom - p->top; ++i) {
|
|
|
|
|
j = opstart + i;
|
|
|
|
|
if (0 <= j && j < dis->ops.i) {
|
|
|
|
|
if (j == opline) AppendPanel(p, i, "\e[7m");
|
|
|
|
|
AppendPanel(p, i, dis->ops.p[j].s);
|
|
|
|
|
if (j == opline) AppendPanel(p, i, "\e[27m");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-27 06:08:08 +00:00
|
|
|
|
static void DrawTerminal(struct Panel *p) {
|
|
|
|
|
long y, yn;
|
|
|
|
|
for (yn = MIN(pty->yn, p->bottom - p->top), y = 0; y < yn; ++y) {
|
|
|
|
|
MachinePtyAppendLine(pty, p->lines + y, y);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-31 12:17:31 +00:00
|
|
|
|
static void DrawFlag(struct Panel *p, long i, char name, bool value) {
|
|
|
|
|
char str[] = " ";
|
|
|
|
|
if (value) str[1] = name;
|
|
|
|
|
AppendPanel(p, i, str);
|
2020-08-25 11:23:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void DrawRegister(struct Panel *p, long i, long r) {
|
|
|
|
|
char buf[32];
|
|
|
|
|
uint64_t value, previous;
|
|
|
|
|
value = Read64(m[0].reg[r]);
|
|
|
|
|
previous = Read64(m[1].reg[r]);
|
|
|
|
|
if (value != previous) AppendPanel(p, i, "\e[7m");
|
|
|
|
|
snprintf(buf, sizeof(buf), "%-3s", kRegisterNames[r]);
|
|
|
|
|
AppendPanel(p, i, buf);
|
|
|
|
|
AppendPanel(p, i, " ");
|
|
|
|
|
snprintf(buf, sizeof(buf), "0x%016lx", value);
|
|
|
|
|
AppendPanel(p, i, buf);
|
|
|
|
|
if (value != previous) AppendPanel(p, i, "\e[27m");
|
|
|
|
|
AppendPanel(p, i, " ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void DrawSt(struct Panel *p, long i, long r) {
|
|
|
|
|
char buf[32];
|
2020-08-31 12:17:31 +00:00
|
|
|
|
long double value;
|
2020-08-25 11:23:25 +00:00
|
|
|
|
bool isempty, changed;
|
|
|
|
|
isempty = FpuGetTag(m, r) == kFpuTagEmpty;
|
|
|
|
|
if (isempty) AppendPanel(p, i, "\e[2m");
|
2020-08-31 12:17:31 +00:00
|
|
|
|
value = m[0].fpu.st[(r + m[0].fpu.sp) & 0b111];
|
|
|
|
|
changed = value != m[1].fpu.st[(r + m[0].fpu.sp) & 0b111];
|
2020-08-25 11:23:25 +00:00
|
|
|
|
if (!isempty && changed) AppendPanel(p, i, "\e[7m");
|
|
|
|
|
snprintf(buf, sizeof(buf), "ST%d ", r);
|
|
|
|
|
AppendPanel(p, i, buf);
|
|
|
|
|
AppendPanel(p, i, FormatDouble(buf, value));
|
|
|
|
|
if (changed) AppendPanel(p, i, "\e[27m");
|
|
|
|
|
AppendPanel(p, i, " ");
|
|
|
|
|
if (isempty) AppendPanel(p, i, "\e[22m");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void DrawHr(struct Panel *p, const char *s) {
|
|
|
|
|
long i, wp, ws, wl, wr;
|
|
|
|
|
if (p->bottom - p->top < 1) return;
|
|
|
|
|
wp = p->right - p->left;
|
|
|
|
|
ws = strlen(s);
|
|
|
|
|
wl = wp / 4 - ws / 2;
|
|
|
|
|
wr = wp - (wl + ws);
|
|
|
|
|
for (i = 0; i < wl; ++i) AppendWide(&p->lines[0], u'─');
|
|
|
|
|
AppendStr(&p->lines[0], s);
|
|
|
|
|
for (i = 0; i < wr; ++i) AppendWide(&p->lines[0], u'─');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void DrawCpu(struct Panel *p) {
|
|
|
|
|
char buf[48];
|
2020-08-27 06:08:08 +00:00
|
|
|
|
DrawRegister(p, 0, 7), DrawRegister(p, 0, 0), DrawSt(p, 0, 0);
|
|
|
|
|
DrawRegister(p, 1, 6), DrawRegister(p, 1, 3), DrawSt(p, 1, 1);
|
|
|
|
|
DrawRegister(p, 2, 2), DrawRegister(p, 2, 5), DrawSt(p, 2, 2);
|
|
|
|
|
DrawRegister(p, 3, 1), DrawRegister(p, 3, 4), DrawSt(p, 3, 3);
|
|
|
|
|
DrawRegister(p, 4, 8), DrawRegister(p, 4, 12), DrawSt(p, 4, 4);
|
|
|
|
|
DrawRegister(p, 5, 9), DrawRegister(p, 5, 13), DrawSt(p, 5, 5);
|
|
|
|
|
DrawRegister(p, 6, 10), DrawRegister(p, 6, 14), DrawSt(p, 6, 6);
|
|
|
|
|
DrawRegister(p, 7, 11), DrawRegister(p, 7, 15), DrawSt(p, 7, 7);
|
2020-08-25 11:23:25 +00:00
|
|
|
|
snprintf(buf, sizeof(buf), "RIP 0x%016x FLG", m[0].ip);
|
|
|
|
|
AppendPanel(p, 8, buf);
|
2020-08-31 12:17:31 +00:00
|
|
|
|
DrawFlag(p, 8, 'C', GetFlag(m[0].flags, FLAGS_CF));
|
|
|
|
|
DrawFlag(p, 8, 'P', GetFlag(m[0].flags, FLAGS_PF));
|
|
|
|
|
DrawFlag(p, 8, 'A', GetFlag(m[0].flags, FLAGS_AF));
|
|
|
|
|
DrawFlag(p, 8, 'Z', GetFlag(m[0].flags, FLAGS_ZF));
|
|
|
|
|
DrawFlag(p, 8, 'S', GetFlag(m[0].flags, FLAGS_SF));
|
|
|
|
|
DrawFlag(p, 8, 'I', GetFlag(m[0].flags, FLAGS_IF));
|
|
|
|
|
DrawFlag(p, 8, 'D', GetFlag(m[0].flags, FLAGS_DF));
|
|
|
|
|
DrawFlag(p, 8, 'O', GetFlag(m[0].flags, FLAGS_OF));
|
|
|
|
|
AppendPanel(p, 8, " ");
|
|
|
|
|
if (m->fpu.ie) AppendPanel(p, 8, " IE");
|
|
|
|
|
if (m->fpu.de) AppendPanel(p, 8, " DE");
|
|
|
|
|
if (m->fpu.ze) AppendPanel(p, 8, " ZE");
|
|
|
|
|
if (m->fpu.oe) AppendPanel(p, 8, " OE");
|
|
|
|
|
if (m->fpu.ue) AppendPanel(p, 8, " UE");
|
|
|
|
|
if (m->fpu.pe) AppendPanel(p, 8, " PE");
|
|
|
|
|
if (m->fpu.sf) AppendPanel(p, 8, " SF");
|
|
|
|
|
if (m->fpu.es) AppendPanel(p, 8, " ES");
|
|
|
|
|
if (m->fpu.c0) AppendPanel(p, 8, " C0");
|
|
|
|
|
if (m->fpu.c1) AppendPanel(p, 8, " C1");
|
|
|
|
|
if (m->fpu.c2) AppendPanel(p, 8, " C2");
|
|
|
|
|
if (m->fpu.bf) AppendPanel(p, 8, " BF");
|
2020-08-25 11:23:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void DrawXmm(struct Panel *p, long i, long r) {
|
|
|
|
|
float f;
|
|
|
|
|
double d;
|
|
|
|
|
long j, k, n;
|
|
|
|
|
uint8_t type;
|
|
|
|
|
bool changed;
|
|
|
|
|
char buf[32];
|
|
|
|
|
uint8_t xmm[16];
|
|
|
|
|
uint64_t ival, itmp;
|
|
|
|
|
int cells, left, cellwidth, panwidth;
|
|
|
|
|
memcpy(xmm, m->xmm[r / 8][r % 8], sizeof(xmm));
|
|
|
|
|
changed = memcmp(xmm, m[1].xmm[r / 8][r % 8], sizeof(xmm)) != 0;
|
|
|
|
|
if (changed) AppendPanel(p, i, "\e[7m");
|
|
|
|
|
left = sprintf(buf, "XMM%-2d", r);
|
|
|
|
|
AppendPanel(p, i, buf);
|
|
|
|
|
type = m->xmmtype[r / 8][r % 8];
|
|
|
|
|
switch (type) {
|
|
|
|
|
case kXmmFloat:
|
|
|
|
|
cells = 4;
|
|
|
|
|
break;
|
|
|
|
|
case kXmmDouble:
|
|
|
|
|
cells = 2;
|
|
|
|
|
break;
|
|
|
|
|
case kXmmIntegral:
|
|
|
|
|
cells = 16 / ssewidth;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
unreachable;
|
|
|
|
|
}
|
|
|
|
|
panwidth = p->right - p->left;
|
|
|
|
|
cellwidth = MIN(MAX(0, (panwidth - left) / cells - 1), sizeof(buf) - 1);
|
|
|
|
|
for (j = 0; j < cells; ++j) {
|
|
|
|
|
AppendPanel(p, i, " ");
|
|
|
|
|
switch (type) {
|
|
|
|
|
case kXmmFloat:
|
|
|
|
|
memcpy(&f, xmm + j * sizeof(f), sizeof(f));
|
|
|
|
|
FormatDouble(buf, f);
|
|
|
|
|
break;
|
|
|
|
|
case kXmmDouble:
|
|
|
|
|
memcpy(&d, xmm + j * sizeof(d), sizeof(d));
|
|
|
|
|
FormatDouble(buf, d);
|
|
|
|
|
break;
|
|
|
|
|
case kXmmIntegral:
|
|
|
|
|
ival = 0;
|
|
|
|
|
for (k = 0; k < ssewidth; ++k) {
|
|
|
|
|
itmp = xmm[j * ssewidth + k] & 0xff;
|
|
|
|
|
itmp <<= k * 8;
|
|
|
|
|
ival |= itmp;
|
|
|
|
|
}
|
|
|
|
|
if (!ssehex) {
|
|
|
|
|
if (0 && ssewidth == 1 && (040 <= ival && ival < 0200 - 1)) {
|
|
|
|
|
sprintf(buf, "%`'c", ival);
|
|
|
|
|
} else {
|
|
|
|
|
int64toarray_radix10(SignExtend(ival, ssewidth * 8), buf);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
uint64toarray_fixed16(ival, buf, ssewidth * 8);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
unreachable;
|
|
|
|
|
}
|
|
|
|
|
buf[cellwidth] = '\0';
|
|
|
|
|
AppendPanel(p, i, buf);
|
|
|
|
|
n = cellwidth - strlen(buf);
|
|
|
|
|
for (k = 0; k < n; ++k) {
|
|
|
|
|
AppendPanel(p, i, " ");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (changed) AppendPanel(p, i, "\e[27m");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void DrawSse(struct Panel *p) {
|
|
|
|
|
long i;
|
|
|
|
|
for (i = 0; i < MIN(16, MAX(0, p->bottom - p->top)); ++i) {
|
|
|
|
|
DrawXmm(p, i, i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ScrollCode(struct Panel *p) {
|
|
|
|
|
long i, n;
|
|
|
|
|
n = p->bottom - p->top;
|
|
|
|
|
i = m->ip / DUMPWIDTH;
|
|
|
|
|
if (!(memstart <= i && i < memstart + n)) {
|
|
|
|
|
memstart = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ScrollReadData(struct Panel *p) {
|
|
|
|
|
long i, n, addr;
|
|
|
|
|
n = p->bottom - p->top;
|
|
|
|
|
i = m->readaddr / DUMPWIDTH;
|
|
|
|
|
if (!(readstart <= i && i < readstart + n)) {
|
|
|
|
|
readstart = i - n / 3;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ScrollWriteData(struct Panel *p) {
|
|
|
|
|
long i, n, addr;
|
|
|
|
|
n = p->bottom - p->top;
|
|
|
|
|
i = m->writeaddr / DUMPWIDTH;
|
|
|
|
|
if (!(writestart <= i && i < writestart + n)) {
|
|
|
|
|
writestart = i - n / 3;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ScrollStack(struct Panel *p) {
|
|
|
|
|
long i, n;
|
|
|
|
|
n = p->bottom - p->top;
|
|
|
|
|
i = Read64(m->sp) / DUMPWIDTH;
|
|
|
|
|
if (!(stackstart <= i && i < stackstart + n)) {
|
|
|
|
|
stackstart = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void DrawMemory(struct Panel *p, long beg, long a, long b) {
|
|
|
|
|
char buf[16];
|
|
|
|
|
long i, j, k, c;
|
|
|
|
|
bool high, changed;
|
|
|
|
|
high = false;
|
|
|
|
|
for (i = 0; i < p->bottom - p->top; ++i) {
|
|
|
|
|
snprintf(buf, sizeof(buf), "%p ", (beg + i) * DUMPWIDTH);
|
|
|
|
|
AppendStr(&p->lines[i], buf);
|
|
|
|
|
for (j = 0; j < DUMPWIDTH; ++j) {
|
|
|
|
|
k = (beg + i) * DUMPWIDTH + j;
|
2020-08-27 06:08:08 +00:00
|
|
|
|
c = VirtualBing(k);
|
2020-08-25 11:23:25 +00:00
|
|
|
|
changed = a <= k && k < b;
|
|
|
|
|
if (changed && !high) {
|
|
|
|
|
high = true;
|
|
|
|
|
AppendStr(&p->lines[i], "\e[7m");
|
|
|
|
|
} else if (!changed && high) {
|
|
|
|
|
AppendStr(&p->lines[i], "\e[27m");
|
|
|
|
|
high = false;
|
|
|
|
|
}
|
|
|
|
|
AppendWide(&p->lines[i], c);
|
|
|
|
|
}
|
|
|
|
|
if (high) {
|
|
|
|
|
AppendStr(&p->lines[i], "\e[27m");
|
|
|
|
|
high = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void DrawMaps(struct Panel *p) {
|
|
|
|
|
int i;
|
|
|
|
|
char *text, *p1, *p2;
|
|
|
|
|
p1 = text = FormatPml4t(m->cr3);
|
|
|
|
|
for (i = 0; p1; ++i, p1 = p2) {
|
|
|
|
|
if ((p2 = strchr(p1, '\n'))) *p2++ = '\0';
|
|
|
|
|
AppendPanel(p, i, p1);
|
|
|
|
|
}
|
|
|
|
|
free(text);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void DrawBreakpoints(struct Panel *p) {
|
|
|
|
|
int64_t addr;
|
|
|
|
|
char buf[128];
|
|
|
|
|
const char *name;
|
|
|
|
|
long i, line, sym;
|
2020-08-27 06:08:08 +00:00
|
|
|
|
for (line = 0, i = breakpoints.i; i--;) {
|
2020-08-25 11:23:25 +00:00
|
|
|
|
if (breakpoints.p[i].disable) continue;
|
|
|
|
|
addr = breakpoints.p[i].addr;
|
|
|
|
|
sym = DisFindSym(dis, addr);
|
|
|
|
|
name = sym != -1 ? dis->syms.stab + dis->syms.p[sym].name : "UNKNOWN";
|
|
|
|
|
snprintf(buf, sizeof(buf), "%p %s", addr, name);
|
|
|
|
|
AppendPanel(p, line, buf);
|
|
|
|
|
if (sym != -1 && addr != dis->syms.p[sym].addr) {
|
|
|
|
|
snprintf(buf, sizeof(buf), "+%#lx", addr - dis->syms.p[sym].addr);
|
|
|
|
|
AppendPanel(p, line, buf);
|
|
|
|
|
}
|
|
|
|
|
++line;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void DrawTrace(struct Panel *p) {
|
|
|
|
|
int i, n;
|
|
|
|
|
long sym;
|
|
|
|
|
uint8_t *r;
|
|
|
|
|
char line[128];
|
|
|
|
|
const char *name;
|
|
|
|
|
int64_t sp, bp, rp;
|
|
|
|
|
rp = m->ip;
|
|
|
|
|
bp = Read64(m->bp);
|
|
|
|
|
sp = Read64(m->sp);
|
|
|
|
|
for (i = 0; i < p->bottom - p->top;) {
|
|
|
|
|
sym = DisFindSym(dis, rp);
|
|
|
|
|
name = sym != -1 ? dis->syms.stab + dis->syms.p[sym].name : "UNKNOWN";
|
|
|
|
|
snprintf(line, sizeof(line), "%p %p %s", bp, rp, name);
|
|
|
|
|
AppendPanel(p, i, line);
|
|
|
|
|
if (sym != -1 && rp != dis->syms.p[sym].addr) {
|
|
|
|
|
snprintf(line, sizeof(line), "+%#lx", rp - dis->syms.p[sym].addr);
|
|
|
|
|
AppendPanel(p, i, line);
|
|
|
|
|
}
|
|
|
|
|
if (!bp) break;
|
|
|
|
|
if (bp < sp) {
|
|
|
|
|
AppendPanel(p, i, " [STRAY]");
|
|
|
|
|
} else {
|
|
|
|
|
snprintf(line, sizeof(line), " %,ld bytes", bp - sp);
|
|
|
|
|
AppendPanel(p, i, line);
|
|
|
|
|
}
|
|
|
|
|
if (bp & 15 && i) AppendPanel(p, i, " [MISALIGN]");
|
|
|
|
|
++i;
|
|
|
|
|
if ((bp & 0xfff) > 0xff0) break;
|
|
|
|
|
if (!(r = FindReal(m, bp))) {
|
|
|
|
|
AppendPanel(p, i, "CORRUPT FRAME POINTER");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
sp = bp;
|
|
|
|
|
bp = Read64(r + 0);
|
|
|
|
|
rp = Read64(r + 8);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void CheckFramePointerImpl(void) {
|
|
|
|
|
uint8_t *r;
|
|
|
|
|
int64_t bp, sp, rp;
|
|
|
|
|
static int64_t lastbp;
|
|
|
|
|
bp = Read64(m->bp);
|
|
|
|
|
if (bp && bp == lastbp) return;
|
|
|
|
|
lastbp = bp;
|
|
|
|
|
rp = m->ip;
|
|
|
|
|
sp = Read64(m->sp);
|
|
|
|
|
while (bp) {
|
|
|
|
|
if (!(r = FindReal(m, bp))) {
|
|
|
|
|
LOGF("corrupt frame: %p", bp);
|
|
|
|
|
ThrowProtectionFault(m);
|
|
|
|
|
}
|
|
|
|
|
sp = bp;
|
|
|
|
|
bp = Read64(r + 0) - 0;
|
|
|
|
|
rp = Read64(r + 8) - 1;
|
|
|
|
|
if (!bp && !(m->bofram[0] <= rp && rp <= m->bofram[1])) {
|
|
|
|
|
LOGF("bad frame !(%p <= %p <= %p)", m->bofram[0], rp, m->bofram[1]);
|
|
|
|
|
ThrowProtectionFault(m);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
forceinline void CheckFramePointer(void) {
|
|
|
|
|
if (m->bofram[0]) {
|
|
|
|
|
CheckFramePointerImpl();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void Redraw(void) {
|
2020-08-27 06:08:08 +00:00
|
|
|
|
int i, j;
|
|
|
|
|
for (i = 0; i < ARRAYLEN(pan.p); ++i) {
|
|
|
|
|
for (j = 0; j < pan.p[i].bottom - pan.p[i].top; ++j) {
|
|
|
|
|
pan.p[i].lines[j].i = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-08-25 11:23:25 +00:00
|
|
|
|
DrawDisassembly(&pan.disassembly);
|
2020-08-27 06:08:08 +00:00
|
|
|
|
DrawTerminal(&pan.terminal);
|
2020-08-25 11:23:25 +00:00
|
|
|
|
DrawCpu(&pan.registers);
|
|
|
|
|
DrawSse(&pan.sse);
|
|
|
|
|
ScrollCode(&pan.code);
|
|
|
|
|
ScrollStack(&pan.stack);
|
|
|
|
|
ScrollReadData(&pan.readdata);
|
|
|
|
|
ScrollWriteData(&pan.writedata);
|
|
|
|
|
DrawHr(&pan.breakpointshr, "BREAKPOINTS");
|
|
|
|
|
DrawHr(&pan.mapshr, "MAPS");
|
|
|
|
|
DrawHr(&pan.tracehr, m->bofram[0] ? "PROTECTED FRAMES" : "FRAMES");
|
2020-08-27 06:08:08 +00:00
|
|
|
|
DrawHr(&pan.terminalhr, "TELETYPEWRITER");
|
2020-08-25 11:23:25 +00:00
|
|
|
|
DrawHr(&pan.ssehr, "SSE");
|
|
|
|
|
DrawHr(&pan.codehr, "CODE");
|
|
|
|
|
DrawHr(&pan.readhr, "READ");
|
|
|
|
|
DrawHr(&pan.writehr, "WRITE");
|
|
|
|
|
DrawHr(&pan.stackhr, "STACK");
|
|
|
|
|
DrawMaps(&pan.maps);
|
|
|
|
|
DrawTrace(&pan.trace);
|
|
|
|
|
DrawBreakpoints(&pan.breakpoints);
|
|
|
|
|
DrawMemory(&pan.code, memstart, m->ip, m->ip + m->xedd->length);
|
|
|
|
|
DrawMemory(&pan.readdata, readstart, m->readaddr, m->readaddr + m->readsize);
|
|
|
|
|
DrawMemory(&pan.writedata, writestart, m->writeaddr,
|
|
|
|
|
m->writeaddr + m->writesize);
|
|
|
|
|
DrawMemory(&pan.stack, stackstart, Read64(m->sp), Read64(m->sp) + 8);
|
2020-08-27 06:08:08 +00:00
|
|
|
|
if (PrintPanels(ttyfd, ARRAYLEN(pan.p), pan.p, tyn, txn) == -1) {
|
|
|
|
|
LOGF("PrintPanels Interrupted");
|
|
|
|
|
CHECK_EQ(EINTR, errno);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int OnPtyFdClose(int fd) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ssize_t OnPtyFdRead(int fd, void *data, size_t size) {
|
|
|
|
|
return read(fd, data, size);
|
2020-08-25 11:23:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-08-27 06:08:08 +00:00
|
|
|
|
static ssize_t OnPtyFdWrite(int fd, const void *data, size_t size) {
|
|
|
|
|
if (tuimode) {
|
|
|
|
|
return MachinePtyWrite(pty, data, size);
|
|
|
|
|
} else {
|
|
|
|
|
MachinePtyWrite(pty, data, size);
|
|
|
|
|
return write(fd, data, size);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct MachineFdCb kMachineFdCbPty = {
|
|
|
|
|
.close = OnPtyFdClose,
|
|
|
|
|
.read = OnPtyFdRead,
|
|
|
|
|
.write = OnPtyFdWrite,
|
|
|
|
|
};
|
|
|
|
|
|
2020-08-25 11:23:25 +00:00
|
|
|
|
static void LaunchDebuggerReactively(void) {
|
|
|
|
|
LOGF("%s", systemfailure);
|
|
|
|
|
if (tuimode) {
|
|
|
|
|
action |= FAILURE;
|
|
|
|
|
} else {
|
|
|
|
|
if (react) {
|
|
|
|
|
tuimode = true;
|
|
|
|
|
action |= FAILURE;
|
|
|
|
|
} else {
|
|
|
|
|
fprintf(stderr, "ERROR: %s\n", systemfailure);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnDebug(void) {
|
|
|
|
|
strcpy(systemfailure, "IT'S A TRAP");
|
|
|
|
|
LaunchDebuggerReactively();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnSegmentationFault(void) {
|
|
|
|
|
snprintf(systemfailure, sizeof(systemfailure), "SEGMENTATION FAULT %p",
|
|
|
|
|
m->faultaddr);
|
|
|
|
|
LaunchDebuggerReactively();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnProtectionFault(void) {
|
|
|
|
|
strcpy(systemfailure, "PROTECTION FAULT");
|
|
|
|
|
LaunchDebuggerReactively();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnSimdException(void) {
|
|
|
|
|
strcpy(systemfailure, "SIMD FAULT");
|
|
|
|
|
LaunchDebuggerReactively();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnUndefinedInstruction(void) {
|
2020-08-27 06:08:08 +00:00
|
|
|
|
die();
|
2020-08-25 11:23:25 +00:00
|
|
|
|
strcpy(systemfailure, "UNDEFINED INSTRUCTION");
|
|
|
|
|
LaunchDebuggerReactively();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnDecodeError(void) {
|
|
|
|
|
strcpy(stpcpy(systemfailure, "DECODE: "),
|
|
|
|
|
indexdoublenulstring(kXedErrorNames, m->xedd->op.error));
|
|
|
|
|
LaunchDebuggerReactively();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnDivideError(void) {
|
|
|
|
|
strcpy(systemfailure, "DIVIDE BY ZERO OR BANE/-1");
|
|
|
|
|
LaunchDebuggerReactively();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnFpuException(void) {
|
|
|
|
|
strcpy(systemfailure, "FPU EXCEPTION");
|
|
|
|
|
LaunchDebuggerReactively();
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-27 06:08:08 +00:00
|
|
|
|
static void OnExit(int rc) {
|
|
|
|
|
exitcode = rc;
|
|
|
|
|
action |= EXIT;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-25 11:23:25 +00:00
|
|
|
|
static void OnHalt(int interrupt) {
|
|
|
|
|
switch (interrupt) {
|
|
|
|
|
case 1:
|
|
|
|
|
case 3:
|
|
|
|
|
OnDebug();
|
|
|
|
|
break;
|
|
|
|
|
case kMachineSegmentationFault:
|
|
|
|
|
OnSegmentationFault();
|
|
|
|
|
break;
|
|
|
|
|
case kMachineProtectionFault:
|
|
|
|
|
OnProtectionFault();
|
|
|
|
|
break;
|
|
|
|
|
case kMachineSimdException:
|
|
|
|
|
OnSimdException();
|
|
|
|
|
break;
|
|
|
|
|
case kMachineUndefinedInstruction:
|
|
|
|
|
OnUndefinedInstruction();
|
|
|
|
|
break;
|
|
|
|
|
case kMachineDecodeError:
|
|
|
|
|
OnDecodeError();
|
|
|
|
|
break;
|
|
|
|
|
case kMachineDivideError:
|
|
|
|
|
OnDivideError();
|
|
|
|
|
break;
|
|
|
|
|
case kMachineFpuException:
|
|
|
|
|
OnFpuException();
|
|
|
|
|
break;
|
|
|
|
|
case kMachineExit:
|
|
|
|
|
case kMachineHalt:
|
|
|
|
|
default:
|
2020-08-27 06:08:08 +00:00
|
|
|
|
OnExit(interrupt);
|
2020-08-25 11:23:25 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnPageUp(void) {
|
|
|
|
|
opstart -= tyn / 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnPageDown(void) {
|
|
|
|
|
opstart += tyn / 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnUpArrow(void) {
|
|
|
|
|
opstart--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnDownArrow(void) {
|
|
|
|
|
opstart++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnHome(void) {
|
|
|
|
|
opstart = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnEnd(void) {
|
|
|
|
|
opstart = dis->ops.i - (pan.disassembly.bottom - pan.disassembly.top);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnEnter(void) {
|
|
|
|
|
action &= ~FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnTab(void) {
|
|
|
|
|
focus = (focus + 1) % ARRAYLEN(pan.p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnFeed(void) {
|
|
|
|
|
write(ttyfd, "\e[K\e[J", 6);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnUp(void) {
|
|
|
|
|
uint8_t b[8];
|
|
|
|
|
int64_t sp, bp, ret;
|
|
|
|
|
bp = Read64(m->bp);
|
|
|
|
|
sp = Read64(m->sp);
|
|
|
|
|
if (bp >= sp) {
|
|
|
|
|
VirtualSend(m, b, bp + 8, sizeof(b));
|
|
|
|
|
ret = Read64(b);
|
|
|
|
|
ScrollOp(&pan.disassembly, GetDisIndex(ret));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnDown(void) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnStep(void) {
|
|
|
|
|
if (action & FAILURE) return;
|
|
|
|
|
action |= STEP;
|
|
|
|
|
action &= ~NEXT;
|
|
|
|
|
action &= ~CONTINUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnNext(void) {
|
|
|
|
|
if (action & FAILURE) return;
|
|
|
|
|
action ^= NEXT;
|
|
|
|
|
action &= ~STEP;
|
|
|
|
|
action &= ~FINISH;
|
|
|
|
|
action &= ~CONTINUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnFinish(void) {
|
|
|
|
|
if (action & FAILURE) return;
|
|
|
|
|
action ^= FINISH;
|
|
|
|
|
action &= ~NEXT;
|
|
|
|
|
action &= ~FAILURE;
|
|
|
|
|
action &= ~CONTINUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnContinue(void) {
|
|
|
|
|
action |= CONTINUE;
|
|
|
|
|
action &= ~STEP;
|
|
|
|
|
action &= ~NEXT;
|
|
|
|
|
action &= ~FINISH;
|
|
|
|
|
action &= ~FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnQuit(void) {
|
|
|
|
|
action |= QUIT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnRestart(void) {
|
|
|
|
|
action |= RESTART;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnSseType(void) {
|
|
|
|
|
uint8_t t;
|
|
|
|
|
long i, j;
|
|
|
|
|
t = CycleSseType(m->xmmtype[0][0]);
|
|
|
|
|
for (i = 0; i < 2; ++i) {
|
|
|
|
|
for (j = 0; j < 8; ++j) {
|
|
|
|
|
m->xmmtype[i][j] = t;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnSseWidth(void) {
|
|
|
|
|
ssewidth = CycleSseWidth(ssewidth);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnSseHex(void) {
|
|
|
|
|
ssehex = !ssehex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool HasPendingKeyboard(void) {
|
|
|
|
|
struct pollfd fds[1];
|
|
|
|
|
fds[0].fd = ttyfd;
|
|
|
|
|
fds[0].events = POLLIN;
|
|
|
|
|
fds[0].revents = 0;
|
|
|
|
|
poll(fds, ARRAYLEN(fds), 0);
|
|
|
|
|
return fds[0].revents & (POLLIN | POLLERR);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool IsExecuting(void) {
|
|
|
|
|
return (action & (CONTINUE | STEP | NEXT | FINISH)) && !(action & FAILURE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ReadKeyboard(void) {
|
|
|
|
|
int c;
|
|
|
|
|
char b[20];
|
|
|
|
|
ssize_t rc;
|
|
|
|
|
size_t i, n;
|
|
|
|
|
if ((rc = read(ttyfd, b, 16)) != -1) {
|
|
|
|
|
for (n = rc, i = 0; i < n; ++i) {
|
|
|
|
|
switch (b[i++]) {
|
2020-08-27 06:08:08 +00:00
|
|
|
|
CASE('q', OnQ());
|
2020-08-25 11:23:25 +00:00
|
|
|
|
CASE('s', OnStep());
|
|
|
|
|
CASE('n', OnNext());
|
|
|
|
|
CASE('f', OnFinish());
|
|
|
|
|
CASE('x', OnSseHex());
|
|
|
|
|
CASE('c', OnContinue());
|
|
|
|
|
CASE('R', OnRestart());
|
|
|
|
|
CASE('t', OnSseType());
|
|
|
|
|
CASE('w', OnSseWidth());
|
|
|
|
|
CASE('u', OnUp());
|
|
|
|
|
CASE('d', OnDown());
|
2020-08-27 06:08:08 +00:00
|
|
|
|
CASE('B', PopBreakpoint(&breakpoints));
|
2020-08-25 11:23:25 +00:00
|
|
|
|
CASE('\t', OnTab());
|
|
|
|
|
CASE('\r', OnEnter());
|
|
|
|
|
CASE('\n', OnEnter());
|
2020-08-27 06:08:08 +00:00
|
|
|
|
CASE(CTRL('C'), OnCtrlC());
|
|
|
|
|
CASE(CTRL('D'), OnCtrlC());
|
|
|
|
|
CASE(CTRL('\\'), OnQuit());
|
|
|
|
|
CASE(CTRL('Z'), raise(SIGSTOP));
|
2020-08-25 11:23:25 +00:00
|
|
|
|
CASE(CTRL('L'), OnFeed());
|
|
|
|
|
CASE(CTRL('P'), OnUpArrow());
|
|
|
|
|
CASE(CTRL('N'), OnDownArrow());
|
|
|
|
|
CASE(CTRL('V'), OnPageDown());
|
|
|
|
|
case '\e':
|
|
|
|
|
switch (b[i++]) {
|
|
|
|
|
CASE('v', OnPageUp());
|
|
|
|
|
case '[':
|
|
|
|
|
switch (b[i++]) {
|
|
|
|
|
CASE('A', OnUpArrow());
|
|
|
|
|
CASE('B', OnDownArrow());
|
|
|
|
|
CASE('F', OnEnd());
|
|
|
|
|
CASE('H', OnHome());
|
|
|
|
|
case '1':
|
|
|
|
|
switch (b[i++]) {
|
|
|
|
|
CASE('~', OnHome());
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case '4':
|
|
|
|
|
switch (b[i++]) {
|
|
|
|
|
CASE('~', OnEnd());
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case '5':
|
|
|
|
|
switch (b[i++]) {
|
|
|
|
|
CASE('~', OnPageUp());
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case '6':
|
|
|
|
|
switch (b[i++]) {
|
|
|
|
|
CASE('~', OnPageDown());
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case '7':
|
|
|
|
|
switch (b[i++]) {
|
|
|
|
|
CASE('~', OnHome());
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case '8':
|
|
|
|
|
switch (b[i++]) {
|
|
|
|
|
CASE('~', OnEnd());
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-08-27 06:08:08 +00:00
|
|
|
|
} else if (errno == EINTR) {
|
|
|
|
|
LOGF("ReadKeyboard Interrupted");
|
|
|
|
|
} else if (errno == EAGAIN) {
|
|
|
|
|
poll((struct pollfd[]){{ttyfd, POLLIN}}, 1, -1);
|
2020-08-25 11:23:25 +00:00
|
|
|
|
} else {
|
2020-08-27 06:08:08 +00:00
|
|
|
|
perror("ReadKeyboard");
|
|
|
|
|
exit(1);
|
2020-08-25 11:23:25 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int64_t ParseHexValue(const char *s) {
|
|
|
|
|
char *ep;
|
|
|
|
|
int64_t x;
|
|
|
|
|
x = strtoll(s, &ep, 16);
|
|
|
|
|
if (*ep) {
|
|
|
|
|
fputs("ERROR: bad hexadecimal: ", stderr);
|
|
|
|
|
fputs(s, stderr);
|
|
|
|
|
fputc('\n', stderr);
|
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
}
|
|
|
|
|
return x;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void HandleBreakpointFlag(const char *s) {
|
|
|
|
|
struct Breakpoint b = {0};
|
|
|
|
|
if (isdigit(*s)) {
|
|
|
|
|
b.addr = ParseHexValue(s);
|
|
|
|
|
} else {
|
|
|
|
|
b.symbol = optarg;
|
|
|
|
|
}
|
2020-08-27 06:08:08 +00:00
|
|
|
|
PushBreakpoint(&breakpoints, &b);
|
2020-08-25 11:23:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static noreturn void PrintUsage(int rc, FILE *f) {
|
|
|
|
|
fprintf(f, "SYNOPSIS\n\n %s%s", program_invocation_name, USAGE);
|
|
|
|
|
exit(rc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void LeaveScreen(void) {
|
|
|
|
|
char buf[64];
|
|
|
|
|
write(ttyfd, buf, sprintf(buf, "\e[%d;%dH\e[S\r\n", tyn - 1, txn - 1));
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-27 06:08:08 +00:00
|
|
|
|
static void Exec(void) {
|
|
|
|
|
long op;
|
|
|
|
|
ssize_t bp;
|
|
|
|
|
int interrupt;
|
|
|
|
|
ExecSetup();
|
|
|
|
|
if (!(interrupt = setjmp(m->onhalt))) {
|
|
|
|
|
if ((bp = IsAtBreakpoint(&breakpoints, m->ip)) != -1) {
|
|
|
|
|
LOGF("BREAK %p", breakpoints.p[bp].addr);
|
|
|
|
|
tuimode = true;
|
|
|
|
|
LoadInstruction(m);
|
|
|
|
|
ExecuteInstruction(m);
|
|
|
|
|
CheckFramePointer();
|
|
|
|
|
ops++;
|
|
|
|
|
} else {
|
|
|
|
|
for (;;) {
|
|
|
|
|
LoadInstruction(m);
|
|
|
|
|
ExecuteInstruction(m);
|
|
|
|
|
CheckFramePointer();
|
|
|
|
|
ops++;
|
|
|
|
|
if (action || breakpoints.i) {
|
|
|
|
|
if (action & EXIT) {
|
|
|
|
|
LOGF("EXEC EXIT");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (action & INT) {
|
|
|
|
|
LOGF("EXEC INT");
|
|
|
|
|
if (react) {
|
|
|
|
|
LOGF("REACT");
|
|
|
|
|
action &= ~(INT | STEP | FINISH | NEXT);
|
|
|
|
|
tuimode = true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if ((bp = IsAtBreakpoint(&breakpoints, m->ip)) != -1) {
|
|
|
|
|
LOGF("BREAK %p", breakpoints.p[bp].addr);
|
|
|
|
|
tuimode = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
OnHalt(interrupt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void Tui(void) {
|
|
|
|
|
long op;
|
|
|
|
|
ssize_t bp;
|
|
|
|
|
int interrupt;
|
|
|
|
|
LOGF("TUI");
|
|
|
|
|
TuiSetup();
|
|
|
|
|
SetupDraw();
|
|
|
|
|
ScrollOp(&pan.disassembly, GetDisIndex(m->ip));
|
|
|
|
|
if (!(interrupt = setjmp(m->onhalt))) {
|
|
|
|
|
for (;;) {
|
|
|
|
|
if (!(action & FAILURE)) {
|
|
|
|
|
LoadInstruction(m);
|
|
|
|
|
} else {
|
|
|
|
|
m->xedd = m->icache;
|
|
|
|
|
m->xedd->length = 1;
|
|
|
|
|
m->xedd->bytes[0] = 0xCC;
|
|
|
|
|
m->xedd->op.opcode = 0xCC;
|
|
|
|
|
}
|
|
|
|
|
if (action & WINCHED) {
|
|
|
|
|
LOGF("WINCHED");
|
|
|
|
|
GetTtySize();
|
|
|
|
|
action &= ~WINCHED;
|
|
|
|
|
}
|
|
|
|
|
SetupDraw();
|
|
|
|
|
Redraw();
|
|
|
|
|
if (action & FAILURE) {
|
|
|
|
|
LOGF("TUI FAILURE");
|
|
|
|
|
PrintMessageBox(ttyfd, systemfailure, tyn, txn);
|
|
|
|
|
ReadKeyboard();
|
|
|
|
|
} else if (!IsExecuting() || HasPendingKeyboard()) {
|
|
|
|
|
ReadKeyboard();
|
|
|
|
|
}
|
|
|
|
|
if (action & INT) {
|
|
|
|
|
LOGF("TUI INT");
|
|
|
|
|
action &= ~INT;
|
|
|
|
|
if (action & (CONTINUE | NEXT | FINISH)) {
|
|
|
|
|
action &= ~(CONTINUE | NEXT | FINISH);
|
|
|
|
|
} else {
|
|
|
|
|
tuimode = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (action & EXIT) {
|
|
|
|
|
LeaveScreen();
|
|
|
|
|
LOGF("TUI EXIT");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (action & QUIT) {
|
|
|
|
|
LOGF("TUI QUIT");
|
|
|
|
|
action &= ~QUIT;
|
|
|
|
|
raise(SIGQUIT);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (action & RESTART) {
|
|
|
|
|
LOGF("TUI RESTART");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (IsExecuting()) {
|
|
|
|
|
op = GetDisIndex(m->ip);
|
|
|
|
|
ScrollOp(&pan.disassembly, op);
|
|
|
|
|
VERBOSEF("%s", dis->ops.p[op].s);
|
|
|
|
|
memcpy(&m[1], &m[0], sizeof(m[0]));
|
|
|
|
|
if (!(action & CONTINUE)) {
|
|
|
|
|
action &= ~STEP;
|
|
|
|
|
if (action & NEXT) {
|
|
|
|
|
action &= ~NEXT;
|
|
|
|
|
if (IsCall()) {
|
|
|
|
|
BreakAtNextInstruction();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (action & FINISH) {
|
|
|
|
|
if (IsCall()) {
|
|
|
|
|
BreakAtNextInstruction();
|
|
|
|
|
break;
|
|
|
|
|
} else if (IsRet()) {
|
|
|
|
|
action &= ~FINISH;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!IsDebugBreak()) {
|
|
|
|
|
ExecuteInstruction(m);
|
|
|
|
|
} else {
|
|
|
|
|
m->ip += m->xedd->length;
|
|
|
|
|
action &= ~NEXT;
|
|
|
|
|
action &= ~FINISH;
|
|
|
|
|
action &= ~CONTINUE;
|
|
|
|
|
}
|
|
|
|
|
CheckFramePointer();
|
|
|
|
|
ops++;
|
|
|
|
|
if (!(action & CONTINUE)) {
|
|
|
|
|
ScrollOp(&pan.disassembly, GetDisIndex(m->ip));
|
|
|
|
|
if ((action & FINISH) && IsRet()) action &= ~FINISH;
|
|
|
|
|
if (((action & NEXT) && IsRet()) || (action & FINISH)) {
|
|
|
|
|
action &= ~NEXT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ((action & (FINISH | NEXT | CONTINUE)) &&
|
|
|
|
|
(bp = IsAtBreakpoint(&breakpoints, m->ip)) != -1) {
|
|
|
|
|
action &= ~(FINISH | NEXT | CONTINUE);
|
|
|
|
|
LOGF("BREAK %p", breakpoints.p[bp].addr);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
OnHalt(interrupt);
|
|
|
|
|
ScrollOp(&pan.disassembly, GetDisIndex(m->ip));
|
|
|
|
|
}
|
|
|
|
|
TuiCleanup();
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-25 11:23:25 +00:00
|
|
|
|
static void GetOpts(int argc, char *argv[]) {
|
|
|
|
|
int opt;
|
|
|
|
|
stpcpy(stpcpy(stpcpy(logpath, kTmpPath), basename(argv[0])), ".log");
|
|
|
|
|
while ((opt = getopt(argc, argv, "?hvtrsb:HL:")) != -1) {
|
|
|
|
|
switch (opt) {
|
|
|
|
|
case 't':
|
|
|
|
|
tuimode = true;
|
|
|
|
|
break;
|
|
|
|
|
case 'r':
|
|
|
|
|
react = true;
|
|
|
|
|
break;
|
|
|
|
|
case 's':
|
|
|
|
|
printstats = true;
|
|
|
|
|
break;
|
|
|
|
|
case 'b':
|
|
|
|
|
HandleBreakpointFlag(optarg);
|
|
|
|
|
break;
|
|
|
|
|
case 'H':
|
|
|
|
|
g_dis_high = NULL;
|
|
|
|
|
break;
|
|
|
|
|
case 'v':
|
|
|
|
|
++g_loglevel;
|
|
|
|
|
break;
|
|
|
|
|
case 'L':
|
|
|
|
|
strcpy(logpath, optarg);
|
|
|
|
|
break;
|
|
|
|
|
case 'h':
|
|
|
|
|
case '?':
|
|
|
|
|
PrintUsage(EXIT_SUCCESS, stdout);
|
|
|
|
|
default:
|
|
|
|
|
PrintUsage(EX_USAGE, stderr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
g_logfile = fopen(logpath, "a");
|
2020-08-27 06:08:08 +00:00
|
|
|
|
setvbuf(g_logfile, xmalloc(PAGESIZE), _IOLBF, PAGESIZE);
|
2020-08-25 11:23:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int Emulator(int argc, char *argv[]) {
|
|
|
|
|
void *code;
|
2020-08-27 06:08:08 +00:00
|
|
|
|
int rc, fd;
|
2020-08-25 11:23:25 +00:00
|
|
|
|
codepath = argv[optind++];
|
2020-08-27 06:08:08 +00:00
|
|
|
|
pty = MachinePtyNew(20, 80);
|
|
|
|
|
InitMachine(m);
|
|
|
|
|
m->fds.p = xcalloc((m->fds.n = 8), sizeof(struct MachineFd));
|
2020-08-25 11:23:25 +00:00
|
|
|
|
Restart:
|
|
|
|
|
action = 0;
|
|
|
|
|
LoadProgram(m, codepath, argv + optind, environ, elf);
|
2020-08-27 06:08:08 +00:00
|
|
|
|
m->fds.i = 3;
|
|
|
|
|
m->fds.p[0].fd = STDIN_FILENO;
|
|
|
|
|
m->fds.p[0].cb = &kMachineFdCbPty;
|
|
|
|
|
m->fds.p[1].fd = STDOUT_FILENO;
|
|
|
|
|
m->fds.p[1].cb = &kMachineFdCbPty;
|
|
|
|
|
m->fds.p[2].fd = STDERR_FILENO;
|
|
|
|
|
m->fds.p[2].cb = &kMachineFdCbPty;
|
|
|
|
|
while (!(action & EXIT)) {
|
2020-08-25 11:23:25 +00:00
|
|
|
|
if (!tuimode) {
|
2020-08-27 06:08:08 +00:00
|
|
|
|
Exec();
|
2020-08-25 11:23:25 +00:00
|
|
|
|
} else {
|
2020-08-27 06:08:08 +00:00
|
|
|
|
Tui();
|
|
|
|
|
}
|
|
|
|
|
if (action & RESTART) {
|
|
|
|
|
goto Restart;
|
2020-08-25 11:23:25 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (tuimode) {
|
|
|
|
|
LeaveScreen();
|
|
|
|
|
}
|
|
|
|
|
if (printstats) {
|
|
|
|
|
fprintf(stderr, "taken: %,ld\n", taken);
|
|
|
|
|
fprintf(stderr, "ntaken: %,ld\n", ntaken);
|
|
|
|
|
fprintf(stderr, "ops: %,ld\n", ops);
|
|
|
|
|
}
|
|
|
|
|
munmap(elf->ehdr, elf->size);
|
|
|
|
|
DisFree(dis);
|
|
|
|
|
return exitcode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnlyRunOnFirstCpu(void) {
|
|
|
|
|
uint64_t bs;
|
|
|
|
|
bs = 1;
|
|
|
|
|
sched_setaffinity(0, sizeof(bs), &bs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(int argc, char *argv[]) {
|
|
|
|
|
int rc;
|
|
|
|
|
ssewidth = 2; /* 16-bit is best bit */
|
2020-08-27 06:08:08 +00:00
|
|
|
|
if (!NoDebug()) showcrashreports();
|
2020-08-25 11:23:25 +00:00
|
|
|
|
// OnlyRunOnFirstCpu();
|
|
|
|
|
if ((colorize = cancolor())) {
|
|
|
|
|
high.keyword = 155;
|
|
|
|
|
high.reg = 215;
|
|
|
|
|
high.literal = 182;
|
|
|
|
|
high.label = 221;
|
|
|
|
|
high.comment = 112;
|
|
|
|
|
g_dis_high = &high;
|
|
|
|
|
}
|
|
|
|
|
GetOpts(argc, argv);
|
|
|
|
|
if (optind == argc) PrintUsage(EX_USAGE, stderr);
|
|
|
|
|
rc = Emulator(argc, argv);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|