From patchwork Wed Feb 10 15:02:12 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Metzger, Markus T" X-Patchwork-Id: 10794 Received: (qmail 125743 invoked by alias); 10 Feb 2016 15:02:50 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 125700 invoked by uid 89); 10 Feb 2016 15:02:48 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.2 required=5.0 tests=AWL, BAYES_00, RP_MATCHES_RCVD, SPF_PASS autolearn=ham version=3.3.2 spammy=reverse-finish, reversefinish, quad, 42 X-HELO: mga02.intel.com Received: from mga02.intel.com (HELO mga02.intel.com) (134.134.136.20) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 10 Feb 2016 15:02:38 +0000 Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga101.jf.intel.com with ESMTP; 10 Feb 2016 07:02:21 -0800 X-ExtLoop1: 1 Received: from irsmsx106.ger.corp.intel.com ([163.33.3.31]) by fmsmga004.fm.intel.com with ESMTP; 10 Feb 2016 07:02:20 -0800 Received: from irsmsx104.ger.corp.intel.com ([169.254.5.210]) by IRSMSX106.ger.corp.intel.com ([169.254.8.197]) with mapi id 14.03.0248.002; Wed, 10 Feb 2016 15:02:13 +0000 From: "Metzger, Markus T" To: Pedro Alves CC: "gdb-patches@sourceware.org" Subject: RE: [PATCH v2 3/3] btrace, frame: fix crash in get_frame_type Date: Wed, 10 Feb 2016 15:02:12 +0000 Message-ID: References: <1454681922-2228-1-git-send-email-markus.t.metzger@intel.com> <1454681922-2228-3-git-send-email-markus.t.metzger@intel.com> <56B9D620.2020104@redhat.com> <56BA61C6.8060807@redhat.com> <56BB0A0D.80502@redhat.com> In-Reply-To: MIME-Version: 1.0 X-IsSubscribed: yes > -----Original Message----- > From: Metzger, Markus T > Sent: Wednesday, February 10, 2016 11:29 AM > To: Pedro Alves > Cc: gdb-patches@sourceware.org > Subject: RE: [PATCH v2 3/3] btrace, frame: fix crash in get_frame_type > > So, what would break if we internal_error'ed in > > frame_unwind_caller_arch/pc instead or normal error, in the case that > > there's no non-artificial frame? > > Likely nothing. The case of only-artificial-frames is not covered by the test > suite. I'm not sure it is even possible during live debug (ignoring the > discussion about get_prev_frame_always). > > The changes were not motivated by fails but by my attempt to make the > callers of skip_artificial_frames handle the now-possible NULL return > gracefully. > > I ran the btrace suite including the new tests I added to cover the record > btrace tailcall-only-frames case and they pass. I'm running the full test suite > now. No new fails there, as well (64-bit IA). I added a comment based on your statement that frame_unwind_caller_xxx callers should check frame_unwind_caller_id and assert that skip_artificial_frames does not return NULL. Info frame doesn't crash. (gdb) info frame Stack level 0, frame at 0x0: rip = 0x4005b0 in bar (tailcall-only.c:29); saved rip = 0x4005c2 called by frame at 0x0 source language c. Arglist at unknown address. Locals at unknown address,Registers are not available in btrace record history This is from a tailcall-only frame stack in replay mode using the tailcall-only test. The real caller has not been recorded. The output isn't very helpful for record btrace since we don't record register and memory changes. Here's the patch: commit a9ba851aa9a126da90f12eaa1788f2d271530535 Author: Markus Metzger Date: Tue Jan 26 14:58:44 2016 +0100 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. 2016-02-10 Markus Metzger 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. Intel Deutschland GmbH Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de Managing Directors: Christin Eisenschmid, Christian Lamprechter Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928 diff --git a/gdb/frame.c b/gdb/frame.c index b7832c7..9bb493e 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,10 @@ frame_pop (struct frame_info *this_frame) entering THISFRAME. */ prev_frame = skip_tailcall_frames (prev_frame); + /* We cannot pop tailcall frames. */ + if (prev_frame == NULL) + error (_("Cannot pop a tailcall 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 +2597,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..938f8fa 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 (_("\"finish\" not meaningful for tailcall frames.")); + + finish_forward (sm, frame); + } } 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..1137be1 --- /dev/null +++ b/gdb/testsuite/gdb.btrace/tailcall-only.exp @@ -0,0 +1,93 @@ +# 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" "\"finish\" not meaningful for tailcall frames.*" +gdb_test_multiple "return" "return" { + -re "Make .* return now.*y or n. $" { + send_gdb "y\n" + exp_continue + } + -re "Cannot pop a tailcall frame.*$gdb_prompt $" { + pass "return" + } +} + +# But we can reverse-finish +gdb_test "reverse-finish" ".*bar.*" +gdb_test "reverse-step" ".*foo_1.*" 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