2004-04-11 03:42:27 +00:00
|
|
|
.TH MACH-STACK 3
|
|
|
|
.SH NAME
|
2005-01-03 06:40:20 +00:00
|
|
|
stacktrace, localaddr, unwindframe, windindex, windreglocs \- stack traces
|
2004-04-11 03:42:27 +00:00
|
|
|
.SH SYNOPSIS
|
|
|
|
.B #include <u.h>
|
|
|
|
.br
|
|
|
|
.B #include <libc.h>
|
|
|
|
.br
|
|
|
|
.B #include <mach.h>
|
|
|
|
.PP
|
|
|
|
.ft B
|
|
|
|
.ta \w'\fBxxxxxx'u +\w'\fBxxxxxx'u
|
|
|
|
int stacktrace(Map *map, Rgetter rget, Tracer trace)
|
|
|
|
.PP
|
|
|
|
.ft B
|
2005-01-03 06:40:20 +00:00
|
|
|
int localaddr(Map *map, Regs *regs, char *fn, char *val, ulong *val)
|
|
|
|
.PP
|
|
|
|
.ft B
|
|
|
|
int unwindframe(Map *map, Regs *regs, ulong *next, Symbol *sym)
|
|
|
|
.PP
|
|
|
|
.ft B
|
|
|
|
int windindex(char *regname)
|
|
|
|
.PP
|
|
|
|
.ft B
|
|
|
|
Loc* windreglocs(void)
|
2004-04-11 03:42:27 +00:00
|
|
|
.SH DESCRIPTION
|
|
|
|
.I Stacktrace
|
|
|
|
provides machine-independent
|
|
|
|
implementations of process stack traces.
|
|
|
|
They must retrieve data and register contents from an executing
|
|
|
|
image. Sometimes the desired registers are not the current
|
|
|
|
registers but rather a set of saved registers stored elsewhere
|
|
|
|
in memory.
|
|
|
|
The caller may specify an initial register set in the form of an
|
|
|
|
.I Rgetter
|
|
|
|
function, of the form
|
|
|
|
.PP
|
|
|
|
.RS
|
|
|
|
.B "ulong rget(Map *map, char *name)
|
|
|
|
.RE
|
|
|
|
.PP
|
|
|
|
It returns the contents of a register when given a map
|
|
|
|
and a register name.
|
|
|
|
It is usually sufficient for the register function
|
|
|
|
to return meaningful values only for
|
|
|
|
.BR SP
|
|
|
|
and
|
|
|
|
.BR PC ,
|
|
|
|
and for the link register
|
|
|
|
(usually
|
|
|
|
.BR LR )
|
|
|
|
on CISC machines.
|
|
|
|
.PP
|
|
|
|
Given the map and the rgetter,
|
|
|
|
.I stacktrace
|
|
|
|
unwinds the stack starting at the innermost function.
|
|
|
|
At each level in the trace, it calls the tracer function, which has the form
|
|
|
|
.PP
|
|
|
|
.RS
|
|
|
|
.B "int trace(Map *map, ulong pc, ulong callerpc,
|
|
|
|
.br
|
|
|
|
.B " Rgetter rget, Symbol *s)
|
|
|
|
.RE
|
|
|
|
.PP
|
|
|
|
The tracer is passed the map, the current program counter,
|
|
|
|
the program counter of the caller (zero if the caller is unknown),
|
|
|
|
a new
|
|
|
|
.I rget
|
|
|
|
function, and a symbol
|
|
|
|
(see
|
2020-08-16 00:07:38 +00:00
|
|
|
.MR mach-symbol (3) )
|
2004-04-11 03:42:27 +00:00
|
|
|
describing the current function
|
|
|
|
(nil if no symbol is known).
|
|
|
|
The value returned by the tracer
|
|
|
|
controls whether the stack trace continues:
|
|
|
|
a zero or negative return value stops the trace,
|
|
|
|
while a positive return value continues it.
|
|
|
|
.PP
|
|
|
|
The rgetter passed to the tracer is not the rgetter
|
|
|
|
passed to
|
|
|
|
.B stacktrace
|
|
|
|
itself.
|
|
|
|
Instead, it is a function returning the register values
|
|
|
|
at the time of the call, to the extent that they can be
|
|
|
|
reconstructed.
|
|
|
|
The most common use for this rgetter
|
|
|
|
is as an argument to
|
|
|
|
.IR lget4 ,
|
|
|
|
etc., when evaluating the locations of local variables.
|
|
|
|
.PP
|
2005-01-03 06:40:20 +00:00
|
|
|
.I Localaddr
|
2004-04-11 03:42:27 +00:00
|
|
|
uses
|
|
|
|
.I stacktrace
|
|
|
|
to walk up the stack looking for the innermost instance of a function named
|
|
|
|
.I fn ;
|
|
|
|
once it finds the function,
|
|
|
|
it looks for the parameter or local variable
|
|
|
|
.IR var ,
|
2005-01-03 06:40:20 +00:00
|
|
|
storing the address of the variable in
|
|
|
|
.IR val .
|
|
|
|
.PP
|
|
|
|
.I Unwindframe
|
|
|
|
is the low-level function on which
|
|
|
|
.I stacktrace
|
|
|
|
is built.
|
|
|
|
Given the current memory image in
|
|
|
|
.I map
|
|
|
|
and the current register set in
|
|
|
|
.I regs ,
|
|
|
|
.I unwindframe
|
|
|
|
fills in
|
|
|
|
.I next
|
|
|
|
with the values of the register set
|
|
|
|
at the time of the call to the function in the current program counter.
|
|
|
|
.I Sym
|
|
|
|
should be the symbol corresponding to the current function,
|
|
|
|
if available.
|
|
|
|
.PP
|
|
|
|
The
|
|
|
|
.I next
|
|
|
|
array holds only the
|
|
|
|
.IR "winding registers" ,
|
|
|
|
typically the caller-save registers and the program counter and stack pointer.
|
|
|
|
The order of registers in the array is called the
|
|
|
|
.IR "winding order" .
|
|
|
|
The winding set can be found in the array
|
|
|
|
.IB mach -> windreg \fR,
|
|
|
|
which has
|
|
|
|
.IB mach -> nwindreg
|
|
|
|
entries.
|
|
|
|
.I Windindex
|
|
|
|
returns the index of the named register
|
|
|
|
in the winding order.
|
|
|
|
.I Windreglocs
|
|
|
|
returns an array of
|
|
|
|
.I Loc
|
|
|
|
structures corresponding to the winding registers,
|
|
|
|
in the winding order.
|
2004-04-11 03:42:27 +00:00
|
|
|
.SH EXAMPLE
|
|
|
|
The following code writes a simple stack trace to standard output,
|
|
|
|
stopping after at most 20 stack frames.
|
|
|
|
.RS
|
|
|
|
.ft B
|
|
|
|
.nf
|
|
|
|
.ta \w'xxxx'u +\w'xxxx'u +\w'xxxx'u +\w'xxxx'u +\w'xxxx'u
|
|
|
|
static int
|
|
|
|
trace(Map *map, ulong pc, ulong callerpc,
|
|
|
|
Rgetter rget, Symbol *s, int depth)
|
|
|
|
{
|
|
|
|
char buf[512];
|
|
|
|
int i, first;
|
|
|
|
u32int v;
|
|
|
|
Symbol s2;
|
|
|
|
|
|
|
|
if(sym)
|
|
|
|
print("%s+%lx", s->name, pc - loceval(s->loc));
|
|
|
|
else
|
|
|
|
print("%lux", pc);
|
|
|
|
print("(");
|
|
|
|
first = 0;
|
|
|
|
for(i=0; indexlsym(s, &i, &s2)>=0; i++){
|
|
|
|
if(s.class != CPARAM)
|
|
|
|
continue;
|
|
|
|
if(first++)
|
|
|
|
print(", ");
|
|
|
|
if(lget4(map, rget, s->loc, &v) >= 0)
|
|
|
|
print("%s=%#lux", s->name, (ulong)v);
|
|
|
|
else
|
|
|
|
print("%s=???", s->name);
|
|
|
|
}
|
|
|
|
print(") called from ");
|
|
|
|
symoff(buf, sizeof buf, callerpc, CTEXT);
|
|
|
|
print("%s\en", buf);
|
|
|
|
return depth < 20;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(stacktrace(map, nil, trace) <= 0)
|
|
|
|
print("no stack frame\n");
|
|
|
|
.RE
|
|
|
|
.SH SOURCE
|
2005-01-11 17:37:33 +00:00
|
|
|
.B \*9/src/libmach
|
2004-04-11 03:42:27 +00:00
|
|
|
.SH SEE ALSO
|
2020-08-16 00:07:38 +00:00
|
|
|
.MR mach (3)
|
2005-01-03 06:40:20 +00:00
|
|
|
.SH BUGS
|
|
|
|
Need to talk about Regs
|