mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-12 11:10:07 +00:00
137 lines
3.1 KiB
Groff
137 lines
3.1 KiB
Groff
.TH MACH-STACK 3
|
|
.SH NAME
|
|
stacktrace,
|
|
localaddr,
|
|
.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
|
|
int localvar(Map *map, char *fn, char *val, Loc *loc)
|
|
.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
|
|
.IR mach-symbol (3))
|
|
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
|
|
.I Localvar
|
|
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 ,
|
|
storing the location of the variable in
|
|
.IR loc .
|
|
.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
|
|
.B /usr/local/plan9/src/libmach
|
|
.SH SEE ALSO
|
|
.IR mach (3)
|