From 33b4777ca1b7b456af8201b98eda27d1b272cbab Mon Sep 17 00:00:00 2001 From: Markus Metzger Date: Tue, 26 Jan 2016 14:58:44 +0100 Subject: [PATCH] btrace, frame: fix crash in get_frame_type In skip_artificial_frames we repeatedly call get_prev_frame_always until we get a non-inline and non-tailcall frame assuming that there must be such a frame eventually. For record targets, however, we may have a frame chain that consists only of artificial frames. This leads to a crash in get_frame_type when dereferencing a NULL frame pointer. Change skip_artificial_frames and skip_tailcall_frames to return NULL in such a case and modify each caller to cope with a NULL return. In frame_unwind_caller_pc and frame_unwind_caller_arch, we simply assert that the returned value is not NULL. Their caller was supposed to check frame_unwind_caller_id before calling those functions. In other cases, we thrown an error. In infcmd further move the skip_tailcall_frames call to the forward-stepping case since we don't need a frame for reverse execution and we don't want to fail because of that. Reverse-finish does make sense for a tailcall frame. gdb/ * frame.h (skip_tailcall_frames): Update comment. * frame.c (skip_artificial_frames, skip_tailcall_frames): Return NULL if only artificial frames are found. Update comment. (frame_unwind_caller_id): Handle NULL return. (frame_unwind_caller_pc, frame_unwind_caller_arch): Assert that skip_artificial_frames does not return NULL. (frame_pop): Add an error if only tailcall frames are found. * infcmd.c (finish_command): Move skip_tailcall_frames call into forward- execution case. Add an error if only tailcall frames are found. testsuite/ * gdb.btrace/tailcall-only.exp: New. * gdb.btrace/tailcall-only.c: New. * gdb.btrace/x86_64-tailcall-only.S: New. * gdb.btrace/i686-tailcall-only.S: New. --- gdb/ChangeLog | 13 + gdb/frame.c | 48 ++- gdb/frame.h | 3 +- gdb/infcmd.c | 15 +- gdb/testsuite/ChangeLog | 7 + gdb/testsuite/gdb.btrace/i686-tailcall-only.S | 447 ++++++++++++++++++++++++ gdb/testsuite/gdb.btrace/tailcall-only.c | 53 +++ gdb/testsuite/gdb.btrace/tailcall-only.exp | 97 +++++ gdb/testsuite/gdb.btrace/x86_64-tailcall-only.S | 446 +++++++++++++++++++++++ 9 files changed, 1115 insertions(+), 14 deletions(-) create mode 100644 gdb/testsuite/gdb.btrace/i686-tailcall-only.S create mode 100644 gdb/testsuite/gdb.btrace/tailcall-only.c create mode 100644 gdb/testsuite/gdb.btrace/tailcall-only.exp create mode 100644 gdb/testsuite/gdb.btrace/x86_64-tailcall-only.S diff --git a/gdb/ChangeLog b/gdb/ChangeLog index ef88180..e06fc3c 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,18 @@ 2016-02-12 Markus Metzger + * frame.h (skip_tailcall_frames): Update comment. + * frame.c (skip_artificial_frames, skip_tailcall_frames): Return NULL + if only artificial frames are found. Update comment. + (frame_unwind_caller_id): Handle NULL return. + (frame_unwind_caller_pc, frame_unwind_caller_arch): Assert that + skip_artificial_frames does not return NULL. + (frame_pop): Add an error if only tailcall frames are found. + * infcmd.c (finish_command): Move skip_tailcall_frames call into + forward-execution case. Add an error if only tailcall frames are + found. + +2016-02-12 Markus Metzger + * stack.c (frame_info): Check frame_unwind_caller_id. 2016-02-12 Markus Metzger diff --git a/gdb/frame.c b/gdb/frame.c index b7832c7..d621dd7 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -420,7 +420,8 @@ fprint_frame (struct ui_file *file, struct frame_info *fi) /* Given FRAME, return the enclosing frame as found in real frames read-in from inferior memory. Skip any previous frames which were made up by GDB. - Return the original frame if no immediate previous frames exist. */ + Return FRAME if FRAME is a non-artificial frame. + Return NULL if FRAME is the start of an artificial-only chain. */ static struct frame_info * skip_artificial_frames (struct frame_info *frame) @@ -428,12 +429,17 @@ skip_artificial_frames (struct frame_info *frame) /* Note we use get_prev_frame_always, and not get_prev_frame. The latter will truncate the frame chain, leading to this function unintentionally returning a null_frame_id (e.g., when the user - sets a backtrace limit). This is safe, because as these frames - are made up by GDB, there must be a real frame in the chain - below. */ + sets a backtrace limit). + + Note that for record targets we may get a frame chain that consists + of artificial frames only. */ while (get_frame_type (frame) == INLINE_FRAME || get_frame_type (frame) == TAILCALL_FRAME) - frame = get_prev_frame_always (frame); + { + frame = get_prev_frame_always (frame); + if (frame == NULL) + break; + } return frame; } @@ -444,7 +450,13 @@ struct frame_info * skip_tailcall_frames (struct frame_info *frame) { while (get_frame_type (frame) == TAILCALL_FRAME) - frame = get_prev_frame (frame); + { + /* Note that for record targets we may get a frame chain that consists of + tailcall frames only. */ + frame = get_prev_frame (frame); + if (frame == NULL) + break; + } return frame; } @@ -507,6 +519,9 @@ frame_unwind_caller_id (struct frame_info *next_frame) requests the frame ID of "main()"s caller. */ next_frame = skip_artificial_frames (next_frame); + if (next_frame == NULL) + return null_frame_id; + this_frame = get_prev_frame_always (next_frame); if (this_frame) return get_frame_id (skip_artificial_frames (this_frame)); @@ -880,7 +895,14 @@ frame_unwind_pc (struct frame_info *this_frame) CORE_ADDR frame_unwind_caller_pc (struct frame_info *this_frame) { - return frame_unwind_pc (skip_artificial_frames (this_frame)); + this_frame = skip_artificial_frames (this_frame); + + /* We must have a non-artificial frame. The caller is supposed to check + the result of frame_unwind_caller_id (), which returns NULL_FRAME_ID + in this case. */ + gdb_assert (this_frame != NULL); + + return frame_unwind_pc (this_frame); } int @@ -985,6 +1007,9 @@ frame_pop (struct frame_info *this_frame) entering THISFRAME. */ prev_frame = skip_tailcall_frames (prev_frame); + if (prev_frame == NULL) + error (_("Cannot find the caller frame.")); + /* Make a copy of all the register values unwound from this frame. Save them in a scratch buffer so that there isn't a race between trying to extract the old values from the current regcache while @@ -2571,7 +2596,14 @@ frame_unwind_arch (struct frame_info *next_frame) struct gdbarch * frame_unwind_caller_arch (struct frame_info *next_frame) { - return frame_unwind_arch (skip_artificial_frames (next_frame)); + next_frame = skip_artificial_frames (next_frame); + + /* We must have a non-artificial frame. The caller is supposed to check + the result of frame_unwind_caller_id (), which returns NULL_FRAME_ID + in this case. */ + gdb_assert (next_frame != NULL); + + return frame_unwind_arch (next_frame); } /* Gets the language of FRAME. */ diff --git a/gdb/frame.h b/gdb/frame.h index 7e8b01e..8ee64f1 100644 --- a/gdb/frame.h +++ b/gdb/frame.h @@ -821,7 +821,8 @@ extern int frame_unwinder_is (struct frame_info *fi, extern enum language get_frame_language (struct frame_info *frame); /* Return the first non-tailcall frame above FRAME or FRAME if it is not a - tailcall frame. */ + tailcall frame. Return NULL if FRAME is the start of a tailcall-only + chain. */ extern struct frame_info *skip_tailcall_frames (struct frame_info *frame); diff --git a/gdb/infcmd.c b/gdb/infcmd.c index 930dc61..a80bf0a 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -2000,10 +2000,6 @@ finish_command (char *arg, int from_tty) return; } - /* Ignore TAILCALL_FRAME type frames, they were executed already before - entering THISFRAME. */ - frame = skip_tailcall_frames (frame); - /* Find the function we will return from. */ sm->function = find_pc_function (get_frame_pc (get_selected_frame (NULL))); @@ -2030,7 +2026,16 @@ finish_command (char *arg, int from_tty) if (execution_direction == EXEC_REVERSE) finish_backward (sm); else - finish_forward (sm, frame); + { + /* Ignore TAILCALL_FRAME type frames, they were executed already before + entering THISFRAME. */ + frame = skip_tailcall_frames (frame); + + if (frame == NULL) + error (_("Cannot find the caller frame.")); + + finish_forward (sm, frame); + } } diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 0d61440..63d47cd 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2016-02-12 Markus Metzger + + * gdb.btrace/tailcall-only.exp: New. + * gdb.btrace/tailcall-only.c: New. + * gdb.btrace/x86_64-tailcall-only.S: New. + * gdb.btrace/i686-tailcall-only.S: New. + 2016-02-11 Pedro Alves * README (Parallel testing): Add missing double quotes. diff --git a/gdb/testsuite/gdb.btrace/i686-tailcall-only.S b/gdb/testsuite/gdb.btrace/i686-tailcall-only.S new file mode 100644 index 0000000..a89f2f2 --- /dev/null +++ b/gdb/testsuite/gdb.btrace/i686-tailcall-only.S @@ -0,0 +1,447 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2016 Free Software Foundation, Inc. + + 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 . + + + This file has been generated using: + gcc -m32 -march=i686 -S -O2 -dA -g tailcall-only.c -o i686-tailcall-only.S + */ + + .file "tailcall-only.c" + .text +.Ltext0: + .p2align 4,,15 + .type bar_1, @function +bar_1: +.LFB0: + .file 1 "tailcall-only.c" + # tailcall-only.c:22 + .loc 1 22 0 + .cfi_startproc +# BLOCK 2 freq:10000 seq:0 +# PRED: ENTRY [100.0%] (FALLTHRU) + # tailcall-only.c:24 + .loc 1 24 0 + movl $42, %eax +# SUCC: EXIT [100.0%] + ret + .cfi_endproc +.LFE0: + .size bar_1, .-bar_1 + .p2align 4,,15 + .type bar, @function +bar: +.LFB1: + # tailcall-only.c:28 + .loc 1 28 0 + .cfi_startproc +# BLOCK 2 freq:10000 seq:0 +# PRED: ENTRY [100.0%] (FALLTHRU) + # tailcall-only.c:29 + .loc 1 29 0 + jmp bar_1 +# SUCC: EXIT [100.0%] (ABNORMAL,SIBCALL) +.LVL0: + .cfi_endproc +.LFE1: + .size bar, .-bar + .p2align 4,,15 + .type foo_1, @function +foo_1: +.LFB2: + # tailcall-only.c:34 + .loc 1 34 0 + .cfi_startproc +# BLOCK 2 freq:10000 seq:0 +# PRED: ENTRY [100.0%] (FALLTHRU) + # tailcall-only.c:35 + .loc 1 35 0 + jmp bar +# SUCC: EXIT [100.0%] (ABNORMAL,SIBCALL) +.LVL1: + .cfi_endproc +.LFE2: + .size foo_1, .-foo_1 + .p2align 4,,15 + .type foo, @function +foo: +.LFB3: + # tailcall-only.c:40 + .loc 1 40 0 + .cfi_startproc +# BLOCK 2 freq:10000 seq:0 +# PRED: ENTRY [100.0%] (FALLTHRU) + # tailcall-only.c:41 + .loc 1 41 0 + jmp foo_1 +# SUCC: EXIT [100.0%] (ABNORMAL,SIBCALL) +.LVL2: + .cfi_endproc +.LFE3: + .size foo, .-foo + .section .text.startup,"ax",@progbits + .p2align 4,,15 + .globl main + .type main, @function +main: +.LFB4: + # tailcall-only.c:46 + .loc 1 46 0 + .cfi_startproc +# BLOCK 2 freq:10000 seq:0 +# PRED: ENTRY [100.0%] (FALLTHRU) + # tailcall-only.c:49 + .loc 1 49 0 + call foo +.LVL3: + # tailcall-only.c:50 + .loc 1 50 0 + addl $1, %eax +.LVL4: +# SUCC: EXIT [100.0%] + # tailcall-only.c:53 + .loc 1 53 0 + ret + .cfi_endproc +.LFE4: + .size main, .-main + .text +.Letext0: + .section .debug_info,"",@progbits +.Ldebug_info0: + .long 0xd5 # Length of Compilation Unit Info + .value 0x4 # DWARF version number + .long .Ldebug_abbrev0 # Offset Into Abbrev. Section + .byte 0x4 # Pointer Size (in bytes) + .uleb128 0x1 # (DIE (0xb) DW_TAG_compile_unit) + .long .LASF1 # DW_AT_producer: "GNU C 4.8.3 20140911 (Red Hat 4.8.3-9) -m32 -march=i686 -g -O2" + .byte 0x1 # DW_AT_language + .long .LASF2 # DW_AT_name: "tailcall-only.c" + .long .LASF3 # DW_AT_comp_dir: "" + .long .Ldebug_ranges0+0 # DW_AT_ranges + .long 0 # DW_AT_low_pc + .long .Ldebug_line0 # DW_AT_stmt_list + .uleb128 0x2 # (DIE (0x25) DW_TAG_subprogram) + .long .LASF4 # DW_AT_name: "bar_1" + .byte 0x1 # DW_AT_decl_file (tailcall-only.c) + .byte 0x15 # DW_AT_decl_line + # DW_AT_prototyped + .long 0x3a # DW_AT_type + .long .LFB0 # DW_AT_low_pc + .long .LFE0-.LFB0 # DW_AT_high_pc + .uleb128 0x1 # DW_AT_frame_base + .byte 0x9c # DW_OP_call_frame_cfa + # DW_AT_GNU_all_call_sites + .uleb128 0x3 # (DIE (0x3a) DW_TAG_base_type) + .byte 0x4 # DW_AT_byte_size + .byte 0x5 # DW_AT_encoding + .ascii "int\0" # DW_AT_name + .uleb128 0x4 # (DIE (0x41) DW_TAG_subprogram) + .ascii "bar\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (tailcall-only.c) + .byte 0x1b # DW_AT_decl_line + # DW_AT_prototyped + .long 0x3a # DW_AT_type + .long .LFB1 # DW_AT_low_pc + .long .LFE1-.LFB1 # DW_AT_high_pc + .uleb128 0x1 # DW_AT_frame_base + .byte 0x9c # DW_OP_call_frame_cfa + # DW_AT_GNU_all_call_sites + .long 0x64 # DW_AT_sibling + .uleb128 0x5 # (DIE (0x5a) DW_TAG_GNU_call_site) + .long .LVL0 # DW_AT_low_pc + # DW_AT_GNU_tail_call + .long 0x25 # DW_AT_abstract_origin + .byte 0 # end of children of DIE 0x41 + .uleb128 0x6 # (DIE (0x64) DW_TAG_subprogram) + .long .LASF0 # DW_AT_name: "foo_1" + .byte 0x1 # DW_AT_decl_file (tailcall-only.c) + .byte 0x21 # DW_AT_decl_line + # DW_AT_prototyped + .long 0x3a # DW_AT_type + .long .LFB2 # DW_AT_low_pc + .long .LFE2-.LFB2 # DW_AT_high_pc + .uleb128 0x1 # DW_AT_frame_base + .byte 0x9c # DW_OP_call_frame_cfa + # DW_AT_GNU_all_call_sites + .long 0x87 # DW_AT_sibling + .uleb128 0x5 # (DIE (0x7d) DW_TAG_GNU_call_site) + .long .LVL1 # DW_AT_low_pc + # DW_AT_GNU_tail_call + .long 0x41 # DW_AT_abstract_origin + .byte 0 # end of children of DIE 0x64 + .uleb128 0x4 # (DIE (0x87) DW_TAG_subprogram) + .ascii "foo\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (tailcall-only.c) + .byte 0x27 # DW_AT_decl_line + # DW_AT_prototyped + .long 0x3a # DW_AT_type + .long .LFB3 # DW_AT_low_pc + .long .LFE3-.LFB3 # DW_AT_high_pc + .uleb128 0x1 # DW_AT_frame_base + .byte 0x9c # DW_OP_call_frame_cfa + # DW_AT_GNU_all_call_sites + .long 0xaa # DW_AT_sibling + .uleb128 0x5 # (DIE (0xa0) DW_TAG_GNU_call_site) + .long .LVL2 # DW_AT_low_pc + # DW_AT_GNU_tail_call + .long 0x64 # DW_AT_abstract_origin + .byte 0 # end of children of DIE 0x87 + .uleb128 0x7 # (DIE (0xaa) DW_TAG_subprogram) + # DW_AT_external + .long .LASF5 # DW_AT_name: "main" + .byte 0x1 # DW_AT_decl_file (tailcall-only.c) + .byte 0x2d # DW_AT_decl_line + # DW_AT_prototyped + .long 0x3a # DW_AT_type + .long .LFB4 # DW_AT_low_pc + .long .LFE4-.LFB4 # DW_AT_high_pc + .uleb128 0x1 # DW_AT_frame_base + .byte 0x9c # DW_OP_call_frame_cfa + # DW_AT_GNU_all_call_sites + .uleb128 0x8 # (DIE (0xbf) DW_TAG_variable) + .long .LASF6 # DW_AT_name: "answer" + .byte 0x1 # DW_AT_decl_file (tailcall-only.c) + .byte 0x2f # DW_AT_decl_line + .long 0x3a # DW_AT_type + .long .LLST0 # DW_AT_location + .uleb128 0x9 # (DIE (0xce) DW_TAG_GNU_call_site) + .long .LVL3 # DW_AT_low_pc + .long 0x87 # DW_AT_abstract_origin + .byte 0 # end of children of DIE 0xaa + .byte 0 # end of children of DIE 0xb + .section .debug_abbrev,"",@progbits +.Ldebug_abbrev0: + .uleb128 0x1 # (abbrev code) + .uleb128 0x11 # (TAG: DW_TAG_compile_unit) + .byte 0x1 # DW_children_yes + .uleb128 0x25 # (DW_AT_producer) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x13 # (DW_AT_language) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x1b # (DW_AT_comp_dir) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x55 # (DW_AT_ranges) + .uleb128 0x17 # (DW_FORM_sec_offset) + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x10 # (DW_AT_stmt_list) + .uleb128 0x17 # (DW_FORM_sec_offset) + .byte 0 + .byte 0 + .uleb128 0x2 # (abbrev code) + .uleb128 0x2e # (TAG: DW_TAG_subprogram) + .byte 0 # DW_children_no + .uleb128 0x3 # (DW_AT_name) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x27 # (DW_AT_prototyped) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x12 # (DW_AT_high_pc) + .uleb128 0x6 # (DW_FORM_data4) + .uleb128 0x40 # (DW_AT_frame_base) + .uleb128 0x18 # (DW_FORM_exprloc) + .uleb128 0x2117 # (DW_AT_GNU_all_call_sites) + .uleb128 0x19 # (DW_FORM_flag_present) + .byte 0 + .byte 0 + .uleb128 0x3 # (abbrev code) + .uleb128 0x24 # (TAG: DW_TAG_base_type) + .byte 0 # DW_children_no + .uleb128 0xb # (DW_AT_byte_size) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3e # (DW_AT_encoding) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .byte 0 + .byte 0 + .uleb128 0x4 # (abbrev code) + .uleb128 0x2e # (TAG: DW_TAG_subprogram) + .byte 0x1 # DW_children_yes + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x27 # (DW_AT_prototyped) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x12 # (DW_AT_high_pc) + .uleb128 0x6 # (DW_FORM_data4) + .uleb128 0x40 # (DW_AT_frame_base) + .uleb128 0x18 # (DW_FORM_exprloc) + .uleb128 0x2117 # (DW_AT_GNU_all_call_sites) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x1 # (DW_AT_sibling) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x5 # (abbrev code) + .uleb128 0x4109 # (TAG: DW_TAG_GNU_call_site) + .byte 0 # DW_children_no + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x2115 # (DW_AT_GNU_tail_call) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x31 # (DW_AT_abstract_origin) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x6 # (abbrev code) + .uleb128 0x2e # (TAG: DW_TAG_subprogram) + .byte 0x1 # DW_children_yes + .uleb128 0x3 # (DW_AT_name) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x27 # (DW_AT_prototyped) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x12 # (DW_AT_high_pc) + .uleb128 0x6 # (DW_FORM_data4) + .uleb128 0x40 # (DW_AT_frame_base) + .uleb128 0x18 # (DW_FORM_exprloc) + .uleb128 0x2117 # (DW_AT_GNU_all_call_sites) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x1 # (DW_AT_sibling) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x7 # (abbrev code) + .uleb128 0x2e # (TAG: DW_TAG_subprogram) + .byte 0x1 # DW_children_yes + .uleb128 0x3f # (DW_AT_external) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x27 # (DW_AT_prototyped) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x12 # (DW_AT_high_pc) + .uleb128 0x6 # (DW_FORM_data4) + .uleb128 0x40 # (DW_AT_frame_base) + .uleb128 0x18 # (DW_FORM_exprloc) + .uleb128 0x2117 # (DW_AT_GNU_all_call_sites) + .uleb128 0x19 # (DW_FORM_flag_present) + .byte 0 + .byte 0 + .uleb128 0x8 # (abbrev code) + .uleb128 0x34 # (TAG: DW_TAG_variable) + .byte 0 # DW_children_no + .uleb128 0x3 # (DW_AT_name) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x2 # (DW_AT_location) + .uleb128 0x17 # (DW_FORM_sec_offset) + .byte 0 + .byte 0 + .uleb128 0x9 # (abbrev code) + .uleb128 0x4109 # (TAG: DW_TAG_GNU_call_site) + .byte 0 # DW_children_no + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x31 # (DW_AT_abstract_origin) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .byte 0 + .section .debug_loc,"",@progbits +.Ldebug_loc0: +.LLST0: + .long .LVL3 # Location list begin address (*.LLST0) + .long .LVL4 # Location list end address (*.LLST0) + .value 0x3 # Location expression size + .byte 0x70 # DW_OP_breg0 + .sleb128 1 + .byte 0x9f # DW_OP_stack_value + .long .LVL4 # Location list begin address (*.LLST0) + .long .LFE4 # Location list end address (*.LLST0) + .value 0x1 # Location expression size + .byte 0x50 # DW_OP_reg0 + .long 0 # Location list terminator begin (*.LLST0) + .long 0 # Location list terminator end (*.LLST0) + .section .debug_aranges,"",@progbits + .long 0x24 # Length of Address Ranges Info + .value 0x2 # DWARF Version + .long .Ldebug_info0 # Offset of Compilation Unit Info + .byte 0x4 # Size of Address + .byte 0 # Size of Segment Descriptor + .value 0 # Pad to 8 byte boundary + .value 0 + .long .Ltext0 # Address + .long .Letext0-.Ltext0 # Length + .long .LFB4 # Address + .long .LFE4-.LFB4 # Length + .long 0 + .long 0 + .section .debug_ranges,"",@progbits +.Ldebug_ranges0: + .long .Ltext0 # Offset 0 + .long .Letext0 + .long .LFB4 # Offset 0x8 + .long .LFE4 + .long 0 + .long 0 + .section .debug_line,"",@progbits +.Ldebug_line0: + .section .debug_str,"MS",@progbits,1 +.LASF4: + .string "bar_1" +.LASF2: + .string "tailcall-only.c" +.LASF1: + .string "GNU C 4.8.3 20140911 (Red Hat 4.8.3-9) -m32 -march=i686 -g -O2" +.LASF6: + .string "answer" +.LASF5: + .string "main" +.LASF3: + .string "" +.LASF0: + .string "foo_1" + .ident "GCC: (GNU) 4.8.3 20140911 (Red Hat 4.8.3-9)" + .section .note.GNU-stack,"",@progbits diff --git a/gdb/testsuite/gdb.btrace/tailcall-only.c b/gdb/testsuite/gdb.btrace/tailcall-only.c new file mode 100644 index 0000000..5913ddc --- /dev/null +++ b/gdb/testsuite/gdb.btrace/tailcall-only.c @@ -0,0 +1,53 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2016 Free Software Foundation, Inc. + + Contributed by Intel Corp. + + 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 . */ + +static __attribute__ ((noinline)) int +bar_1 (void) +{ + return 42; +} + +static __attribute__ ((noinline)) int +bar (void) +{ + return bar_1 (); +} + +static __attribute__ ((noinline)) int +foo_1 (void) +{ + return bar (); +} + +static __attribute__ ((noinline)) int +foo (void) +{ + return foo_1 (); +} + +int +main (void) +{ + int answer; + + answer = foo (); + answer += 1; + + return answer; +} diff --git a/gdb/testsuite/gdb.btrace/tailcall-only.exp b/gdb/testsuite/gdb.btrace/tailcall-only.exp new file mode 100644 index 0000000..44501f5 --- /dev/null +++ b/gdb/testsuite/gdb.btrace/tailcall-only.exp @@ -0,0 +1,97 @@ +# This testcase is part of GDB, the GNU debugger. +# +# Copyright 2016 Free Software Foundation, Inc. +# +# 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 . +# +# +# This is a variant of tailcall.exp where the entire trace contains only tail +# calls. This used to cause a crash in get_frame_type. +# + +# check for btrace support +if { [skip_btrace_tests] } { return -1 } + +# This test requires the compiler to generate a tail call. To guarantee that +# we always get one, we use an assembly source file. +# +# We use different assembly sources based on the target architecture. +# +# Luckily, they are similar enough that a single test script can handle +# both. +set opts {} +if [info exists COMPILE] { + # make check RUNTESTFLAGS="gdb.btrace/tailcall-only.exp COMPILE=1" + standard_testfile tailcall-only.c + lappend opts debug optimize=-O2 +} elseif {[istarget "x86_64-*-*"]} { + standard_testfile x86_64-tailcall-only.S +} elseif {[istarget "i?86-*-*"]} { + standard_testfile i686-tailcall-only.S +} else { + verbose "Skipping ${testfile}." + return +} + +if [prepare_for_testing tailcall-only.exp $testfile $srcfile $opts] { + return -1 +} +if ![runto_main] { + return -1 +} + +# we want to see the full trace for this test +gdb_test_no_output "set record function-call-history-size 0" + +# trace foo +gdb_test "step" ".*" "prepare for recording" +gdb_test_no_output "record btrace" +gdb_test "stepi 4" ".*" "record branch trace" + +# for debugging +gdb_test "info record" ".*" + +# show the branch trace with calls indented +gdb_test "record function-call-history /c 1" [multi_line \ + "1\tfoo" \ + "2\t foo_1" \ + "3\t bar" \ + "4\t bar_1" + ] "function-call-history" + +# We can step +gdb_test "record goto begin" ".*foo.*" +gdb_test "stepi" ".*foo_1.*" "step into foo_1" +gdb_test "step" ".*bar.*" "step into bar" +gdb_test "stepi" ".*bar_1.*" "step into bar_1" + +# We can neither finish nor return. +gdb_test "finish" "Cannot find the caller frame.*" +gdb_test_multiple "return" "return" { + -re "Make .* return now.*y or n. $" { + send_gdb "y\n" + exp_continue + } + -re "Cannot find the caller frame.*$gdb_prompt $" { + pass "return" + } +} + +# But we can reverse-finish +gdb_test "reverse-finish" ".*bar.*" +gdb_test "reverse-step" ".*foo_1.*" + +# Info frame isn't useful but doesn't crash as it used to. +gdb_test "up" ".*foo.*" +gdb_test "info frame" ".*" diff --git a/gdb/testsuite/gdb.btrace/x86_64-tailcall-only.S b/gdb/testsuite/gdb.btrace/x86_64-tailcall-only.S new file mode 100644 index 0000000..710288a --- /dev/null +++ b/gdb/testsuite/gdb.btrace/x86_64-tailcall-only.S @@ -0,0 +1,446 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2016 Free Software Foundation, Inc. + + 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 . + + + This file has been generated using: + gcc -S -O2 -dA -g tailcall-only.c -o x86_64-tailcall-only.S */ + + .file "tailcall-only.c" + .text +.Ltext0: + .p2align 4,,15 + .type bar_1, @function +bar_1: +.LFB0: + .file 1 "tailcall-only.c" + # tailcall-only.c:22 + .loc 1 22 0 + .cfi_startproc +# BLOCK 2 freq:10000 seq:0 +# PRED: ENTRY [100.0%] (FALLTHRU) + # tailcall-only.c:24 + .loc 1 24 0 + movl $42, %eax +# SUCC: EXIT [100.0%] + ret + .cfi_endproc +.LFE0: + .size bar_1, .-bar_1 + .p2align 4,,15 + .type bar, @function +bar: +.LFB1: + # tailcall-only.c:28 + .loc 1 28 0 + .cfi_startproc +# BLOCK 2 freq:10000 seq:0 +# PRED: ENTRY [100.0%] (FALLTHRU) + # tailcall-only.c:29 + .loc 1 29 0 + jmp bar_1 +# SUCC: EXIT [100.0%] (ABNORMAL,SIBCALL) +.LVL0: + .cfi_endproc +.LFE1: + .size bar, .-bar + .p2align 4,,15 + .type foo_1, @function +foo_1: +.LFB2: + # tailcall-only.c:34 + .loc 1 34 0 + .cfi_startproc +# BLOCK 2 freq:10000 seq:0 +# PRED: ENTRY [100.0%] (FALLTHRU) + # tailcall-only.c:35 + .loc 1 35 0 + jmp bar +# SUCC: EXIT [100.0%] (ABNORMAL,SIBCALL) +.LVL1: + .cfi_endproc +.LFE2: + .size foo_1, .-foo_1 + .p2align 4,,15 + .type foo, @function +foo: +.LFB3: + # tailcall-only.c:40 + .loc 1 40 0 + .cfi_startproc +# BLOCK 2 freq:10000 seq:0 +# PRED: ENTRY [100.0%] (FALLTHRU) + # tailcall-only.c:41 + .loc 1 41 0 + jmp foo_1 +# SUCC: EXIT [100.0%] (ABNORMAL,SIBCALL) +.LVL2: + .cfi_endproc +.LFE3: + .size foo, .-foo + .section .text.startup,"ax",@progbits + .p2align 4,,15 + .globl main + .type main, @function +main: +.LFB4: + # tailcall-only.c:46 + .loc 1 46 0 + .cfi_startproc +# BLOCK 2 freq:10000 seq:0 +# PRED: ENTRY [100.0%] (FALLTHRU) + # tailcall-only.c:49 + .loc 1 49 0 + call foo +.LVL3: + # tailcall-only.c:50 + .loc 1 50 0 + addl $1, %eax +.LVL4: +# SUCC: EXIT [100.0%] + # tailcall-only.c:53 + .loc 1 53 0 + ret + .cfi_endproc +.LFE4: + .size main, .-main + .text +.Letext0: + .section .debug_info,"",@progbits +.Ldebug_info0: + .long 0x111 # Length of Compilation Unit Info + .value 0x4 # DWARF version number + .long .Ldebug_abbrev0 # Offset Into Abbrev. Section + .byte 0x8 # Pointer Size (in bytes) + .uleb128 0x1 # (DIE (0xb) DW_TAG_compile_unit) + .long .LASF1 # DW_AT_producer: "GNU C 4.8.3 20140911 (Red Hat 4.8.3-9) -mtune=generic -march=x86-64 -g -O2" + .byte 0x1 # DW_AT_language + .long .LASF2 # DW_AT_name: "tailcall-only.c" + .long .LASF3 # DW_AT_comp_dir: "" + .long .Ldebug_ranges0+0 # DW_AT_ranges + .quad 0 # DW_AT_low_pc + .long .Ldebug_line0 # DW_AT_stmt_list + .uleb128 0x2 # (DIE (0x29) DW_TAG_subprogram) + .long .LASF4 # DW_AT_name: "bar_1" + .byte 0x1 # DW_AT_decl_file (tailcall-only.c) + .byte 0x15 # DW_AT_decl_line + # DW_AT_prototyped + .long 0x46 # DW_AT_type + .quad .LFB0 # DW_AT_low_pc + .quad .LFE0-.LFB0 # DW_AT_high_pc + .uleb128 0x1 # DW_AT_frame_base + .byte 0x9c # DW_OP_call_frame_cfa + # DW_AT_GNU_all_call_sites + .uleb128 0x3 # (DIE (0x46) DW_TAG_base_type) + .byte 0x4 # DW_AT_byte_size + .byte 0x5 # DW_AT_encoding + .ascii "int\0" # DW_AT_name + .uleb128 0x4 # (DIE (0x4d) DW_TAG_subprogram) + .ascii "bar\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (tailcall-only.c) + .byte 0x1b # DW_AT_decl_line + # DW_AT_prototyped + .long 0x46 # DW_AT_type + .quad .LFB1 # DW_AT_low_pc + .quad .LFE1-.LFB1 # DW_AT_high_pc + .uleb128 0x1 # DW_AT_frame_base + .byte 0x9c # DW_OP_call_frame_cfa + # DW_AT_GNU_all_call_sites + .long 0x7c # DW_AT_sibling + .uleb128 0x5 # (DIE (0x6e) DW_TAG_GNU_call_site) + .quad .LVL0 # DW_AT_low_pc + # DW_AT_GNU_tail_call + .long 0x29 # DW_AT_abstract_origin + .byte 0 # end of children of DIE 0x4d + .uleb128 0x6 # (DIE (0x7c) DW_TAG_subprogram) + .long .LASF0 # DW_AT_name: "foo_1" + .byte 0x1 # DW_AT_decl_file (tailcall-only.c) + .byte 0x21 # DW_AT_decl_line + # DW_AT_prototyped + .long 0x46 # DW_AT_type + .quad .LFB2 # DW_AT_low_pc + .quad .LFE2-.LFB2 # DW_AT_high_pc + .uleb128 0x1 # DW_AT_frame_base + .byte 0x9c # DW_OP_call_frame_cfa + # DW_AT_GNU_all_call_sites + .long 0xab # DW_AT_sibling + .uleb128 0x5 # (DIE (0x9d) DW_TAG_GNU_call_site) + .quad .LVL1 # DW_AT_low_pc + # DW_AT_GNU_tail_call + .long 0x4d # DW_AT_abstract_origin + .byte 0 # end of children of DIE 0x7c + .uleb128 0x4 # (DIE (0xab) DW_TAG_subprogram) + .ascii "foo\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (tailcall-only.c) + .byte 0x27 # DW_AT_decl_line + # DW_AT_prototyped + .long 0x46 # DW_AT_type + .quad .LFB3 # DW_AT_low_pc + .quad .LFE3-.LFB3 # DW_AT_high_pc + .uleb128 0x1 # DW_AT_frame_base + .byte 0x9c # DW_OP_call_frame_cfa + # DW_AT_GNU_all_call_sites + .long 0xda # DW_AT_sibling + .uleb128 0x5 # (DIE (0xcc) DW_TAG_GNU_call_site) + .quad .LVL2 # DW_AT_low_pc + # DW_AT_GNU_tail_call + .long 0x7c # DW_AT_abstract_origin + .byte 0 # end of children of DIE 0xab + .uleb128 0x7 # (DIE (0xda) DW_TAG_subprogram) + # DW_AT_external + .long .LASF5 # DW_AT_name: "main" + .byte 0x1 # DW_AT_decl_file (tailcall-only.c) + .byte 0x2d # DW_AT_decl_line + # DW_AT_prototyped + .long 0x46 # DW_AT_type + .quad .LFB4 # DW_AT_low_pc + .quad .LFE4-.LFB4 # DW_AT_high_pc + .uleb128 0x1 # DW_AT_frame_base + .byte 0x9c # DW_OP_call_frame_cfa + # DW_AT_GNU_all_call_sites + .uleb128 0x8 # (DIE (0xf7) DW_TAG_variable) + .long .LASF6 # DW_AT_name: "answer" + .byte 0x1 # DW_AT_decl_file (tailcall-only.c) + .byte 0x2f # DW_AT_decl_line + .long 0x46 # DW_AT_type + .long .LLST0 # DW_AT_location + .uleb128 0x9 # (DIE (0x106) DW_TAG_GNU_call_site) + .quad .LVL3 # DW_AT_low_pc + .long 0xab # DW_AT_abstract_origin + .byte 0 # end of children of DIE 0xda + .byte 0 # end of children of DIE 0xb + .section .debug_abbrev,"",@progbits +.Ldebug_abbrev0: + .uleb128 0x1 # (abbrev code) + .uleb128 0x11 # (TAG: DW_TAG_compile_unit) + .byte 0x1 # DW_children_yes + .uleb128 0x25 # (DW_AT_producer) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x13 # (DW_AT_language) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x1b # (DW_AT_comp_dir) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x55 # (DW_AT_ranges) + .uleb128 0x17 # (DW_FORM_sec_offset) + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x10 # (DW_AT_stmt_list) + .uleb128 0x17 # (DW_FORM_sec_offset) + .byte 0 + .byte 0 + .uleb128 0x2 # (abbrev code) + .uleb128 0x2e # (TAG: DW_TAG_subprogram) + .byte 0 # DW_children_no + .uleb128 0x3 # (DW_AT_name) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x27 # (DW_AT_prototyped) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x12 # (DW_AT_high_pc) + .uleb128 0x7 # (DW_FORM_data8) + .uleb128 0x40 # (DW_AT_frame_base) + .uleb128 0x18 # (DW_FORM_exprloc) + .uleb128 0x2117 # (DW_AT_GNU_all_call_sites) + .uleb128 0x19 # (DW_FORM_flag_present) + .byte 0 + .byte 0 + .uleb128 0x3 # (abbrev code) + .uleb128 0x24 # (TAG: DW_TAG_base_type) + .byte 0 # DW_children_no + .uleb128 0xb # (DW_AT_byte_size) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3e # (DW_AT_encoding) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .byte 0 + .byte 0 + .uleb128 0x4 # (abbrev code) + .uleb128 0x2e # (TAG: DW_TAG_subprogram) + .byte 0x1 # DW_children_yes + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x27 # (DW_AT_prototyped) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x12 # (DW_AT_high_pc) + .uleb128 0x7 # (DW_FORM_data8) + .uleb128 0x40 # (DW_AT_frame_base) + .uleb128 0x18 # (DW_FORM_exprloc) + .uleb128 0x2117 # (DW_AT_GNU_all_call_sites) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x1 # (DW_AT_sibling) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x5 # (abbrev code) + .uleb128 0x4109 # (TAG: DW_TAG_GNU_call_site) + .byte 0 # DW_children_no + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x2115 # (DW_AT_GNU_tail_call) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x31 # (DW_AT_abstract_origin) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x6 # (abbrev code) + .uleb128 0x2e # (TAG: DW_TAG_subprogram) + .byte 0x1 # DW_children_yes + .uleb128 0x3 # (DW_AT_name) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x27 # (DW_AT_prototyped) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x12 # (DW_AT_high_pc) + .uleb128 0x7 # (DW_FORM_data8) + .uleb128 0x40 # (DW_AT_frame_base) + .uleb128 0x18 # (DW_FORM_exprloc) + .uleb128 0x2117 # (DW_AT_GNU_all_call_sites) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x1 # (DW_AT_sibling) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x7 # (abbrev code) + .uleb128 0x2e # (TAG: DW_TAG_subprogram) + .byte 0x1 # DW_children_yes + .uleb128 0x3f # (DW_AT_external) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x27 # (DW_AT_prototyped) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x12 # (DW_AT_high_pc) + .uleb128 0x7 # (DW_FORM_data8) + .uleb128 0x40 # (DW_AT_frame_base) + .uleb128 0x18 # (DW_FORM_exprloc) + .uleb128 0x2117 # (DW_AT_GNU_all_call_sites) + .uleb128 0x19 # (DW_FORM_flag_present) + .byte 0 + .byte 0 + .uleb128 0x8 # (abbrev code) + .uleb128 0x34 # (TAG: DW_TAG_variable) + .byte 0 # DW_children_no + .uleb128 0x3 # (DW_AT_name) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x2 # (DW_AT_location) + .uleb128 0x17 # (DW_FORM_sec_offset) + .byte 0 + .byte 0 + .uleb128 0x9 # (abbrev code) + .uleb128 0x4109 # (TAG: DW_TAG_GNU_call_site) + .byte 0 # DW_children_no + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x31 # (DW_AT_abstract_origin) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .byte 0 + .section .debug_loc,"",@progbits +.Ldebug_loc0: +.LLST0: + .quad .LVL3 # Location list begin address (*.LLST0) + .quad .LVL4 # Location list end address (*.LLST0) + .value 0x3 # Location expression size + .byte 0x70 # DW_OP_breg0 + .sleb128 1 + .byte 0x9f # DW_OP_stack_value + .quad .LVL4 # Location list begin address (*.LLST0) + .quad .LFE4 # Location list end address (*.LLST0) + .value 0x1 # Location expression size + .byte 0x50 # DW_OP_reg0 + .quad 0 # Location list terminator begin (*.LLST0) + .quad 0 # Location list terminator end (*.LLST0) + .section .debug_aranges,"",@progbits + .long 0x3c # Length of Address Ranges Info + .value 0x2 # DWARF Version + .long .Ldebug_info0 # Offset of Compilation Unit Info + .byte 0x8 # Size of Address + .byte 0 # Size of Segment Descriptor + .value 0 # Pad to 16 byte boundary + .value 0 + .quad .Ltext0 # Address + .quad .Letext0-.Ltext0 # Length + .quad .LFB4 # Address + .quad .LFE4-.LFB4 # Length + .quad 0 + .quad 0 + .section .debug_ranges,"",@progbits +.Ldebug_ranges0: + .quad .Ltext0 # Offset 0 + .quad .Letext0 + .quad .LFB4 # Offset 0x10 + .quad .LFE4 + .quad 0 + .quad 0 + .section .debug_line,"",@progbits +.Ldebug_line0: + .section .debug_str,"MS",@progbits,1 +.LASF4: + .string "bar_1" +.LASF2: + .string "tailcall-only.c" +.LASF1: + .string "GNU C 4.8.3 20140911 (Red Hat 4.8.3-9) -mtune=generic -march=x86-64 -g -O2" +.LASF6: + .string "answer" +.LASF5: + .string "main" +.LASF3: + .string "" +.LASF0: + .string "foo_1" + .ident "GCC: (GNU) 4.8.3 20140911 (Red Hat 4.8.3-9)" + .section .note.GNU-stack,"",@progbits -- 2.7.4