Skip to content

Commit

Permalink
[debug] Enhance stack backtrace and instrumention library
Browse files Browse the repository at this point in the history
  • Loading branch information
ghaerr committed Apr 5, 2024
1 parent 4148b2e commit 6b8ae04
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 73 deletions.
2 changes: 2 additions & 0 deletions elks/kernel/printk.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ static void vprintk(const char *fmt, va_list p)
break;
case 'P':
v = current->pid;
c = 'd';
n = 10;
goto out;
case 'D':
c += 'X' - 'D';
Expand Down
8 changes: 4 additions & 4 deletions elkscmd/debug/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ CFLAGS += -fno-optimize-sibling-calls
CFLAGS += -fno-omit-frame-pointer
# optional instrumentation for function tracing
CFLAGS += -finstrument-functions-simple
# include symbol table in executable and heap to read it
LDFLAGS += -maout-symtab -maout-heap=12000
# include symbol table in executable
LDFLAGS += -maout-symtab

# added after CFLAGS for non-instrumented .c files in this directory
NOINSTFLAGS = -fno-instrument-functions -fno-instrument-functions-simple
Expand All @@ -37,7 +37,7 @@ testsym: $(TESTOBJS)
./nm86 $@ > $@.map

disasm: $(DISASMOBJS)
$(LD) $(LDFLAGS) -maout-heap=0xffff -o $@ $^ $(LDLIBS)
$(LD) $(LDFLAGS) -o $@ $^ $(LDLIBS)

system.sym:
cp -p $(TOPDIR)/elks/arch/i86/boot/system.sym $(TOPDIR)/elkscmd/debug
Expand All @@ -53,7 +53,7 @@ dis.o: dis.c
$(CC) $(CFLAGS) $(NOINSTFLAGS) -c -o $*.o $<

nm86: nm86.c syms.c
$(HOSTCC) $(HOSTCFLAGS) -o $@ $^
$(HOSTCC) $(HOSTCFLAGS) -D__far= -o $@ $^

hostdisasm: dis.c disasm.c syms.c
$(HOSTCC) $(HOSTCFLAGS) -D__far= -Wno-int-to-void-pointer-cast -Wno-format -o $@ $^
Expand Down
11 changes: 7 additions & 4 deletions elkscmd/debug/instrument.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,28 @@
/* turn on for microcycle (CPU cycle/1000) timing info */
#define HAS_RDTSC 0 /* has RDTSC instruction: requires 386+ CPU */

static char ftrace;
static int count;
static size_t ftrace;
static size_t start_sp;
static size_t max_stack;
static int count;

/* runs before main and rewrites argc/argv on stack if --ftrace found */
__attribute__((no_instrument_function,constructor(120)))
static void ftrace_checkargs(void)
{
char **avp = __argv + 1;

if ((*avp && !strcmp(*avp, "--ftrace")) || getenv("FTRACE")) {
ftrace = (size_t)getenv("FTRACE");
if ((*avp && !strcmp(*avp, "--ftrace"))) {
while (*avp) {
*avp = *(avp + 1);
avp++;
}
ftrace = 1;
__argc--;
ftrace = 1;
}
if (ftrace)
sym_read_exe_symbols(__program_filename);
#if HAS_RDTSC
_get_micro_count(); /* init timer base */
#endif
Expand Down
9 changes: 5 additions & 4 deletions elkscmd/debug/readprologue.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include "instrument.h"
#include "syms.h"

#define ADDR_CRT0 0x35 /* address within crt0.S (=_start) */

#define _get_csbyte(ip) __extension__ ({ \
unsigned char _v; \
asm volatile ("mov %%cs:(%%bx),%%al" \
Expand All @@ -34,8 +36,8 @@ int * noinstrument _get_fn_start_address(int *addr)

/* look backwards for prologue: push %bp/mov %sp,%bp (55 89 e5) */
for(;;) {
/* main called at 0x37 from crt0.S which has no prologue at _start */
if ((unsigned int)ip-i <= 0x37)
/* main called at ADDR_CRT0 from crt0.S which has no prologue at _start */
if ((size_t)ip-i < ADDR_CRT0)
return 0; /* _start address or start address not found */

if (_get_csbyte(ip-i+0) == 0x55 && /* push %bp */
Expand Down Expand Up @@ -68,8 +70,7 @@ int noinstrument _get_push_count(int *fnstart)
if (opcode == 0x57) /* push %di */
count = (count+1) | DI_PUSHED, opcode = _get_csbyte(fp++);
if (opcode == 0x55 || /* push %bp */
(opcode == 0x59 && (unsigned int)fp < 0x40)) /* hack for crt0.S 'pop %cx' start */
(opcode == 0x59 && (size_t)fp < ADDR_CRT0)) /* hack for crt0.S 'pop %cx' start */
count = (count + 1) | BP_PUSHED, opcode = _get_csbyte(fp);
//printf("%s (%x) pushes %x\n", sym_text_symbol(addr, 1), (int)addr, count);
return count;
}
2 changes: 2 additions & 0 deletions elkscmd/debug/stacktrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* June 2022 Greg Haerr
*/
#include <stdio.h>
#include <unistd.h>
#include "instrument.h"
#include "syms.h"

Expand Down Expand Up @@ -54,6 +55,7 @@ void noinstrument _print_stack(int arg1)
int *fn = (int *)_print_stack;
int i = 0;

sym_read_exe_symbols(__program_filename);
printf("Level Addr BP DI SI Ret Arg Arg2 Arg3 Arg4\n"
"~~~~~ ~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
do {
Expand Down
174 changes: 121 additions & 53 deletions elkscmd/debug/syms.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,124 +14,174 @@
#include <stdint.h>
#include "syms.h"

static unsigned char *syms;
static unsigned char __far *syms;
struct minix_exec_hdr sym_hdr;

#define MAGIC 0x0301 /* magic number for executable progs */

static void noinstrument fmemcpy(unsigned char __far *dst, unsigned char *src, int n)
{
do {
*dst++ = *src++;
} while (--n);
}

/* allocate space and read symbol table */
static unsigned char __far * noinstrument alloc_read(int fd, size_t size)
{
if (size == 0 || size > 32767)
return NULL;
#if __ia16__
#define ALLOC(s,n) ((int)(s = sbrk(n)) != -1)
unsigned char __far *s;
size_t n, t = 0;
unsigned char buf[512];
if (!(s = fmemalloc(size)))
return NULL;
do {
n = size > sizeof(buf)? sizeof(buf): size;
if (read(fd, buf, n) != n)
return NULL; // FIXME no fmemfree
fmemcpy(s+t, buf, n);
t += n;
size -= n;
} while (size);
return s;
#else
#define ALLOC(s,n) ((s = malloc(n)) != NULL)
char * __program_filename;
unsigned char *s;
if (!(s = malloc(size)))
return NULL;
if (read(fd, s, size) != size)
return NULL;
return (unsigned char __far *)s;
#endif

#define MAGIC 0x0301 /* magic number for executable progs */
}

/* read symbol table from executable into memory */
unsigned char * noinstrument sym_read_exe_symbols(char *path)
unsigned char __far * noinstrument sym_read_exe_symbols(char *path)
{
int fd;
unsigned char *s;
unsigned char __far *s;
char fullpath[PATH_MAX];

if (syms) return syms;
if ((fd = open(path, O_RDONLY)) < 0) {
sprintf(fullpath, "/bin/%s", path); // FIXME use PATH
strcpy(fullpath, "/bin/"); // FIXME use path
strcpy(fullpath+5, path);
if ((fd = open(fullpath, O_RDONLY)) < 0)
return NULL;
}
errno = 0;
if (read(fd, &sym_hdr, sizeof(sym_hdr)) != sizeof(sym_hdr)
|| ((sym_hdr.type & 0xFFFF) != MAGIC)
|| (sym_hdr.syms == 0 || sym_hdr.syms > 32767)
|| (!ALLOC(s, (int)sym_hdr.syms))
|| (lseek(fd, -(int)sym_hdr.syms, SEEK_END) < 0)
|| (read(fd, s, (int)sym_hdr.syms) != (int)sym_hdr.syms)) {
int e = errno;
close(fd);
errno = e;
return NULL;
|| !(s = alloc_read(fd, (size_t)sym_hdr.syms))) {
int e = errno;
close(fd);
errno = e;
return NULL;
}
close(fd);
syms = s;
return syms;
}

/* read symbol table file into memory */
unsigned char * noinstrument sym_read_symbols(char *path)
unsigned char __far * noinstrument sym_read_symbols(char *path)
{
int fd;
unsigned char *s;
unsigned char __far *s;
struct stat sbuf;

if (syms) return syms;
if ((fd = open(path, O_RDONLY)) < 0)
return NULL;
errno = 0;
if (fstat(fd, &sbuf) < 0
|| (sbuf.st_size == 0 || sbuf.st_size > 32767)
|| (!ALLOC(s, (int)sbuf.st_size))
|| (read(fd, s, (int)sbuf.st_size) != (int)sbuf.st_size)) {
int e = errno;
close(fd);
errno = e;
return NULL;
|| !(s = alloc_read(fd, (size_t)sbuf.st_size))) {
int e = errno;
close(fd);
errno = e;
return NULL;
}
close(fd);
syms = s;
return syms;
}

static int noinstrument type_text(unsigned char *p)
static int noinstrument type_text(unsigned char __far *p)
{
return (p[TYPE] == 'T' || p[TYPE] == 't' || p[TYPE] == 'W');
}

static int noinstrument type_ftext(unsigned char *p)
static int noinstrument type_ftext(unsigned char __far *p)
{
return (p[TYPE] == 'F' || p[TYPE] == 'f');
}

static int noinstrument type_data(unsigned char *p)
static int noinstrument type_data(unsigned char __far *p)
{
return (p[TYPE] == 'D' || p[TYPE] == 'd' ||
p[TYPE] == 'B' || p[TYPE] == 'b' ||
p[TYPE] == 'V');
}

#if UNUSED
/* map .text address to function start address */
void * noinstrument sym_fn_start_address(void *addr)
static char * noinstrument hexout(char *buf, unsigned int v, int zstart)
{
unsigned char *p, *lastp;
int sh = 12;

do {
int c = (v >> sh) & 15;
if (!c && sh > zstart)
continue;
if (c > 9)
*buf++ = 'a' - 10 + c;
else
*buf++ = '0' + c;
} while ((sh -= 4) >= 0);
*buf = '\0';
return buf;
}

if (!syms && !sym_read_exe_symbols(__program_filename))
return 0;
static char * noinstrument hex(char *buf, unsigned int v)
{
return hexout(buf, v, 0); /* %x */
}

lastp = syms;
for (p = next(lastp); ; lastp = p, p = next(p)) {
if (!type_text(p) || ((unsigned short)addr < *(unsigned short *)(&p[ADDR])))
break;
}
return (void *) (intptr_t) *(unsigned short *)(&lastp[ADDR]);
static char * noinstrument hex4(char *buf, unsigned int v)
{
return hexout(buf, v, 12); /* %04x */
}

static char * noinstrument fstrncpy(char *dst, unsigned char __far *src, int n)
{
do {
*dst++ = *src++;
} while (--n);
*dst = '\0';
return dst;
}
#endif

/*
* Convert address to symbol string+offset,
* offset = 0 don't show offset, offset = -1 no offset specified.
*/
static char * noinstrument sym_string(void *addr, int offset,
int (*istype)(unsigned char *p))
int (*istype)(unsigned char __far *p))
{
unsigned char *p, *lastp;
unsigned char __far *p;
unsigned char __far *lastp;
char *cp;
static char buf[64];

if (!syms && !sym_read_exe_symbols(__program_filename)) {
if (!syms) {
hex:
if (!offset || offset == -1)
sprintf(buf, "%04x", (unsigned int)addr);
else
sprintf(buf, "%04x+%x", (unsigned int)addr-offset, offset);
if (!offset || offset == -1) {
hex4(buf, (size_t)addr);
} else {
cp = hex4(buf, (size_t)addr-offset);
*cp++ = '+';
hex(cp, offset);
}
return buf;
}

Expand All @@ -142,14 +192,17 @@ static char * noinstrument sym_string(void *addr, int offset,
goto hex;
}
for (p = next(lastp); ; lastp = p, p = next(p)) {
if (!istype(p) || ((unsigned short)addr < *(unsigned short *)(&p[ADDR])))
if (!istype(p) || ((unsigned short)addr < *(unsigned short __far *)(&p[ADDR])))
break;
}
int lastaddr = *(unsigned short *)(&lastp[ADDR]);
int lastaddr = *(unsigned short __far *)(&lastp[ADDR]);
if (offset && addr - lastaddr) {
sprintf(buf, "%.*s+%x", lastp[SYMLEN], lastp+SYMBOL,
(unsigned int)addr - lastaddr);
} else sprintf(buf, "%.*s", lastp[SYMLEN], lastp+SYMBOL);
cp = fstrncpy(buf, lastp+SYMBOL, lastp[SYMLEN]);
*cp++ = '+';
hex(cp, (size_t)addr - lastaddr);
} else {
fstrncpy(buf, lastp+SYMBOL, lastp[SYMLEN]);
}
return buf;
}

Expand All @@ -172,6 +225,21 @@ char * noinstrument sym_data_symbol(void *addr, int offset)
}

#if UNUSED
/* map .text address to function start address */
void * noinstrument sym_fn_start_address(void *addr)
{
unsigned char __far *p;
unsigned char __far *lastp;

if (!syms) return NULL;
lastp = syms;
for (p = next(lastp); ; lastp = p, p = next(p)) {
if (!type_text(p) || ((unsigned short)addr < *(unsigned short __far *)(&p[ADDR])))
break;
}
return (void *) (intptr_t) *(unsigned short __far *)(&lastp[ADDR]);
}

static int noinstrument type_any(unsigned char *p)
{
return p[TYPE] != '\0';
Expand Down
Loading

0 comments on commit 6b8ae04

Please sign in to comment.