Skip to content

Commit

Permalink
Support debugging eXecute-only ELF segments
Browse files Browse the repository at this point in the history
  • Loading branch information
jart committed Jul 22, 2023
1 parent 768e9bb commit a00feef
Show file tree
Hide file tree
Showing 12 changed files with 75 additions and 24 deletions.
20 changes: 15 additions & 5 deletions blink/abort.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,30 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include <stdlib.h>

#include "blink/assert.h"
#include "blink/macros.h"
#include "blink/stats.h"
#include "blink/util.h"

bool g_exitdontabort;
static struct AbortHooks {
int n;
aborthook_f *p[4];
} g_aborthooks;

void AtAbort(aborthook_f *hook) {
unassert(g_aborthooks.n < ARRAYLEN(g_aborthooks.p));
g_aborthooks.p[g_aborthooks.n++] = hook;
}

void Abort(void) {
int i;
#ifndef NDEBUG
if (FLAG_statistics) {
PrintStats();
}
#endif
if (g_exitdontabort) {
exit(1);
} else {
abort();
for (i = g_aborthooks.n; i--;) {
g_aborthooks.p[i]();
}
abort();
}
2 changes: 1 addition & 1 deletion blink/bios.c
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ static void VidyaServiceWriteTeletype(u8 ch) {
void VidyaServiceSetMode(int mode) {
int cols, lines;
vidya = mode;
if (LookupAddress(m, 0xB0000)) {
if (SpyAddress(m, 0xB0000)) {
ptyisenabled = true;
lines = 25;
switch (mode) {
Expand Down
3 changes: 3 additions & 0 deletions blink/blink.c
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,9 @@ void exit(int status) {
int main(int argc, char *argv[]) {
SetupWeb();
GetStartDir();
#ifndef NDEBUG
AtAbort(PrintStats);
#endif
#ifndef DISABLE_STRACE
setlocale(LC_ALL, "");
#endif
Expand Down
18 changes: 11 additions & 7 deletions blink/blinkenlights.c
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,7 @@ static int VirtualBing(i64 v) {
int rc;
jmp_buf busted;
onbusted = &busted;
if ((p = (u8 *)LookupAddress(m, v))) {
if ((p = SpyAddress(m, v))) {
if (!setjmp(busted)) {
rc = kCp437[p[0] & 255];
} else {
Expand All @@ -686,7 +686,7 @@ static int VirtualShadow(i64 v) {
jmp_buf busted;
if (IsShadow(v)) return -2;
onbusted = &busted;
if ((p = (char *)LookupAddress(m, (v >> 3) + 0x7fff8000))) {
if ((p = (char *)SpyAddress(m, (v >> 3) + 0x7fff8000))) {
if (!setjmp(busted)) {
rc = p[0] & 0xff;
} else {
Expand Down Expand Up @@ -954,6 +954,7 @@ void TuiSetup(void) {
CommonSetup();
VfsTcgetattr(ttyout, &oldterm);
atexit(TtyRestore);
AtAbort(TtyRestore);
once = true;
report = true;
}
Expand Down Expand Up @@ -1870,7 +1871,7 @@ static void DrawFrames(struct Panel *p) {
}
++i;
if (((m->ss.base + bp) & 0xfff) > 0xff0) break;
if (!(r = LookupAddress(m, m->ss.base + bp))) {
if (!(r = SpyAddress(m, m->ss.base + bp))) {
AppendPanel(p, i - framesstart, "CORRUPT FRAME POINTER");
break;
}
Expand All @@ -1889,7 +1890,7 @@ static void CheckFramePointerImpl(void) {
lastbp = bp;
rp = m->ip;
while (bp) {
if (!(r = LookupAddress(m, m->ss.base + bp))) {
if (!(r = SpyAddress(m, m->ss.base + bp))) {
LOGF("corrupt frame: %0*" PRIx64 "", GetAddrHexWidth(), bp);
ThrowProtectionFault(m);
}
Expand Down Expand Up @@ -2132,8 +2133,8 @@ void Redraw(bool force) {
ShowHistory();
return;
}
LookupAddress(m, m->ip);
LookupAddress(m, Get64(m->sp));
LookupAddress(m, m->ip); // want page fault
LookupAddress(m, Get64(m->sp)); // want page fault
BEGIN_NO_PAGE_FAULTS;
start_draw = GetTime();
execsecs = ToNanoseconds(SubtractTime(start_draw, last_draw)) * 1e-9;
Expand Down Expand Up @@ -3679,9 +3680,12 @@ int main(int argc, char *argv[]) {
struct System *s;
static struct sigaction sa;
setlocale(LC_ALL, "");
g_exitdontabort = true;
SetupWeb();
GetStartDir();
AtAbort(PrintStats);
#ifndef NDEBUG
AtAbort(PrintStats);
#endif
// Ensure utf-8 is printed correctly on windows, this method
// has issues(http://stackoverflow.com/a/10884364/4279) but
// should work for at least windows 7 and newer.
Expand Down
9 changes: 9 additions & 0 deletions blink/checked.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,18 @@

#define __STDC_VERSION_STDCKDINT_H__ 202311L

#if ((defined(__GNUC__) && __GNUC__ >= 5 && !defined(__ICC)) || \
(defined(__has_builtin) && (__has_builtin(__builtin_add_overflow) && \
__has_builtin(__builtin_sub_overflow) && \
__has_builtin(__builtin_mul_overflow))))
#define ckd_add(res, x, y) __builtin_add_overflow((x), (y), (res))
#define ckd_sub(res, x, y) __builtin_sub_overflow((x), (y), (res))
#define ckd_mul(res, x, y) __builtin_mul_overflow((x), (y), (res))
#else
#define ckd_add(res, x, y) (*(res) = (x) + (y), 0)
#define ckd_sub(res, x, y) (*(res) = (x) - (y), 0)
#define ckd_mul(res, x, y) (*(res) = (x) * (y), 0)
#endif

#endif /* <stdckdint.h> */
#endif /* EASYCKDINT_H_ */
6 changes: 3 additions & 3 deletions blink/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,14 +136,14 @@ int GetInstruction(struct Machine *m, i64 pc, struct XedDecodedInst *x) {
int i, rc, err;
u8 copy[15], *toil, *addr;
BEGIN_NO_PAGE_FAULTS;
if ((addr = LookupAddress(m, pc))) {
if ((addr = SpyAddress(m, pc))) {
if ((i = 4096 - (pc & 4095)) >= 15) {
if (!DecodeInstruction(x, addr, 15, m->mode.omode)) {
rc = 0;
} else {
rc = kMachineDecodeError;
}
} else if ((toil = LookupAddress(m, pc + i))) {
} else if ((toil = SpyAddress(m, pc + i))) {
memcpy(copy, addr, i);
memcpy(copy + i, toil, 15 - i);
if (!DecodeInstruction(x, copy, 15, m->mode.omode)) {
Expand Down Expand Up @@ -287,7 +287,7 @@ const char *GetBacktrace(struct Machine *m) {
}
++i;
if (((m->ss.base + bp) & 0xfff) > 0xff0) break;
if (!(r = LookupAddress(m, m->ss.base + bp))) {
if (!(r = SpyAddress(m, m->ss.base + bp))) {
APPEND(" [CORRUPT FRAME POINTER]");
break;
}
Expand Down
4 changes: 2 additions & 2 deletions blink/dis.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,14 +229,14 @@ static long DisAppendOpLines(struct Dis *d, struct Machine *m, i64 addr) {
}
}
n = MAX(1, MIN(15, n));
if (!(r = LookupAddress(m, addr))) return -1;
if (!(r = SpyAddress(m, addr))) return -1;
k = 0x1000 - (addr & 0xfff);
if (n <= k) {
p = (u8 *)r;
} else {
p = b;
memcpy(b, r, k);
if ((r = LookupAddress(m, addr + k))) {
if ((r = SpyAddress(m, addr + k))) {
memcpy(b + k, r, n - k);
} else {
n = k;
Expand Down
6 changes: 4 additions & 2 deletions blink/machine.h
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,7 @@ bool HasPageLock(const struct Machine *, i64) nosideeffect;
void CollectPageLocks(struct Machine *);
u8 *LookupAddress(struct Machine *, i64);
u8 *LookupAddress2(struct Machine *, i64, u64, u64);
u8 *SpyAddress(struct Machine *, i64);
u8 *Load(struct Machine *, i64, size_t, u8 *);
u8 *MallocPage(void);
u8 *RealAddress(struct Machine *, i64);
Expand Down Expand Up @@ -806,8 +807,9 @@ void LogCodOp(struct Machine *, const char *);
#endif

MICRO_OP_SAFE u8 Cpl(struct Machine *m) {
return !m->metal ? 3u :
m->mode.genmode != XED_GEN_MODE_REAL ? (m->cs.sel & 3u) : 0u;
return !m->metal ? 3u
: m->mode.genmode != XED_GEN_MODE_REAL ? (m->cs.sel & 3u)
: 0u;
}

#define BEGIN_NO_PAGE_FAULTS \
Expand Down
23 changes: 21 additions & 2 deletions blink/memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,7 @@ u64 FindPageTableEntry(struct Machine *m, u64 page) {
u8 *LookupAddress2(struct Machine *m, i64 virt, u64 mask, u64 need) {
u8 *host;
u64 entry;
if (!m->metal ||
m->mode.omode == XED_MODE_LONG ||
if (!m->metal || m->mode.omode == XED_MODE_LONG ||
(m->mode.genmode != XED_GEN_MODE_REAL && (m->system->cr0 & CR0_PG))) {
if (!(entry = FindPageTableEntry(m, virt & -4096))) {
return 0;
Expand Down Expand Up @@ -307,6 +306,26 @@ flattencalls u8 *GetAddress(struct Machine *m, i64 v) {
return LookupAddress(m, v);
}

/**
* Translates virtual address into pointer.
*
* This function bypasses memory protection, since it's used to display
* memory in the debugger tui. That's useful, for example, if debugging
* programs that specify an eXecute-only program header.
*
* It's recommended that the caller use:
*
* BEGIN_NO_PAGE_FAULTS;
* i64 address = ...;
* u8 *pointer = SpyAddress(m, address);
* END_NO_PAGE_FAULTS;
*
* When calling this function.
*/
u8 *SpyAddress(struct Machine *m, i64 virt) {
return LookupAddress2(m, virt, 0, 0);
}

u8 *ResolveAddress(struct Machine *m, i64 v) {
u8 *r;
if ((r = GetAddress(m, v))) return r;
Expand Down
2 changes: 2 additions & 0 deletions blink/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -538,9 +538,11 @@ static int SysSpawn(struct Machine *m, u64 flags, u64 stack, u64 ptid, u64 ctid,
}
if (((flags & CLONE_PARENT_SETTID_LINUX) &&
((ptid & (sizeof(int) - 1)) ||
!IsValidMemory(m, ptid, 4, PROT_READ | PROT_WRITE) ||
!(ptid_ptr = (_Atomic(int) *)LookupAddress(m, ptid)))) ||
((flags & CLONE_CHILD_SETTID_LINUX) &&
((ctid & (sizeof(int) - 1)) ||
!IsValidMemory(m, ctid, 4, PROT_READ | PROT_WRITE) ||
!(ctid_ptr = (_Atomic(int) *)LookupAddress(m, ctid))))) {
LOGF("bad clone() ptid / ctid pointers: %#" PRIx64, flags);
return efault();
Expand Down
4 changes: 3 additions & 1 deletion blink/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
#include "blink/builtin.h"
#include "blink/types.h"

typedef void aborthook_f(void);

extern int optind_;
extern char *optarg_;
extern const short kCp437[256];
extern bool g_exitdontabort;

_Noreturn void Abort(void);
void AtAbort(aborthook_f *);
char *GetStartDir(void);
int GetOpt(int, char *const[], const char *);
u64 tpenc(uint32_t);
Expand Down
2 changes: 1 addition & 1 deletion blink/watch.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ ssize_t IsAtWatchpoint(struct Watchpoints *wps, struct Machine *m) {
m->ip = oldip;
// TODO(jart): Handle case of overlapping page boundary.
// TODO(jart): Possibly track munmap() type cases.
if ((r = LookupAddress(m, wps->p[i].addr))) {
if ((r = SpyAddress(m, wps->p[i].addr))) {
w = Read64(r);
if (!wps->p[i].initialized) {
wps->p[i].oldvalue = w;
Expand Down

0 comments on commit a00feef

Please sign in to comment.