2013-03-11 08:59:00 +00:00
|
|
|
# This testcase is part of GDB, the GNU debugger.
|
|
|
|
#
|
2015-01-01 09:32:14 +00:00
|
|
|
# Copyright 2013-2015 Free Software Foundation, Inc.
|
2013-03-11 08:59:00 +00:00
|
|
|
#
|
|
|
|
# Contributed by Intel Corp. <christian.himpel@intel.com>
|
|
|
|
#
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation; either version 3 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
# check for btrace support
|
|
|
|
if { [skip_btrace_tests] } { return -1 }
|
|
|
|
|
|
|
|
# start inferior
|
|
|
|
standard_testfile
|
|
|
|
if [prepare_for_testing function_call_history.exp $testfile {} {debug}] {
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
if ![runto_main] {
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
|
|
|
# start btrace
|
|
|
|
gdb_test_no_output "record btrace"
|
|
|
|
|
|
|
|
# set bp after increment loop and continue
|
|
|
|
set bp_location [gdb_get_line_number "bp.1" $testfile.c]
|
|
|
|
gdb_breakpoint $bp_location
|
|
|
|
gdb_continue_to_breakpoint "cont to $bp_location" ".*$testfile.c:$bp_location.*"
|
|
|
|
|
2013-12-18 13:47:17 +00:00
|
|
|
proc rec_fun_all {} {
|
2015-03-10 08:51:27 +00:00
|
|
|
gdb_test "record function-call-history 1" [multi_line \
|
2013-05-13 12:57:42 +00:00
|
|
|
"1\tmain" \
|
|
|
|
"2\tinc" \
|
|
|
|
"3\tmain" \
|
|
|
|
"4\tinc" \
|
|
|
|
"5\tmain" \
|
|
|
|
"6\tinc" \
|
|
|
|
"7\tmain" \
|
|
|
|
"8\tinc" \
|
|
|
|
"9\tmain" \
|
|
|
|
"10\tinc" \
|
|
|
|
"11\tmain" \
|
|
|
|
"12\tinc" \
|
|
|
|
"13\tmain" \
|
|
|
|
"14\tinc" \
|
|
|
|
"15\tmain" \
|
|
|
|
"16\tinc" \
|
|
|
|
"17\tmain" \
|
|
|
|
"18\tinc" \
|
|
|
|
"19\tmain" \
|
|
|
|
"20\tinc" \
|
2015-03-10 08:51:27 +00:00
|
|
|
"21\tmain"]
|
2013-12-18 13:47:17 +00:00
|
|
|
}
|
|
|
|
|
2013-03-11 08:59:00 +00:00
|
|
|
# show function call history with unlimited size, we expect to see all 21 entries
|
|
|
|
gdb_test_no_output "set record function-call-history-size 0"
|
2013-12-18 13:47:17 +00:00
|
|
|
with_test_prefix "size unlimited" rec_fun_all
|
2013-03-11 08:59:00 +00:00
|
|
|
|
|
|
|
# show function call history with size of 21, we expect to see all 21 entries
|
|
|
|
gdb_test_no_output "set record function-call-history-size 21"
|
2013-12-18 13:47:17 +00:00
|
|
|
with_test_prefix "size 21" rec_fun_all
|
2013-03-11 08:59:00 +00:00
|
|
|
|
|
|
|
# show first 15 entries
|
|
|
|
gdb_test_no_output "set record function-call-history-size 15"
|
2015-03-10 08:51:27 +00:00
|
|
|
gdb_test "record function-call-history 1" [multi_line \
|
2013-05-13 12:57:42 +00:00
|
|
|
"1\tmain" \
|
|
|
|
"2\tinc" \
|
|
|
|
"3\tmain" \
|
|
|
|
"4\tinc" \
|
|
|
|
"5\tmain" \
|
|
|
|
"6\tinc" \
|
|
|
|
"7\tmain" \
|
|
|
|
"8\tinc" \
|
|
|
|
"9\tmain" \
|
|
|
|
"10\tinc" \
|
|
|
|
"11\tmain" \
|
|
|
|
"12\tinc" \
|
|
|
|
"13\tmain" \
|
|
|
|
"14\tinc" \
|
2015-03-10 08:51:27 +00:00
|
|
|
"15\tmain"] "forward - 1"
|
2013-03-11 08:59:00 +00:00
|
|
|
|
|
|
|
# show last 6 entries
|
2015-03-10 08:51:27 +00:00
|
|
|
gdb_test "record function-call-history +" [multi_line \
|
2013-05-13 12:57:42 +00:00
|
|
|
"16\tinc" \
|
|
|
|
"17\tmain" \
|
|
|
|
"18\tinc" \
|
|
|
|
"19\tmain" \
|
|
|
|
"20\tinc" \
|
2015-03-10 08:51:27 +00:00
|
|
|
"21\tmain"] "forward - 2"
|
2013-03-11 08:59:00 +00:00
|
|
|
|
|
|
|
# moving further should not work
|
2013-12-18 13:47:17 +00:00
|
|
|
gdb_test "record function-call-history +" "At the end of the branch trace record\\." "forward - 3"
|
2013-03-11 08:59:00 +00:00
|
|
|
|
|
|
|
# make sure we cannot move any further a second time
|
2013-12-18 13:47:17 +00:00
|
|
|
gdb_test "record function-call-history +" "At the end of the branch trace record\\." "forward - 4"
|
2013-03-11 08:59:00 +00:00
|
|
|
|
|
|
|
# moving back showing the latest 15 function calls
|
2015-03-10 08:51:27 +00:00
|
|
|
gdb_test "record function-call-history -" [multi_line \
|
2013-05-13 12:57:42 +00:00
|
|
|
"7\tmain" \
|
|
|
|
"8\tinc" \
|
|
|
|
"9\tmain" \
|
|
|
|
"10\tinc" \
|
|
|
|
"11\tmain" \
|
|
|
|
"12\tinc" \
|
|
|
|
"13\tmain" \
|
|
|
|
"14\tinc" \
|
|
|
|
"15\tmain" \
|
|
|
|
"16\tinc" \
|
|
|
|
"17\tmain" \
|
|
|
|
"18\tinc" \
|
|
|
|
"19\tmain" \
|
|
|
|
"20\tinc" \
|
2015-03-10 08:51:27 +00:00
|
|
|
"21\tmain"] "backward - 1"
|
2013-03-11 08:59:00 +00:00
|
|
|
|
|
|
|
# moving further back shows the 6 first function calls
|
2015-03-10 08:51:27 +00:00
|
|
|
gdb_test "record function-call-history -" [multi_line \
|
2013-05-13 12:57:42 +00:00
|
|
|
"1\tmain" \
|
|
|
|
"2\tinc" \
|
|
|
|
"3\tmain" \
|
|
|
|
"4\tinc" \
|
|
|
|
"5\tmain" \
|
2015-03-10 08:51:27 +00:00
|
|
|
"6\tinc"] "backward - 2"
|
2013-03-11 08:59:00 +00:00
|
|
|
|
|
|
|
# moving further back shouldn't work
|
2013-12-18 13:47:17 +00:00
|
|
|
gdb_test "record function-call-history -" "At the start of the branch trace record\\." "backward - 3"
|
2013-03-11 08:59:00 +00:00
|
|
|
|
|
|
|
# make sure we cannot move any further back
|
2013-12-18 13:47:17 +00:00
|
|
|
gdb_test "record function-call-history -" "At the start of the branch trace record\\." "backward - 4"
|
2013-03-11 08:59:00 +00:00
|
|
|
|
2013-04-18 08:58:05 +00:00
|
|
|
# don't mess around with path names
|
|
|
|
gdb_test_no_output "set filename-display basename"
|
|
|
|
|
2013-03-11 08:59:00 +00:00
|
|
|
# moving forward again, but this time with file and line number, expected to see the first 15 entries
|
2015-03-10 08:51:27 +00:00
|
|
|
gdb_test "record function-call-history /l +" [multi_line \
|
2013-04-18 08:58:05 +00:00
|
|
|
"\[0-9\]*\tmain\tat $srcfile:40,41" \
|
|
|
|
"\[0-9\]*\tinc\tat $srcfile:22,24" \
|
|
|
|
"\[0-9\]*\tmain\tat $srcfile:40,41" \
|
|
|
|
"\[0-9\]*\tinc\tat $srcfile:22,24" \
|
|
|
|
"\[0-9\]*\tmain\tat $srcfile:40,41" \
|
|
|
|
"\[0-9\]*\tinc\tat $srcfile:22,24" \
|
|
|
|
"\[0-9\]*\tmain\tat $srcfile:40,41" \
|
|
|
|
"\[0-9\]*\tinc\tat $srcfile:22,24" \
|
|
|
|
"\[0-9\]*\tmain\tat $srcfile:40,41" \
|
|
|
|
"\[0-9\]*\tinc\tat $srcfile:22,24" \
|
|
|
|
"\[0-9\]*\tmain\tat $srcfile:40,41" \
|
|
|
|
"\[0-9\]*\tinc\tat $srcfile:22,24" \
|
|
|
|
"\[0-9\]*\tmain\tat $srcfile:40,41" \
|
|
|
|
"\[0-9\]*\tinc\tat $srcfile:22,24" \
|
|
|
|
"\[0-9\]*\tmain\tat $srcfile:40,41" \
|
2015-03-10 08:51:27 +00:00
|
|
|
] "forward /l - 1"
|
2013-03-11 08:59:00 +00:00
|
|
|
|
|
|
|
# moving forward and expect to see the latest 6 entries
|
2015-03-10 08:51:27 +00:00
|
|
|
gdb_test "record function-call-history /l +" [multi_line \
|
2013-04-18 08:58:05 +00:00
|
|
|
"\[0-9\]*\tinc\tat $srcfile:22,24" \
|
|
|
|
"\[0-9\]*\tmain\tat $srcfile:40,41" \
|
|
|
|
"\[0-9\]*\tinc\tat $srcfile:22,24" \
|
|
|
|
"\[0-9\]*\tmain\tat $srcfile:40,41" \
|
|
|
|
"\[0-9\]*\tinc\tat $srcfile:22,24" \
|
|
|
|
"\[0-9\]*\tmain\tat $srcfile:40,43" \
|
2015-03-10 08:51:27 +00:00
|
|
|
] "forward /l - 2"
|
2013-03-11 08:59:00 +00:00
|
|
|
|
|
|
|
# moving further forward shouldn't work
|
2013-12-18 13:47:17 +00:00
|
|
|
gdb_test "record function-call-history /l +" "At the end of the branch trace record\\." "forward /l - 3"
|
|
|
|
gdb_test "record function-call-history /l" "At the end of the branch trace record\\." "forward /l - 4"
|
|
|
|
|
2015-03-10 08:51:27 +00:00
|
|
|
set expected_range [multi_line \
|
2013-05-13 12:57:42 +00:00
|
|
|
"4\tinc" \
|
|
|
|
"5\tmain" \
|
|
|
|
"6\tinc" \
|
|
|
|
"7\tmain" \
|
|
|
|
"8\tinc" \
|
|
|
|
"9\tmain" \
|
2015-03-10 08:51:27 +00:00
|
|
|
"10\tinc"]
|
2013-03-11 08:59:00 +00:00
|
|
|
|
|
|
|
# show functions in instruction range
|
2013-04-17 07:39:43 +00:00
|
|
|
gdb_test "record function-call-history 4,10" $expected_range
|
2013-05-13 12:57:42 +00:00
|
|
|
gdb_test "record function-call-history 4,+7" $expected_range
|
2013-04-17 07:39:43 +00:00
|
|
|
gdb_test "record function-call-history 10,-7" $expected_range
|
|
|
|
gdb_test "record function-call-history 4,4" "4\tinc\r"
|
2013-03-11 08:59:00 +00:00
|
|
|
|
|
|
|
# set bp after fib recursion and continue
|
|
|
|
set bp_location [gdb_get_line_number "bp.2" $testfile.c]
|
|
|
|
gdb_breakpoint $bp_location
|
|
|
|
gdb_continue_to_breakpoint "cont to $bp_location" ".*$testfile.c:$bp_location.*"
|
|
|
|
|
btrace: change branch trace data structure
The branch trace is represented as 3 vectors:
- a block vector
- a instruction vector
- a function vector
Each vector (except for the first) is computed from the one above.
Change this into a graph where a node represents a sequence of instructions
belonging to the same function and where we have three types of edges to connect
the function segments:
- control flow
- same function (instance)
- call stack
This allows us to navigate in the branch trace. We will need this for "record
goto" and reverse execution.
This patch introduces the data structure and computes the control flow edges.
It also introduces iterator structs to simplify iterating over the branch trace
in control-flow order.
It also fixes PR gdb/15240 since now recursive calls are handled correctly.
Fix the test that got the number of expected fib instances and also the
function numbers wrong.
The current instruction had been part of the branch trace. This will look odd
once we start support for reverse execution. Remove it. We still keep it in
the trace itself to allow extending the branch trace more easily in the future.
2014-01-16 Markus Metzger <markus.t.metzger@intel.com>
* btrace.h (struct btrace_func_link): New.
(enum btrace_function_flag): New.
(struct btrace_inst): Rename to ...
(struct btrace_insn): ...this. Update all users.
(struct btrace_func) <ibegin, iend>: Remove.
(struct btrace_func_link): New.
(struct btrace_func): Rename to ...
(struct btrace_function): ...this. Update all users.
(struct btrace_function) <segment, flow, up, insn, insn_offset)
(number, level, flags>: New.
(struct btrace_insn_iterator): Rename to ...
(struct btrace_insn_history): ...this.
Update all users.
(struct btrace_insn_iterator, btrace_call_iterator): New.
(struct btrace_target_info) <btrace, itrace, ftrace>: Remove.
(struct btrace_target_info) <begin, end, level>
<insn_history, call_history>: New.
(btrace_insn_get, btrace_insn_number, btrace_insn_begin)
(btrace_insn_end, btrace_insn_prev, btrace_insn_next)
(btrace_insn_cmp, btrace_find_insn_by_number, btrace_call_get)
(btrace_call_number, btrace_call_begin, btrace_call_end)
(btrace_call_prev, btrace_call_next, btrace_call_cmp)
(btrace_find_function_by_number, btrace_set_insn_history)
(btrace_set_call_history): New.
* btrace.c (btrace_init_insn_iterator)
(btrace_init_func_iterator, compute_itrace): Remove.
(ftrace_print_function_name, ftrace_print_filename)
(ftrace_skip_file): Change
parameter to const.
(ftrace_init_func): Remove.
(ftrace_debug): Use new btrace_function fields.
(ftrace_function_switched): Also consider gaining and
losing symbol information).
(ftrace_print_insn_addr, ftrace_new_call, ftrace_new_return)
(ftrace_new_switch, ftrace_find_caller, ftrace_new_function)
(ftrace_update_caller, ftrace_fixup_caller, ftrace_new_tailcall):
New.
(ftrace_new_function): Move. Remove debug print.
(ftrace_update_lines, ftrace_update_insns): New.
(ftrace_update_function): Check for call, ret, and jump.
(compute_ftrace): Renamed to ...
(btrace_compute_ftrace): ...this. Rewritten to compute call
stack.
(btrace_fetch, btrace_clear): Updated.
(btrace_insn_get, btrace_insn_number, btrace_insn_begin)
(btrace_insn_end, btrace_insn_prev, btrace_insn_next)
(btrace_insn_cmp, btrace_find_insn_by_number, btrace_call_get)
(btrace_call_number, btrace_call_begin, btrace_call_end)
(btrace_call_prev, btrace_call_next, btrace_call_cmp)
(btrace_find_function_by_number, btrace_set_insn_history)
(btrace_set_call_history): New.
* record-btrace.c (require_btrace): Use new btrace thread
info fields.
(record_btrace_info, btrace_insn_history)
(record_btrace_insn_history, record_btrace_insn_history_range):
Use new btrace thread info fields and new iterator.
(btrace_func_history_src_line): Rename to ...
(btrace_call_history_src_line): ...this. Use new btrace
thread info fields.
(btrace_func_history): Rename to ...
(btrace_call_history): ...this. Use new btrace thread info
fields and new iterator.
(record_btrace_call_history, record_btrace_call_history_range):
Use new btrace thread info fields and new iterator.
testsuite/
* gdb.btrace/function_call_history.exp: Fix expected function
trace.
* gdb.btrace/instruction_history.exp: Initialize traced.
Remove traced_functions.
2013-03-22 13:32:47 +00:00
|
|
|
# at this point we expect to have main, fib, ..., fib, main, where fib occurs 9 times,
|
|
|
|
# so we limit the output to only show the latest 11 function calls
|
|
|
|
gdb_test_no_output "set record function-call-history-size 11"
|
2015-03-10 08:51:27 +00:00
|
|
|
gdb_test "record function-call-history" [multi_line \
|
2013-05-13 12:57:42 +00:00
|
|
|
"21\tmain" \
|
btrace: change branch trace data structure
The branch trace is represented as 3 vectors:
- a block vector
- a instruction vector
- a function vector
Each vector (except for the first) is computed from the one above.
Change this into a graph where a node represents a sequence of instructions
belonging to the same function and where we have three types of edges to connect
the function segments:
- control flow
- same function (instance)
- call stack
This allows us to navigate in the branch trace. We will need this for "record
goto" and reverse execution.
This patch introduces the data structure and computes the control flow edges.
It also introduces iterator structs to simplify iterating over the branch trace
in control-flow order.
It also fixes PR gdb/15240 since now recursive calls are handled correctly.
Fix the test that got the number of expected fib instances and also the
function numbers wrong.
The current instruction had been part of the branch trace. This will look odd
once we start support for reverse execution. Remove it. We still keep it in
the trace itself to allow extending the branch trace more easily in the future.
2014-01-16 Markus Metzger <markus.t.metzger@intel.com>
* btrace.h (struct btrace_func_link): New.
(enum btrace_function_flag): New.
(struct btrace_inst): Rename to ...
(struct btrace_insn): ...this. Update all users.
(struct btrace_func) <ibegin, iend>: Remove.
(struct btrace_func_link): New.
(struct btrace_func): Rename to ...
(struct btrace_function): ...this. Update all users.
(struct btrace_function) <segment, flow, up, insn, insn_offset)
(number, level, flags>: New.
(struct btrace_insn_iterator): Rename to ...
(struct btrace_insn_history): ...this.
Update all users.
(struct btrace_insn_iterator, btrace_call_iterator): New.
(struct btrace_target_info) <btrace, itrace, ftrace>: Remove.
(struct btrace_target_info) <begin, end, level>
<insn_history, call_history>: New.
(btrace_insn_get, btrace_insn_number, btrace_insn_begin)
(btrace_insn_end, btrace_insn_prev, btrace_insn_next)
(btrace_insn_cmp, btrace_find_insn_by_number, btrace_call_get)
(btrace_call_number, btrace_call_begin, btrace_call_end)
(btrace_call_prev, btrace_call_next, btrace_call_cmp)
(btrace_find_function_by_number, btrace_set_insn_history)
(btrace_set_call_history): New.
* btrace.c (btrace_init_insn_iterator)
(btrace_init_func_iterator, compute_itrace): Remove.
(ftrace_print_function_name, ftrace_print_filename)
(ftrace_skip_file): Change
parameter to const.
(ftrace_init_func): Remove.
(ftrace_debug): Use new btrace_function fields.
(ftrace_function_switched): Also consider gaining and
losing symbol information).
(ftrace_print_insn_addr, ftrace_new_call, ftrace_new_return)
(ftrace_new_switch, ftrace_find_caller, ftrace_new_function)
(ftrace_update_caller, ftrace_fixup_caller, ftrace_new_tailcall):
New.
(ftrace_new_function): Move. Remove debug print.
(ftrace_update_lines, ftrace_update_insns): New.
(ftrace_update_function): Check for call, ret, and jump.
(compute_ftrace): Renamed to ...
(btrace_compute_ftrace): ...this. Rewritten to compute call
stack.
(btrace_fetch, btrace_clear): Updated.
(btrace_insn_get, btrace_insn_number, btrace_insn_begin)
(btrace_insn_end, btrace_insn_prev, btrace_insn_next)
(btrace_insn_cmp, btrace_find_insn_by_number, btrace_call_get)
(btrace_call_number, btrace_call_begin, btrace_call_end)
(btrace_call_prev, btrace_call_next, btrace_call_cmp)
(btrace_find_function_by_number, btrace_set_insn_history)
(btrace_set_call_history): New.
* record-btrace.c (require_btrace): Use new btrace thread
info fields.
(record_btrace_info, btrace_insn_history)
(record_btrace_insn_history, record_btrace_insn_history_range):
Use new btrace thread info fields and new iterator.
(btrace_func_history_src_line): Rename to ...
(btrace_call_history_src_line): ...this. Use new btrace
thread info fields.
(btrace_func_history): Rename to ...
(btrace_call_history): ...this. Use new btrace thread info
fields and new iterator.
(record_btrace_call_history, record_btrace_call_history_range):
Use new btrace thread info fields and new iterator.
testsuite/
* gdb.btrace/function_call_history.exp: Fix expected function
trace.
* gdb.btrace/instruction_history.exp: Initialize traced.
Remove traced_functions.
2013-03-22 13:32:47 +00:00
|
|
|
"22\tfib" \
|
|
|
|
"23\tfib" \
|
|
|
|
"24\tfib" \
|
|
|
|
"25\tfib" \
|
|
|
|
"26\tfib" \
|
|
|
|
"27\tfib" \
|
|
|
|
"28\tfib" \
|
|
|
|
"29\tfib" \
|
2013-05-13 12:57:42 +00:00
|
|
|
"30\tfib" \
|
2015-03-10 08:51:27 +00:00
|
|
|
"31\tmain"] "recursive"
|
2013-04-18 08:58:05 +00:00
|
|
|
|
|
|
|
# show indented function call history for fib
|
2015-03-10 08:51:27 +00:00
|
|
|
gdb_test "record function-call-history /c 21, +11" [multi_line \
|
2013-04-18 08:58:05 +00:00
|
|
|
"21\tmain" \
|
|
|
|
"22\t fib" \
|
|
|
|
"23\t fib" \
|
|
|
|
"24\t fib" \
|
|
|
|
"25\t fib" \
|
|
|
|
"26\t fib" \
|
|
|
|
"27\t fib" \
|
|
|
|
"28\t fib" \
|
|
|
|
"29\t fib" \
|
|
|
|
"30\t fib" \
|
|
|
|
"31\tmain" \
|
2015-03-10 08:51:27 +00:00
|
|
|
] "indented"
|
2013-04-18 08:58:05 +00:00
|
|
|
|
|
|
|
# make sure we can handle incomplete trace with respect to indentation
|
|
|
|
if ![runto_main] {
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
# navigate to the fib in line 24 above
|
|
|
|
gdb_breakpoint fib
|
|
|
|
gdb_continue_to_breakpoint "cont to fib.1"
|
|
|
|
gdb_continue_to_breakpoint "cont to fib.2"
|
|
|
|
gdb_continue_to_breakpoint "cont to fib.3"
|
|
|
|
gdb_continue_to_breakpoint "cont to fib.4"
|
|
|
|
|
|
|
|
# start tracing
|
|
|
|
gdb_test_no_output "record btrace"
|
|
|
|
|
|
|
|
# continue until line 30 above
|
|
|
|
delete_breakpoints
|
|
|
|
set bp_location [gdb_get_line_number "bp.2" $testfile.c]
|
|
|
|
gdb_breakpoint $bp_location
|
|
|
|
gdb_continue_to_breakpoint "cont to bp.2" ".*$testfile.c:$bp_location\r\n.*"
|
|
|
|
|
|
|
|
# let's look at the trace. we expect to see the tail of the above listing.
|
2015-03-10 08:51:27 +00:00
|
|
|
gdb_test "record function-call-history /c" [multi_line \
|
2013-04-18 08:58:05 +00:00
|
|
|
"1\t fib" \
|
|
|
|
"2\t fib" \
|
|
|
|
"3\t fib" \
|
|
|
|
"4\t fib" \
|
|
|
|
"5\t fib" \
|
|
|
|
"6\tmain" \
|
2015-03-10 08:51:27 +00:00
|
|
|
] "indented tail"
|