Stack traces: Difference between revisions

From Rosetta Code
Content added Content deleted
(added php)
(Ada solution added)
Line 4: Line 4:
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.
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.
<br clear=all>
<br clear=all>
=={{header|Ada}}==
{{works with|GNAT}}

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:
<pre>
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
</pre>
=={{header|C}}==
=={{header|C}}==
{{works with|POSIX}}
{{works with|POSIX}}

Revision as of 07:37, 6 June 2009

Task
Stack traces
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.

Ada

Works with: GNAT

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

C

Works with: POSIX
Works with: GNU

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>

  1. include <stdlib.h>
  2. include <unistd.h>
  1. include <execinfo.h>
  1. 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]

Java

Works with: Java version 5.0

<lang java>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 >= 1 ; i--, j+=2) { System.out.printf("%" + j + "s%s.%s%n", "", elems[i].getClassName(), elems[i].getMethodName()); }

   }

}</lang>

PHP

<lang php>debug_print_backtrace();</lang>

Python

see the traceback module <lang python>import traceback

traceback.print_stack()</lang>

Ruby

<lang ruby>begin

 raise "boom"

rescue => detail

 puts detail.backtrace.join("\n")

end</lang>

Smalltalk

Works with: GNU 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.</lang>

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