1#!/usr/bin/tclsh
2#
3# Parse the output of
4#
5#         objdump -d sqlite3.o
6#
7# for x64 and generate a report showing:
8#
9#    (1)  Stack used by each function
10#    (2)  Recursion paths and their aggregate stack depth
11#
12set getStack 0
13while {![eof stdin]} {
14  set line [gets stdin]
15  if {[regexp {^[0-9a-f]+ <([^>]+)>:\s*$} $line all procname]} {
16    set curfunc $procname
17    set root($curfunc) 1
18    set calls($curfunc) {}
19    set calledby($curfunc) {}
20    set recursive($curfunc) {}
21    set stkdepth($curfunc) 0
22    set getStack 1
23    continue
24  }
25  if {[regexp {callq? +[0-9a-z]+ <([^>]+)>} $line all other]} {
26    set key [list $curfunc $other]
27    set callpair($key) 1
28    unset -nocomplain root($curfunc)
29    continue
30  }
31  if {[regexp {sub +\$(0x[0-9a-z]+),%[er]sp} $line all xdepth]} {
32    if {$getStack} {
33      scan $xdepth %x depth
34      set stkdepth($curfunc) $depth
35      set getStack 0
36    }
37    continue
38  }
39}
40
41puts "****************** Stack Usage By Function ********************"
42set sdlist {}
43foreach f [array names stkdepth] {
44  lappend sdlist [list $stkdepth($f) $f]
45}
46foreach sd [lsort -integer -decr -index 0 $sdlist] {
47  foreach {depth fname} $sd break
48  puts [format {%6d %s} $depth $fname]
49}
50
51puts "****************** Stack Usage By Recursion *******************"
52foreach key [array names callpair] {
53  foreach {from to} $key break
54  lappend calls($from) $to
55  # lappend calledby($to) $from
56}
57proc all_descendents {root} {
58  global calls recursive
59  set todo($root) $root
60  set go 1
61  while {$go} {
62    set go 0
63    foreach f [array names todo] {
64      set path $todo($f)
65      unset todo($f)
66      if {![info exists calls($f)]} continue
67      foreach x $calls($f) {
68        if {$x==$root} {
69          lappend recursive($root) [concat $path $root]
70        } elseif {![info exists d($x)]} {
71          set go 1
72          set todo($x) [concat $path $x]
73          set d($x) 1
74        }
75      }
76    }
77  }
78  return [array names d]
79}
80set pathlist {}
81foreach f [array names recursive] {
82  all_descendents $f
83  foreach m $recursive($f) {
84    set depth 0
85    foreach b [lrange $m 0 end-1] {
86      set depth [expr {$depth+$stkdepth($b)}]
87    }
88    lappend pathlist [list $depth $m]
89  }
90}
91foreach path [lsort -integer -decr -index 0 $pathlist] {
92  foreach {depth m} $path break
93  set first [lindex $m 0]
94  puts [format {%6d %s %d} $depth $first $stkdepth($first)]
95  foreach b [lrange $m 1 end] {
96    puts "          $b $stkdepth($b)"
97  }
98}
99