Stack traces: Difference between revisions
Added Oz. |
Added Forth |
||
Line 246: | Line 246: | ||
SBCL's backtraces consist entirely of lists of the form <code>(<var>function-name</var> <var>args...</var>)</code>. |
SBCL's backtraces consist entirely of lists of the form <code>(<var>function-name</var> <var>args...</var>)</code>. |
||
=={{header|Forth}}== |
|||
In Forth, calling sequence information is kept on the Return Stack.Some Forth compilers have the word "R.S" that dumps the contents of the Return Stack - just like ".S:, which dumps the contents of the Data Stack. Note this may also include stack frames, local variables and temporary values. Forth has no way of knowing which is which, because that is usually left to the programmer. |
|||
{{works with|4tH|3.60.0}} |
|||
<lang forth>[UNDEFINED] R.S [IF] |
|||
\ Return stack counterpart of DEPTH |
|||
\ Note the STACK-CELLS correction is there to hide RDEPTH itself |
|||
( -- n) |
|||
: RDEPTH STACK-CELLS -2 [+] CELLS RP@ - ; |
|||
\ Return stack counterpart of .S |
|||
\ Note the : R.S R> .. >R ; sequence is there to hide R.S itself |
|||
( --) |
|||
: R.S R> CR RDEPTH DUP 0> IF DUP |
|||
BEGIN DUP WHILE R> -ROT 1- REPEAT DROP DUP |
|||
BEGIN DUP WHILE ROT DUP . >R 1- REPEAT DROP |
|||
THEN ." (TORS) " DROP >R ; |
|||
[THEN]</lang> |
|||
=={{header|J}}== |
=={{header|J}}== |
||
Revision as of 18:17, 22 February 2010
You are encouraged to solve this task according to the task description, using any language you may know.
Many programming languages allow for introspection of the current call stack environment. This can be for a variety of purposes such as enforcing security checks, debugging, or for getting access to the stack frame of callers.
This task calls for you to print out (in a manner considered suitable for the platform) the current call stack. The amount of information printed for each frame on the call stack is not constrained, but should include at least the name of the function or method at that level of the stack frame. You may explicitly add a call to produce the stack trace to the (example) code being instrumented for examination.
The task should allow the program to continue after generating the stack trace. The task report here must include the trace from a sample program.
Ada
The provided solution is specific to the GNAT Ada compiler. Further it is restricted to some platforms. See the description of the package GNAT.Traceback supplied with GNAT. The switch -g must be used in order to include debug information into the executable. <lang Ada>with Ada.Text_IO; use Ada.Text_IO; with GNAT.Traceback; use GNAT.Traceback; with GNAT.Traceback.Symbolic; use GNAT.Traceback.Symbolic;
procedure Test_Stack_Trace is
procedure Call_Stack is Trace : Tracebacks_Array (1..1_000); Length : Natural; begin Call_Chain (Trace, Length); Put_Line (Symbolic_Traceback (Trace (1..Length))); end Call_Stack;
procedure Inner (K : Integer) is begin Call_Stack; end Inner; procedure Middle (X, Y : Integer) is begin Inner (X * Y); end Middle; procedure Outer (A, B, C : Integer) is begin Middle (A + B, B + C); end Outer;
begin
Outer (2,3,5);
end Test_Stack_Trace;</lang> Sample output:
00417D7F in ?? at cygming-crtend.c:0 00401A61 in test_stack_trace.call_stack at test_stack_trace.adb:10 00401A25 in test_stack_trace.inner at test_stack_trace.adb:16 00401A0C in test_stack_trace.middle at test_stack_trace.adb:21 0040193E in test_stack_trace.outer at test_stack_trace.adb:26 004018A2 in _ada_test_stack_trace at test_stack_trace.adb:30 004016BE in main at b~test_stack_trace.adb:183 00401235 in ?? at cygming-crtend.c:0 00401286 in ?? at cygming-crtend.c:0 7C817075 in ?? at ??:0
AutoHotkey
The local, static, and global bindings are viewable using 'Listvars'
recently executed lines are available through ListLines
ListLines can be turned on or off... with:
ListLines, On|Off
<lang autohotkey>f()
return
f() { return g() }
g() { ListLines msgbox, lines recently executed x = local to g ListVars msgbox, variable bindings }
- Persistent</lang>
BASIC
On Beta BASIC and SAM BASIC, the call stack is used for procedure calls, GOSUBs and DO loops. The stack contains return addresses as line and statement numbers. (The parameters for procedures are stored in another stack.) POP statement can be used to pop the return address from the stack.
The following procedure pops the return addrsses from the stack and lists the corresponding lines where the call occurred. Since it is not possible to push the addresses back into the stack, it is not possible to continue the normal flow of execution after displaying the stack. However, it is possible to continue the program otherwise. If the program execution stops on error, it is possible to display the call stack by typing callstack in command mode.
100 DEF PROC callstack 110 ON ERROR GOTO 1000 120 FOR i=1 TO 100 130 POP lnum 140 LIST lnum TO lnum 150 NEXT i 190 END PROC 1000 PRINT "End of stack" 1010 STOP
Example usage. An error is generated on line 320, which causes branch to error handler on line 1100. The error handler displays error number followed by call stack.
200 DEF PROC foo count 210 PRINT "foo "; 220 IF count > 1 230 foo count-1 240 ELSE 250 bar 260 END IF 290 END PROC 300 DEF PROC bar 310 PRINT "bar" 320 x = 1/0 390 END PROC 500 ON ERROR GOTO 1100 510 foo 3 520 STOP 1100 PRINT "Error "; error; " on line "; lino 1110 PRINT "Callstack:" 1120 callstack 1130 STOP
Output:
foo foo foo bar Error 28 on line 320 Call stack: 1120 callstack 320 x = 1/0 250 bar 230 foo count-1 230 foo count-1 510 foo 3 End of stack
C
The backtrace* functions are a GNU extension to the standard C library.
In order to be able to see the symbols, we need to link with an option telling to export symbols names in the dynamic section (for ELF and targets supporting it); for gcc, it means using the option -rdynamic (or -export-dynamic in the GNU linker). Otherwise we see only addresses. Static functions will always have their names "hidden".
<lang c>#include <stdio.h>
- include <stdlib.h>
- include <unistd.h>
- include <execinfo.h>
- define MAX_BT 200
void print_stack_trace() {
void *buffer[MAX_BT]; int n;
n = backtrace(buffer, MAX_BT); fprintf(stderr, "--- (depth %d) ---\n", n); backtrace_symbols_fd(buffer, n, STDERR_FILENO);
}
void inner(int k)
{
print_stack_trace();
}
void middle(int x, int y) {
inner(x*y);
}
void outer(int a, int b, int c) {
middle(a+b, b+c);
}
int main() {
outer(2,3,5); return EXIT_SUCCESS;
}</lang>
Sample output on my system:
--- (depth 7) --- ./pst(print_stack_trace+0x1f)[0x8048683] ./pst(inner+0xb)[0x80486cd] ./pst(middle+0x15)[0x80486e4] ./pst(outer+0x23)[0x8048709] ./pst(main+0x2d)[0x8048738] /lib/i686/libc.so.6(__libc_start_main+0xe5)[0xb7e045c5] ./pst[0x80485d1]
Common Lisp
Stack trace facilities are not specified by the Common Lisp standard. Implementations vary widely in the amount of information provided, how it can be retrieved, and the amount of internal implementation detail included.
Here we use SWANK, which a component of SLIME, a Common Lisp IDE (it is the library loaded into the target Lisp system to enable interaction and remote debugging), to make use of its portable debugging facilities:
<lang lisp>(swank-backend:call-with-debugging-environment
(lambda () (swank:backtrace 0 nil)))</lang>
Here are a few lines of the result when running under SBCL, the rest is omitted since it's long and boring: <lang lisp>((0 "((LAMBDA (SWANK-BACKEND::DEBUGGER-LOOP-FN)) #<FUNCTION (LAMBDA #) {100459BBC9}>)")
(1 "(SB-INT:SIMPLE-EVAL-IN-LEXENV (SWANK-BACKEND:CALL-WITH-DEBUGGING-ENVIRONMENT (LAMBDA () (SWANK:BACKTRACE 0 NIL))) #<NULL-LEXENV>)") (2 "(SWANK::EVAL-REGION \"(swank-backend:call-with-debugging-environment\\n (lambda ()\\n (swank:backtrace 0 nil)))\\n\\n\")") (3 "((LAMBDA ()))") ...)</lang>
Note that this is a data structure containing the backtrace, not a format intended for presentation. In SBCL, executing (sb-debug:backtrace 7)
produces output like this (run from the SLIME-REPL, which is why it still contains mentions of SWANK):
<lang lisp>CL-USER> (sb-debug:backtrace 7) 0: (SB-DEBUG::MAP-BACKTRACE
#<CLOSURE (LAMBDA (SB-DEBUG::FRAME)) {1193EFCD}>)[:EXTERNAL]
1: (BACKTRACE
7 #<TWO-WAY-STREAM :INPUT-STREAM #<SWANK-BACKEND::SLIME-INPUT-STREAM {120F6519}> :OUTPUT-STREAM #<SWANK-BACKEND::SLIME-OUTPUT-STREAM {1208F3E1}>>)
2: (SB-INT:SIMPLE-EVAL-IN-LEXENV (BACKTRACE 7) #<NULL-LEXENV>) 3: (SWANK::EVAL-REGION
"(sb-debug:backtrace 7)
") 4: ((LAMBDA ())) 5: (SWANK::TRACK-PACKAGE #<CLOSURE (LAMBDA ()) {1193ECBD}>) 6: (SWANK::CALL-WITH-RETRY-RESTART
"Retry SLIME REPL evaluation request." #<CLOSURE (LAMBDA ()) {1193EC4D}>)</lang>
SBCL's backtraces consist entirely of lists of the form (function-name args...)
.
Forth
In Forth, calling sequence information is kept on the Return Stack.Some Forth compilers have the word "R.S" that dumps the contents of the Return Stack - just like ".S:, which dumps the contents of the Data Stack. Note this may also include stack frames, local variables and temporary values. Forth has no way of knowing which is which, because that is usually left to the programmer.
<lang forth>[UNDEFINED] R.S [IF] \ Return stack counterpart of DEPTH \ Note the STACK-CELLS correction is there to hide RDEPTH itself
( -- n)
- RDEPTH STACK-CELLS -2 [+] CELLS RP@ - ;
\ Return stack counterpart of .S \ Note the : R.S R> .. >R ; sequence is there to hide R.S itself
( --)
- R.S R> CR RDEPTH DUP 0> IF DUP
BEGIN DUP WHILE R> -ROT 1- REPEAT DROP DUP BEGIN DUP WHILE ROT DUP . >R 1- REPEAT DROP THEN ." (TORS) " DROP >R ;
[THEN]</lang>
J
J's stack can be accessed only when suspension has been enabled. When suspension has not been enabled, break points will not work, errors will bubble out to the top level, and the stack data structure will not be available.
To enable suspension and record subsequent stack frames: <lang j> 13!:0]1</lang>
To retrieve a current stack trace: <lang j> 13!:13</lang>
See also: http://www.jsoftware.com/help/dictionary/dx013.htm
Java
<lang java5>public class StackTracer {
public static void printStackTrace() {
StackTraceElement[] elems = Thread.currentThread().getStackTrace();
System.out.println("Stack trace:"); for (int i = elems.length-1, j = 2 ; i >= 3 ; i--, j+=2) { System.out.printf("%" + j + "s%s.%s%n", "", elems[i].getClassName(), elems[i].getMethodName()); }
}
}</lang> Demonstration code: <lang java5>public class StackTraceDemo {
static void inner() {
StackTracer.printStackTrace();
} static void middle() {
inner();
} static void outer() {
middle();
} public static void main(String[] args) {
outer();
}
}</lang> Output:
Stack trace: StackTraceDemo.main StackTraceDemo.outer StackTraceDemo.middle StackTraceDemo.inner
JavaScript
There is no standard way to do this, but some implementations provide it.
<lang javascript>try {
throw new Error;
} catch(e) {
alert(e.stack);
}</lang>
<lang javascript>try {
throw new Error;
} catch(e) {
alert(e.message);
}</lang> The following version works in many browsers but it infinitely loops when there is recursion: <lang javascript>function foo () {
var stack = "Stack trace:"; for (var f = arguments.callee // current function ; f; f = f.caller) { stack += "\n" + f.name; } alert(stack);
} foo();</lang>
Mathematica
Built-in function Stack does the task, example I: <lang Mathematica>f[g[1, Print[Stack[]]; 2]]</lang> prints, gives back: <lang Mathematica>{f,g,CompoundExpression,Print} f[g[1, 2]]</lang> Example II: <lang Mathematica>f[g[1, Print[Stack[_]]; 2]]</lang> prints, gives back: <lang Mathematica>{f[g[1,Print[Stack[_]];2]],g[1,Print[Stack[_]];2],Print[Stack[_]];2,Print[Stack[_]]} f[g[1, 2]]</lang> Related and similar functions are: Trace, TracePrint, TraceScan,TraceDialog, Monitor, StackInhibit, StackBegin, StackComplete. In the manual look for 'guide/SymbolicExecutionHistory'.
OCaml
<lang ocaml>let div a b = a / b
let () =
try let _ = div 3 0 in () with e -> prerr_endline(Printexc.to_string e); Printexc.print_backtrace stderr;
- </lang>
outputs:
Division_by_zero Raised by primitive operation at file "test.ml", line 4, characters 14-21
By Environment Variable
Another way is to set the environment variable OCAMLRUNPARAM to b, for example you can add in your ~/.bashrc file this line:
export OCAMLRUNPARAM='b'
Then the code doesn't need additionnal statements: <lang ocaml>let div a b = a / b
let () =
let _ = div 3 0 in ()
- </lang>
outputs:
Fatal error: exception Division_by_zero Raised at file "test.ml", line 4, characters 10-17
Oz
System exceptions contain the current stack at the nested feature debug.stack
. For example:
<lang oz>declare
proc {Test} _ = 1 div 0 end
in
try {Test} catch E then {Inspect E} end</lang>
Output:
To have such a stack trace in custom exceptions, either indicate this by throwing a record value with a debug:unit
feature or use the Exception module to create exceptions.
To access the stack trace directly, you can use the undocumented internal Debug module. Its getTaskStack
function takes a thread, a depth value and a boolean "verbose" flag. It returns a list of stack frames. Example:
<lang oz>%% make sure that simple function calls are not optimized away
\switch +controlflowinfo
declare
[Debug] = {Link ['x-oz://boot/Debug']}
proc {F} {G} end
proc {G} {H} end
proc {H} {Inspect {Debug.getTaskStack {Thread.this} 100 true}} end
in
{F}</lang>
Output:
Perl
<lang perl>use Carp 'cluck';
sub g {cluck 'Hello from &g';} sub f {g;}
f;</lang>
This prints:
Hello from &g at Print a Stack Trace line 3 main::g() called at Print a Stack Trace line 4 main::f() called at Print a Stack Trace line 6
PHP
<lang php><?php class StackTraceDemo {
static function inner() { debug_print_backtrace(); } static function middle() { self::inner(); } static function outer() { self::middle(); }
}
StackTraceDemo::outer(); ?></lang>
#0 StackTraceDemo::inner() called at [/home/cweiske/Dev/cvs/test/php-stacktrace.php:7] #1 StackTraceDemo::middle() called at [/home/cweiske/Dev/cvs/test/php-stacktrace.php:10] #2 StackTraceDemo::outer() called at [/home/cweiske/Dev/cvs/test/php-stacktrace.php:14]
Python
See the traceback module <lang python>import traceback
def f(): return g() def g(): traceback.print_stack()
f()</lang>
Sample output from a session in the Idle IDE:
File "<string>", line 1, in <module> File "C:\Python26\lib\idlelib\run.py", line 93, in main ret = method(*args, **kwargs) File "C:\Python26\lib\idlelib\run.py", line 293, in runcode exec code in self.locals File "C:/Documents and Settings/All Users/Documents/Paddys/traceback.py", line 6, in <module> f() File "C:/Documents and Settings/All Users/Documents/Paddys/traceback.py", line 3, in f def f(): return g() File "C:/Documents and Settings/All Users/Documents/Paddys/traceback.py", line 4, in g def g(): traceback.print_stack()
R
<lang R>foo <- function() {
bar <- function() { sys.calls() } bar()
}
foo()</lang>
[[1]] foo() [[2]] bar()
traceback() returns the callstack of the last unhandled (i.e. not in try/catch) error.
You can also see the stack trace when a function is called (or as it exits) using the trace function. <lang R>trace("foo", recover) foo()</lang>
Tracing foo() on entry Enter a frame number, or 0 to exit 1: foo() Selection:
Ruby
<lang ruby>def outer(a,b,c)
middle a+b, b+c
end
def middle(d,e)
inner d+e
end
def inner(f)
puts caller(0) puts "continuing... my arg is #{f}"
end
outer 2,3,5</lang>
$ ruby stacktrace.rb stacktrace.rb:10:in `inner' stacktrace.rb:6:in `middle' stacktrace.rb:2:in `outer' stacktrace.rb:14 continuing... my arg is 13
Exceptions caught in a rescue clause contain the trace information: <lang ruby>def outer(a,b,c)
middle a+b, b+c
end
def middle(d,e)
inner d+e
end
def inner(f)
raise puts "this will not be printed"
end
begin
outer 2,3,5
rescue Exception => e
puts e.backtrace
end puts "continuing after the rescue..."</lang>
stacktrace.rb:10:in `inner' stacktrace.rb:6:in `middle' stacktrace.rb:2:in `outer' stacktrace.rb:15 continuing after the rescue...
Scala
While the code on the Java example works with Scala too, the code below is an alternative. Which, by the way, could be used from Java as well, with minor modifications.
<lang scala>def callStack = try { error("exception") } catch { case ex => ex.getStackTrace drop 2 }
def printStackTrace = callStack drop 1 /* don't print ourselves! */ foreach println</lang>
Usage example:
scala> def f1 = printStackTrace f1: Unit scala> def f2 = f1 f2: Unit scala> def f3 = f2 f3: Unit scala> f3 line40$object$$iw$$iw$.f1(<console>:6) line41$object$$iw$$iw$.f2(<console>:7) line42$object$$iw$$iw$.f3(<console>:8) line43$object$$iw$$iw$.<init>(<console>:10) line43$object$$iw$$iw$.<clinit>(<console>) RequestResult$line43$object$.<init>(<console>:4) RequestResult$line43$object$.<clinit>(<console>) RequestResult$line43$object.result(<console>) sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) java.lang.reflect.Method.invoke(Method.java:597) scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$13.apply(Interpreter.scala:788) scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$13.apply(Interpreter.scala:788) scala.util.control.Exception$Catch.apply(Exception.scala:79) scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1.apply(Interpreter.scala:787) scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1.apply(Interpreter.scala:787) scala.util.control.Exception$Catch.apply(Exception.scala:79) scala.tools.nsc.Interpreter$Request.loadAndRun(Interpreter.scala:786) scala.tools.nsc.Interpreter.interpret(Interpreter.scala:435) scala.tools.nsc.Interpreter.interpret(Interpreter.scala:425) scala.tools.nsc.InterpreterLoop.interpretStartingWith(InterpreterLoop.scala:331) scala.tools.nsc.InterpreterLoop.command(InterpreterLoop.scala:308) scala.tools.nsc.InterpreterLoop.processLine$1(InterpreterLoop.scala:205) scala.tools.nsc.InterpreterLoop.repl(InterpreterLoop.scala:223) scala.tools.nsc.InterpreterLoop.main(InterpreterLoop.scala:379) scala.tools.nsc.MainGenericRunner$.createLoop$1(MainGenericRunner.scala:119) scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:144) scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
Note that the stack is an array of StackTraceElement, on which it is possible to get the class and method name as well as the file name and line number of its definition.
Slate
The following #printCurrentStack is already defined in the base slate image but it is replicated here.
<lang slate>slate[1]> d@(Debugger traits) printCurrentStack &limit: limit &stream: out &showLocation: showLocation [
d clone `>> [baseFramePointer: (d interpreter framePointerOf: #printCurrentStack). buildFrames. printBacktrace &limit: limit &stream: out &showLocation: showLocation ]
]. Defining function 'printCurrentStack' on: 'Debugger traits' [printCurrentStack &limit: &stream: &showLocation:]</lang>
The output from calling the function:
<lang slate>slate[2]> Debugger printCurrentStack. Backtrace (method @ source): frame: 0 [printCurrentStack &limit: &stream: &showLocation:] @ stdin:0 frame: 1 [evaluateIn: &optionals:] @ src/mobius/syntax.slate:180 frame: 2 [(arity: 0)] @ src/lib/repl.slate:155 frame: 3 [on:do:] @ src/core/condition.slate:43 frame: 4 [(arity: 0)] @ src/lib/repl.slate:147 frame: 5 [handlingCases:] @ src/core/condition.slate:64 frame: 6 [interpretHook:] @ src/lib/repl.slate:42 frame: 7 [(arity: 0)] @ src/lib/repl.slate:139 frame: 8 [enter] @ src/lib/repl.slate:135 frame: 9 [start &resource:] @ src/lib/repl.slate:185 frame: 10 [start] @ src/mobius/prelude.slate:38 Nil</lang>
Smalltalk
A backtrace is normally sent when some error occurs; however, it can be "forced":
<lang smalltalk>Object subclass: Container [
Container class >> outer: a and: b and: c [ self middle: (a+b) and: (b+c) ] Container class >> middle: x and: y [ self inner: (x*y) ] Container class >> inner: k [ Smalltalk backtrace ]
].
Container outer: 2 and: 3 and: 5.
'Anyway, we continue with it' displayNl.</lang>
Output:
Container class>>inner: Container class>>middle:and: Container class>>outer:and:and: UndefinedObject>>executeStatements Anyway, we continue with it
Tcl
<lang tcl>proc printStackTrace {} {
puts "Stack trace:" for {set i 1} {$i < [info level]} {incr i} { puts [string repeat " " $i][info level $i] }
}</lang> Demonstration code: <lang tcl>proc outer {a b c} {
middle [expr {$a+$b}] [expr {$b+$c}]
} proc middle {x y} {
inner [expr {$x*$y}]
} proc inner k {
printStackTrace
} outer 2 3 5</lang> Produces this output:
Stack trace: outer 2 3 5 middle 5 8 inner 40