615 lines
13 KiB
C
615 lines
13 KiB
C
/** @file
|
|
For dumping the stack, GDA, heap and text segment.
|
|
*/
|
|
|
|
/* $Id$ */
|
|
|
|
#include <ctype.h>
|
|
|
|
#include "em_abs.h"
|
|
#include "dump.h"
|
|
#include "logging.h"
|
|
#include "global.h"
|
|
#include "log.h"
|
|
#include "memdirect.h"
|
|
#include "mem.h"
|
|
#include "fra.h"
|
|
#include "text.h"
|
|
#include "proctab.h"
|
|
#include "shadow.h"
|
|
#include "linfil.h"
|
|
#include "rsb.h"
|
|
|
|
extern long inr; /* from log.c */
|
|
|
|
/****************************************************************
|
|
* Dumping routines for debugging, in human-readable form. *
|
|
****************************************************************/
|
|
|
|
#ifdef LOGGING
|
|
|
|
/* The file is repetitive and should probably be partly generated,
|
|
although it is not directly evident how.
|
|
*/
|
|
|
|
/* Forward declarations */
|
|
PRIVATE char *displ_undefs(int, ptr), *displ_fil(ptr), *displ_sh(char, int), *displ_code(int);
|
|
PRIVATE ptr std_raw(ptr, int), std_rsb(ptr);
|
|
PRIVATE int std_bytes(ptr, ptr, int), dtd_bytes(ptr, ptr, int), FRAd_bytes(int, int, int);
|
|
PRIVATE void std_item(ptr), std_left_undefs(int, ptr);
|
|
PRIVATE void gdad_item(ptr), gdad_left_undefs(int, ptr);
|
|
PRIVATE void hpd_item(ptr), hpd_left_undefs(int, ptr);
|
|
PRIVATE void FRA_dump(void), FRA_item(int);
|
|
|
|
/******** Stack Dump ********/
|
|
|
|
void std_all(long sz, int rawfl)
|
|
{
|
|
register ptr addr;
|
|
|
|
if (!check_log(" d1 "))
|
|
return;
|
|
|
|
LOG((" d2 "));
|
|
LOG((" d2 . . STACK_DUMP[%ld/%ld%s] . . INR = %lu . . STACK_DUMP . .",
|
|
wsize, psize, rawfl ? ", raw" : "", inr));
|
|
LOG((" d2 ----------------------------------------------------------------"));
|
|
|
|
/* find a good start address */
|
|
addr = (sz && sz < ML - SP ? SP + sz : ML);
|
|
/* find RSB backwards */
|
|
while (in_stack(addr) && !is_st_prot(addr)) {
|
|
addr++;
|
|
}
|
|
/* find end of RSB backwards */
|
|
while (in_stack(addr) && is_st_prot(addr)) {
|
|
addr++;
|
|
}
|
|
addr--;
|
|
|
|
/* dump the stack */
|
|
while (in_stack(addr)) {
|
|
addr = std_raw(addr, rawfl);
|
|
addr = std_rsb(addr);
|
|
}
|
|
FRA_dump();
|
|
LOG((" d1 >> AB = %lu, LB = %lu, SP = %lu, HP = %lu, LIN = %lu, FIL = %s",
|
|
AB, LB, SP, HP, getLIN(), displ_fil(getFIL())));
|
|
LOG((" d2 ----------------------------------------------------------------"));
|
|
LOG((" d2 "));
|
|
}
|
|
|
|
PRIVATE ptr std_raw(ptr addr, int rawfl)
|
|
{
|
|
/* Produces a formatted dump of the stack segment starting
|
|
at addr, up to the Return Status Block (identified
|
|
by protection bits)
|
|
*/
|
|
register int nundef = 0;
|
|
|
|
LOG((" d2 ADDRESS BYTE ITEM VALUE SHADOW"));
|
|
|
|
while ( in_stack(addr)
|
|
&& (!is_st_prot(addr) || rawfl)
|
|
) {
|
|
if (st_sh(addr) == UNDEFINED) {
|
|
if (nundef++ == 0)
|
|
LOG((" d2 %10lu undef", addr));
|
|
}
|
|
else {
|
|
if (nundef) {
|
|
std_left_undefs(nundef, addr + 1);
|
|
nundef = 0;
|
|
}
|
|
std_item(addr);
|
|
}
|
|
addr--;
|
|
}
|
|
if (nundef)
|
|
std_left_undefs(nundef, addr + 1);
|
|
return addr;
|
|
}
|
|
|
|
PRIVATE void std_item(ptr addr)
|
|
{
|
|
if ( is_wordaligned(addr)
|
|
&& is_in_stack(addr, psize)
|
|
&& std_bytes(addr, addr + psize, SH_DATAP|SH_INSP)
|
|
) {
|
|
/* print a pointer value */
|
|
LOG((" d2 %10lu %3lu [%10lu] (%-s)",
|
|
addr,
|
|
btol(stack_loc(addr)),
|
|
p_in_stack(addr),
|
|
displ_sh(st_sh(addr), stack_loc(addr))));
|
|
}
|
|
else
|
|
if ( is_wordaligned(addr)
|
|
&& w_is_in_stack(addr)
|
|
&& std_bytes(addr, addr + wsize, SH_INT)
|
|
) {
|
|
/* print a word value */
|
|
LOG((" d2 %10lu %3lu [%10ld] (%-s)",
|
|
addr,
|
|
btol(stack_loc(addr)),
|
|
w_in_stack(addr),
|
|
displ_sh(st_sh(addr), stack_loc(addr))));
|
|
}
|
|
else {
|
|
/* just print the byte */
|
|
LOG((" d2 %10lu %3lu (%-s)",
|
|
addr,
|
|
btol(stack_loc(addr)),
|
|
displ_sh(st_sh(addr), stack_loc(addr))));
|
|
}
|
|
}
|
|
|
|
/** Dumps the Return Status Block. */
|
|
PRIVATE ptr std_rsb(ptr addr)
|
|
{
|
|
ptr dmp_lb;
|
|
int code;
|
|
long pi;
|
|
ptr pc;
|
|
ptr lb;
|
|
long lin;
|
|
ptr fil;
|
|
char pr_descr[300];
|
|
|
|
if (!in_stack(addr))
|
|
return addr;
|
|
|
|
dmp_lb = addr - (rsbsize-1); /* pseudo local base */
|
|
if (!in_stack(dmp_lb)) {
|
|
LOG((" d1 >>RSB: >>>> INCOMPLETE <<<<"));
|
|
return dmp_lb;
|
|
}
|
|
|
|
code = (int)w_in_stack(dmp_lb + rsb_rsbcode);
|
|
pi = (long)p_in_stack(dmp_lb + rsb_PI);
|
|
pc = p_in_stack(dmp_lb + rsb_PC);
|
|
lb = p_in_stack(dmp_lb + rsb_LB);
|
|
lin = LIN_in_stack(dmp_lb + rsb_LIN);
|
|
fil = p_in_stack(dmp_lb + rsb_FIL);
|
|
|
|
if (pi == -1) {
|
|
sprintf(pr_descr, "uninit");
|
|
}
|
|
else
|
|
if (pi < NProc) {
|
|
sprintf(pr_descr, "(%ld,%ld)",
|
|
pi, (long)proctab[pi].pr_nloc);
|
|
}
|
|
else {
|
|
sprintf(pr_descr, "%ld >>>> ILLEGAL <<<<", pi);
|
|
}
|
|
LOG((" d1 >> RSB: code = %s, PI = %s, PC = %lu, LB = %lu, LIN = %lu, FIL = %s",
|
|
displ_code(code), pr_descr, pc, lb, lin, displ_fil(fil)));
|
|
|
|
LOG((" d2 "));
|
|
return addr - rsbsize;
|
|
}
|
|
|
|
PRIVATE char *displ_code(int rsbcode)
|
|
{
|
|
switch (rsbcode) {
|
|
case RSB_STP: return "STP";
|
|
case RSB_CAL: return "CAL";
|
|
case RSB_RTT: return "RTT";
|
|
case RSB_NRT: return "NRT";
|
|
default: return ">>Bad RSB code<<";
|
|
}
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
PRIVATE void std_left_undefs(int nundef, ptr addr)
|
|
{
|
|
/* handle pending undefineds */
|
|
switch (nundef) {
|
|
case 1:
|
|
break;
|
|
case 2:
|
|
LOG((" d2 %10lu undef", addr));
|
|
break;
|
|
default:
|
|
LOG((" d2 | | | | | |"));
|
|
LOG((" d2 %10lu undef (%s)",
|
|
addr, displ_undefs(nundef, addr)));
|
|
break;
|
|
}
|
|
}
|
|
|
|
PRIVATE void FRA_dump(void)
|
|
{
|
|
register int addr;
|
|
|
|
LOG((" d2 FRA: size = %d, %s",
|
|
FRASize, FRA_def ? "defined" : "undefined"));
|
|
|
|
for (addr = 0; addr < FRASize; addr++) {
|
|
FRA_item(addr);
|
|
}
|
|
}
|
|
|
|
PRIVATE void FRA_item(int addr)
|
|
{
|
|
if ( is_wordaligned(addr)
|
|
&& is_in_FRA(addr, psize)
|
|
&& FRAd_bytes(addr, (int)(addr + psize), SH_DATAP|SH_INSP)
|
|
) {
|
|
/* print a pointer value */
|
|
LOG((" d2 FRA[%1d] %3lu [%10lu] (%-s)",
|
|
addr,
|
|
btol(FRA[addr]),
|
|
p_in_FRA(addr),
|
|
displ_sh(FRA_sh[addr], FRA[addr])));
|
|
}
|
|
else
|
|
if ( is_wordaligned(addr)
|
|
&& is_in_FRA(addr, wsize)
|
|
&& FRAd_bytes(addr, (int)(addr + wsize), SH_INT)
|
|
) {
|
|
/* print a word value */
|
|
LOG((" d2 FRA[%1d] %3lu [%10ld] (%-s)",
|
|
addr,
|
|
btol(FRA[addr]),
|
|
w_in_FRA(addr),
|
|
displ_sh(FRA_sh[addr], FRA[addr])));
|
|
}
|
|
else {
|
|
/* just print the byte */
|
|
LOG((" d2 FRA[%1d] %3lu (%-s)",
|
|
addr,
|
|
btol(FRA[addr]),
|
|
displ_sh(FRA_sh[addr], FRA[addr])));
|
|
}
|
|
}
|
|
|
|
|
|
/******** Global Data Area Dump ********/
|
|
|
|
void gdad_all(ptr low, ptr high)
|
|
{
|
|
register ptr addr;
|
|
register int nundef = 0;
|
|
|
|
if (!check_log(" +1 "))
|
|
return;
|
|
|
|
if (low == 0 && high == 0)
|
|
high = HB;
|
|
|
|
LOG((" +1 "));
|
|
LOG((" +1 . . GDA_DUMP[%ld/%ld] . . INR = %lu . . GDA_DUMP . .",
|
|
wsize, psize, inr));
|
|
LOG((" +1 ----------------------------------------------------------------"));
|
|
LOG((" +1 ADDRESS BYTE WORD VALUE SHADOW"));
|
|
|
|
/* dump global data area contents */
|
|
addr = low;
|
|
while (addr < min(HB, high)) {
|
|
if (dt_sh(addr) == UNDEFINED) {
|
|
if (nundef++ == 0)
|
|
LOG((" +1 %10lu undef", addr));
|
|
}
|
|
else {
|
|
if (nundef) {
|
|
gdad_left_undefs(nundef, addr-1);
|
|
nundef = 0;
|
|
}
|
|
gdad_item(addr);
|
|
}
|
|
addr++;
|
|
}
|
|
if (nundef)
|
|
gdad_left_undefs(nundef, addr-1);
|
|
LOG((" +1 ----------------------------------------------------------------"));
|
|
LOG((" +1 "));
|
|
}
|
|
|
|
PRIVATE void gdad_item(ptr addr)
|
|
{
|
|
if ( is_wordaligned(addr)
|
|
&& is_in_data(addr, psize)
|
|
&& dtd_bytes(addr, addr + psize, SH_DATAP|SH_INSP)
|
|
) {
|
|
/* print a pointer value */
|
|
LOG((" +1 %10lu %3lu [%10lu] (%-s)",
|
|
addr,
|
|
btol(data_loc(addr)),
|
|
p_in_data(addr),
|
|
displ_sh(dt_sh(addr), data_loc(addr))));
|
|
}
|
|
else
|
|
if ( is_wordaligned(addr)
|
|
&& is_in_data(addr, wsize)
|
|
&& dtd_bytes(addr, addr + wsize, SH_INT)
|
|
) {
|
|
/* print a word value */
|
|
LOG((" +1 %10lu %3lu [%10ld] (%-s)",
|
|
addr,
|
|
btol(data_loc(addr)),
|
|
w_in_data(addr),
|
|
displ_sh(dt_sh(addr), data_loc(addr))));
|
|
}
|
|
else {
|
|
/* just print the byte */
|
|
LOG((" +1 %10lu %3lu (%-s)",
|
|
addr,
|
|
btol(data_loc(addr)),
|
|
displ_sh(dt_sh(addr), data_loc(addr))));
|
|
}
|
|
}
|
|
|
|
PRIVATE void gdad_left_undefs(int nundef, ptr addr)
|
|
{
|
|
/* handle pending undefineds */
|
|
switch (nundef) {
|
|
case 1:
|
|
break;
|
|
case 2:
|
|
LOG((" +1 %10lu undef", addr));
|
|
break;
|
|
default:
|
|
LOG((" +1 | | | | | |"));
|
|
LOG((" +1 %10lu undef (%s)",
|
|
addr, displ_undefs(nundef, addr)));
|
|
break;
|
|
}
|
|
}
|
|
|
|
/******** Heap Area Dump ********/
|
|
|
|
void hpd_all(void)
|
|
{
|
|
register ptr addr;
|
|
register int nundef = 0;
|
|
|
|
if (!check_log(" *1 "))
|
|
return;
|
|
|
|
LOG((" *1 "));
|
|
LOG((" *1 . . HEAP_DUMP[%ld/%ld] . . INR = %lu . . HEAP_DUMP . .",
|
|
wsize, psize, inr));
|
|
LOG((" *1 ----------------------------------------------------------------"));
|
|
LOG((" *1 ADDRESS BYTE WORD VALUE SHADOW"));
|
|
|
|
/* dump heap contents */
|
|
for (addr = HB; addr < HP; addr++) {
|
|
if (dt_sh(addr) == UNDEFINED) {
|
|
if (nundef++ == 0)
|
|
LOG((" *1 %10lu undef", addr));
|
|
}
|
|
else {
|
|
if (nundef) {
|
|
hpd_left_undefs(nundef, addr-1);
|
|
nundef = 0;
|
|
}
|
|
hpd_item(addr);
|
|
}
|
|
}
|
|
if (nundef)
|
|
hpd_left_undefs(nundef, addr-1);
|
|
LOG((" *1 ----------------------------------------------------------------"));
|
|
LOG((" *1 "));
|
|
}
|
|
|
|
PRIVATE void hpd_item(ptr addr)
|
|
{
|
|
if ( is_wordaligned(addr)
|
|
&& is_in_data(addr, psize)
|
|
&& dtd_bytes(addr, addr + psize, SH_DATAP|SH_INSP)
|
|
) {
|
|
/* print a pointer value */
|
|
LOG((" *1 %10lu %3lu [%10lu] (%-s)",
|
|
addr,
|
|
btol(data_loc(addr)),
|
|
p_in_data(addr),
|
|
displ_sh(dt_sh(addr), data_loc(addr))));
|
|
}
|
|
else
|
|
if ( is_wordaligned(addr)
|
|
&& is_in_data(addr, wsize)
|
|
&& dtd_bytes(addr, addr + wsize, SH_INT)
|
|
) {
|
|
/* print a word value */
|
|
LOG((" *1 %10lu %3lu [%10ld] (%-s)",
|
|
addr,
|
|
btol(data_loc(addr)),
|
|
w_in_data(addr),
|
|
displ_sh(dt_sh(addr), data_loc(addr))));
|
|
}
|
|
else {
|
|
/* just print the byte */
|
|
LOG((" *1 %10lu %3lu (%-s)",
|
|
addr,
|
|
btol(data_loc(addr)),
|
|
displ_sh(dt_sh(addr), data_loc(addr))));
|
|
}
|
|
}
|
|
|
|
PRIVATE void hpd_left_undefs(int nundef, ptr addr)
|
|
{
|
|
/* handle pending undefineds */
|
|
switch (nundef) {
|
|
case 1:
|
|
break;
|
|
case 2:
|
|
LOG((" *1 %10lu undef", addr));
|
|
break;
|
|
default:
|
|
LOG((" *1 | | | | | |"));
|
|
LOG((" *1 %10lu undef (%s)",
|
|
addr, displ_undefs(nundef, addr)));
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/* Service routines */
|
|
|
|
PRIVATE int std_bytes(ptr low, ptr high, int bits)
|
|
{
|
|
/* True if all stack bytes from low to high-1 have one of the
|
|
bits in bits on.
|
|
*/
|
|
int byte = bits;
|
|
|
|
while (low < high) {
|
|
byte &= st_sh(low);
|
|
low++;
|
|
}
|
|
|
|
return byte & bits;
|
|
}
|
|
|
|
PRIVATE int dtd_bytes(ptr low, ptr high, int bits)
|
|
{
|
|
/* True if all data bytes from low to high-1 have one of the
|
|
bits in bits on.
|
|
*/
|
|
int byte = bits;
|
|
|
|
while (low < high) {
|
|
byte &= dt_sh(low);
|
|
low++;
|
|
}
|
|
|
|
return byte & bits;
|
|
}
|
|
|
|
PRIVATE int FRAd_bytes(int low, int high, int bits)
|
|
{
|
|
/* True if all data bytes from low to high-1 have one of the
|
|
bits in bits on.
|
|
*/
|
|
int byte = bits;
|
|
|
|
while (low < high) {
|
|
byte &= FRA_sh[low];
|
|
low++;
|
|
}
|
|
|
|
return byte & bits;
|
|
}
|
|
|
|
PRIVATE char *displ_undefs(int nundef, ptr addr)
|
|
{
|
|
/* Given the number of undefineds, we want to report the number
|
|
of words with the left-over numbers of bytes on both sides:
|
|
| nundef |
|
|
|left| wrds |right
|
|
.....|........|........|........|...
|
|
a
|
|
d
|
|
d
|
|
r
|
|
This takes some arithmetic.
|
|
*/
|
|
static char buf[30];
|
|
register int left = wsize - 1 - p2i(addr-1) % wsize;
|
|
register int wrds = (nundef-left) / wsize;
|
|
register int right = nundef - left - wrds*wsize;
|
|
|
|
if (wrds == 0) {
|
|
sprintf(buf, "%d byte%s",
|
|
nundef, nundef == 1 ? "" : "s");
|
|
}
|
|
else if (left == 0 && right == 0) {
|
|
sprintf(buf, "%d word%s",
|
|
wrds, wrds == 1 ? "" : "s");
|
|
}
|
|
else if (left == 0) {
|
|
sprintf(buf, "%d word%s + %d byte%s",
|
|
wrds, wrds == 1 ? "" : "s",
|
|
right, right == 1 ? "" : "s");
|
|
}
|
|
else if (right == 0) {
|
|
sprintf(buf, "%d byte%s + %d word%s",
|
|
left, left == 1 ? "" : "s",
|
|
wrds, wrds == 1 ? "" : "s");
|
|
}
|
|
else {
|
|
sprintf(buf, "%d byte%s + %d word%s + %d byte%s",
|
|
left, left == 1 ? "" : "s",
|
|
wrds, wrds == 1 ? "" : "s",
|
|
right, right == 1 ? "" : "s");
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
PRIVATE char *displ_fil(ptr fil)
|
|
{ /* Returns a buffer containing a representation of the
|
|
filename derived from FIL-value fil.
|
|
*/
|
|
static char buf[40];
|
|
char *bp = &buf[0];
|
|
int ch;
|
|
|
|
if (!fil)
|
|
return "NULL";
|
|
if (fil >= HB)
|
|
return "***NOT IN GDA***";
|
|
|
|
*bp++ = '"';
|
|
while (in_gda(fil) && (ch = data_loc(fil))) {
|
|
if (bp < &buf[sizeof buf-1]) {
|
|
*bp++ = (ch < 040 || ch > 126 ? '?' : ch);
|
|
}
|
|
fil++;
|
|
}
|
|
if (bp < &buf[sizeof buf-1])
|
|
*bp++ = '"';
|
|
*bp++ = '\0';
|
|
return &buf[0];
|
|
}
|
|
|
|
PRIVATE char *displ_sh(char shadow, int byte)
|
|
{ /* Returns a buffer containing a description of the
|
|
shadow byte.
|
|
*/
|
|
static char buf[32];
|
|
register char *bufp;
|
|
int check = 0;
|
|
|
|
bufp = buf;
|
|
if (shadow & SH_INT) {
|
|
*bufp++ = 'I';
|
|
*bufp++ = 'n';
|
|
check++;
|
|
}
|
|
if (shadow & SH_FLOAT) {
|
|
*bufp++ = 'F';
|
|
*bufp++ = 'l';
|
|
}
|
|
if (shadow & SH_DATAP) {
|
|
*bufp++ = 'D';
|
|
*bufp++ = 'p';
|
|
}
|
|
if (shadow & SH_INSP) {
|
|
*bufp++ = 'I';
|
|
*bufp++ = 'p';
|
|
}
|
|
|
|
if (shadow & SH_PROT) {
|
|
*bufp++ = ',';
|
|
*bufp++ = ' ';
|
|
*bufp++ = 'P';
|
|
*bufp++ = 'r';
|
|
*bufp++ = 'o';
|
|
*bufp++ = 't';
|
|
}
|
|
|
|
if (check && isascii(byte) && isprint(byte)) {
|
|
*bufp++ = ',';
|
|
*bufp++ = ' ';
|
|
*bufp++ = byte;
|
|
*bufp++ = ' ';
|
|
}
|
|
*bufp = 0;
|
|
return (buf);
|
|
}
|
|
|
|
#endif /* LOGGING */
|
|
|