From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id MAAwOMJo0GllZgYAWB0awg (envelope-from ) for ; Fri, 03 Apr 2026 21:26:26 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=simark.ca; s=mail; t=1775265986; bh=BC/WLwKeqMWMYF3wz4oOrfibuDYWiX5TImIunyCApEs=; h=Date:Subject:To:Cc:References:From:In-Reply-To:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=V7kFR89K117cx8Jx5dl+TMDAXNZLViMEXLXe+Kzekoni2D+4RitqO8keknidGTTSP SPqXtnqCBQE0hrHng4rww8RbncDSi66+0MP02K69ekN4FIP/AMQYTIHtePB9/eu+uV nw56nqKih27yQVLLt2Qr2PSK9/m0rSzHtJDT+mXE= Received: by simark.ca (Postfix, from userid 112) id CFD5C1E0BC; Fri, 03 Apr 2026 21:26:26 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-2.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,RCVD_IN_VALIDITY_CERTIFIED_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED,RCVD_IN_VALIDITY_SAFE_BLOCKED autolearn=ham autolearn_force=no version=4.0.1 Authentication-Results: simark.ca; dkim=pass (1024-bit key; unprotected) header.d=simark.ca header.i=@simark.ca header.a=rsa-sha256 header.s=mail header.b=Q/tZjD1g; dkim-atps=neutral Received: from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 077031E08C for ; Fri, 03 Apr 2026 21:26:25 -0400 (EDT) Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 013B24BA9000 for ; Sat, 4 Apr 2026 01:26:24 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 013B24BA9000 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=simark.ca header.i=@simark.ca header.a=rsa-sha256 header.s=mail header.b=Q/tZjD1g Received: from simark.ca (simark.ca [158.69.221.121]) by sourceware.org (Postfix) with ESMTPS id C06634BA23C3 for ; Sat, 4 Apr 2026 01:25:53 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org C06634BA23C3 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=simark.ca Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=simark.ca ARC-Filter: OpenARC Filter v1.0.0 sourceware.org C06634BA23C3 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=158.69.221.121 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1775265954; cv=none; b=ORBqPSNBFqfm7j2C4GXn0ZitgCR+x+/8OX2rKTSI6YEVIZMMVjQ3Q7XHwp+cJQovAlCSZT9Mp9xl5rA31TbVNbR7a/at5RVfSgkELFW8xsqnYF8Encf7cthy4rGfvm2dJj4Hc01QCbeVFvN1/GaEXIGLQS2bVPRvIcHmRy4jS9Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1775265954; c=relaxed/simple; bh=BC/WLwKeqMWMYF3wz4oOrfibuDYWiX5TImIunyCApEs=; h=DKIM-Signature:Message-ID:Date:MIME-Version:Subject:To:From; b=gxDZHi5W4tBdPz7LYRRc7b+vsIKirk4+Xuz91GhSjWOGSMIFzVBLA40Fb2bhOcghVR8C/BdC1L83NrCrcXwJ5ASaWauvclvSle+DVl//rff4NlPevUGVnSLWVjJzTc/ct3gjOuDQBFp0f/jquZDpsLUIlcU1Wmb7PEOMLRDCmxM= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C06634BA23C3 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=simark.ca; s=mail; t=1775265952; bh=BC/WLwKeqMWMYF3wz4oOrfibuDYWiX5TImIunyCApEs=; h=Date:Subject:To:Cc:References:From:In-Reply-To:From; b=Q/tZjD1gioukf5QT31i8WiMjGNdVLm3ZlwJ1MYDHIPFF/GQtOWdV4RtJUyyxCLAGw ojgfLbTbn3XyhbMHpOlC6yr3fIUCgHtXAE90keG8hdmYb1S1NxR2+HOzQQGKwAHsr4 pqr+zm4X6vifIcbgoGg2mV7v6YGSU0Wvb0rTZpUk= Received: by simark.ca (Postfix) id 878251E08C; Fri, 03 Apr 2026 21:25:52 -0400 (EDT) Message-ID: <1716df2d-07a7-43a1-905e-3ede2efb1ef8@simark.ca> Date: Fri, 3 Apr 2026 21:25:52 -0400 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PATCH v2 1/2] gdb/testsuite: add .debug_frame support in DWARF assembler To: simon.marchi@polymtl.ca, gdb-patches@sourceware.org Cc: Simon Marchi References: <20260316172239.349677-2-simon.marchi@efficios.com> <20260318202801.2030268-1-simon.marchi@polymtl.ca> Content-Language: en-US From: Simon Marchi In-Reply-To: <20260318202801.2030268-1-simon.marchi@polymtl.ca> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org Ping. On 2026-03-18 16:27, simon.marchi@polymtl.ca wrote: > From: Simon Marchi > > Add support to the DWARF assembler for generating .debug_frame sections. > My initial use case is to reproduce a crash happening when encountering > an empty FDE, but I suppose that other use cases will pop up in the > future. > > - Generate procs for the `DW_CFA_*` constants, similar to how the > DW_OP_* constants are handled. These `DW_CFA_*` procs are expected > to be used in the CIE and FDE bodies, described below. > > - Add handlers for `DW_CFA_*` operations that take arguments. I tried > to cover everything that is in DWARF 5. > > - Add the `frame` proc, used to generate one .debug_frame section. > > - Add the `_frame_CIE` proc (available as `CIE` in the context of the > frame proc), used to generate one Common Information Entry. > > - Add the `_frame_FDE` proc (available as `FDE` in the context of the > frame proc), used to generate one Frame Description Entry. > > Due to the nature of the .debug_frame contents (it describes how > specific machine registers get saved), I expect that most of > the tests written using this will be arch-specific. But I think it > will still be useful, as it will let us craft .debug_frame sections to > look exactly how we want. > > I included a test (gdb.dwarf2/debug-frame.exp), which is more like a > proof that we can build something useful using this, and can serve as an > example for whoever wants to write a test case using this in the future. > > Change-Id: I048568ded53883abf52d70139e5cd3e7b4ac3841 > --- > gdb/testsuite/gdb.dwarf2/debug-frame.S | 101 ++++++ > gdb/testsuite/gdb.dwarf2/debug-frame.exp | 130 ++++++++ > gdb/testsuite/lib/dwarf.exp | 394 ++++++++++++++++++++++- > 3 files changed, 624 insertions(+), 1 deletion(-) > create mode 100644 gdb/testsuite/gdb.dwarf2/debug-frame.S > create mode 100644 gdb/testsuite/gdb.dwarf2/debug-frame.exp > > diff --git a/gdb/testsuite/gdb.dwarf2/debug-frame.S b/gdb/testsuite/gdb.dwarf2/debug-frame.S > new file mode 100644 > index 000000000000..231e2dc23704 > --- /dev/null > +++ b/gdb/testsuite/gdb.dwarf2/debug-frame.S > @@ -0,0 +1,101 @@ > +/* Copyright 2026 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 . */ > + > +/* Hand-written x86-64 assembly with no .cfi directives. The .debug_frame > + section is supplied by the companion -dw.S file, generated by the DWARF > + assembler. > + > + The call chain: main -> caller -> callee. > + > + caller sets some known register values, and callee saves those registers in > + different way. */ > + > + .text > + > +/* main */ > + .globl main > + .type main, @function > +main: > + pushq %rbp > + .globl main_after_push_rbp > +main_after_push_rbp: > + movq %rsp, %rbp > + .globl main_after_set_rbp > +main_after_set_rbp: > + call caller > + xorl %eax, %eax > + popq %rbp > + ret > + .size main, . - main > + .globl main_end > +main_end: > + .globl main_len > + .set main_len, main_end - main > + > +/* caller */ > + .globl caller > + .type caller, @function > +caller: > + pushq %rbp > + .globl caller_after_push_rbp > +caller_after_push_rbp: > + movq %rsp, %rbp > + .globl caller_after_set_rbp > +caller_after_set_rbp: > + movq $0x11223344, %r12 > + movq $0x55667788, %r13 > + .globl caller_call_callee > +caller_call_callee: > + call callee > + popq %rbp > + ret > + .size caller, . - caller > + .globl caller_end > +caller_end: > + .globl caller_len > + .set caller_len, caller_end - caller > + > +/* callee */ > + .globl callee > + .type callee, @function > +callee: > + pushq %rbp > + .globl callee_after_push_rbp > +callee_after_push_rbp: > + movq %rsp, %rbp > + .globl callee_after_set_rbp > +callee_after_set_rbp: > + /* Save r12 in the stack, then clobber it. */ > + pushq %r12 > + xorq %r12, %r12 > + /* Save r13 in rax, then clobber it. */ > + movq %r13, %rax > + xorq %r13, %r13 > + /* Clobber r14. This one is described with a DWARF expression. */ > + xorq %r14, %r14 > + .globl callee_body > +callee_body: > + nop > + movq %rax, %r13 > + popq %r12 > + popq %rbp > + ret > + .size callee, . - callee > + .globl callee_end > +callee_end: > + .globl callee_len > + .set callee_len, callee_end - callee > + > + .section .note.GNU-stack,"",@progbits > diff --git a/gdb/testsuite/gdb.dwarf2/debug-frame.exp b/gdb/testsuite/gdb.dwarf2/debug-frame.exp > new file mode 100644 > index 000000000000..ddadab7566ef > --- /dev/null > +++ b/gdb/testsuite/gdb.dwarf2/debug-frame.exp > @@ -0,0 +1,130 @@ > +# Copyright 2026 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 . > + > +# Test that GDB can unwind using a .debug_frame section generated by > +# the DWARF assembler. > +# > +# This test is amd64-specific, but could be ported to other > +# architectures if needed. > + > +load_lib dwarf.exp > + > +require dwarf2_support is_x86_64_m64_target > + > +standard_testfile .S -dw.S > + > +# AMD64 DWARF register numbers. > +set rax 0 > +set rbp 6 > +set rsp 7 > +set r12 12 > +set r13 13 > +set r14 14 > +set rip 16 > + > +foreach_with_prefix is_64 { false true } { > + set asm_file [standard_output_file ${testfile}-${is_64}-dw.S] > + > + Dwarf::assemble $asm_file { > + frame { > + declare_labels cie_label > + > + cie_label: CIE { > + return_address_register $::rip > + data_alignment_factor -8 > + is_64 $::is_64 > + } { > + DW_CFA_def_cfa $::rsp 8 > + DW_CFA_offset $::rip 1 > + } > + > + # FDE for main > + FDE $cie_label main main_len { > + is_64 $::is_64 > + } { > + DW_CFA_set_loc main_after_push_rbp > + DW_CFA_def_cfa_offset 16 > + DW_CFA_offset $::rbp 2 > + DW_CFA_set_loc main_after_set_rbp > + DW_CFA_def_cfa_register $::rbp > + } > + > + # FDE for caller > + FDE $cie_label caller caller_len { > + is_64 $::is_64 > + } { > + DW_CFA_set_loc caller_after_push_rbp > + DW_CFA_def_cfa_offset 16 > + DW_CFA_offset $::rbp 2 > + DW_CFA_set_loc caller_after_set_rbp > + DW_CFA_def_cfa_register $::rbp > + } > + > + # FDE for callee > + FDE $cie_label callee callee_len { > + is_64 $::is_64 > + } { > + DW_CFA_set_loc callee_after_push_rbp > + DW_CFA_def_cfa_offset 16 > + DW_CFA_offset $::rbp 2 > + DW_CFA_set_loc callee_after_set_rbp > + DW_CFA_def_cfa_register $::rbp > + > + DW_CFA_set_loc callee_body > + DW_CFA_offset $::r12 3 > + DW_CFA_register $::r13 $::rax > + > + # r14's value is computed by an arbitrary expression. > + DW_CFA_val_expression $::r14 { > + DW_OP_constu 0x99aabbcc > + } > + } > + } > + } > + > + if { [prepare_for_testing "failed to prepare" ${testfile}-${is_64} \ > + [list $srcfile $asm_file] {nodebug}] } { > + continue > + } > + > + # Stop in caller before the call, to capture rbp. > + if { ![runto caller_call_callee] } { > + continue > + } > + > + set caller_rbp [get_hexadecimal_valueof "\$rbp" "UNKNOWN"] > + > + # Stop inside callee. > + gdb_breakpoint callee_body > + gdb_continue_to_breakpoint "callee_body" > + > + # Verify backtrace shows the full call chain. > + gdb_test "bt" "#0.*callee.*\r\n#1.*caller.*\r\n#2.*main.*" > + > + # Select caller's frame and check saved registers. > + gdb_test "frame 1" "#1.*caller.*" > + > + # r12 was saved on the stack by callee. > + gdb_test "p/x \$r12" "= 0x11223344" > + > + # r13 was saved in rax by callee. > + gdb_test "p/x \$r13" "= 0x55667788" > + > + # r14's value is computed by a DWARF expression. > + gdb_test "p/x \$r14" "= 0x99aabbcc" > + > + # rbp should match what caller had. > + gdb_test "p/x \$rbp" "= ${caller_rbp}" > +} > diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp > index 9fa5c4e297da..e545019e065b 100644 > --- a/gdb/testsuite/lib/dwarf.exp > +++ b/gdb/testsuite/lib/dwarf.exp > @@ -602,6 +602,10 @@ namespace eval Dwarf { > variable _loc_addr_size > variable _loc_offset_size > > + # Variables used when generating a .debug_frame section. > + variable _frame_addr_size > + variable _frame_offset_size > + > proc _process_one_constant {name value} { > variable _constants > variable _FORM > @@ -618,7 +622,6 @@ namespace eval Dwarf { > } > > # We only try to shorten some very common things. > - # FIXME: CFA? > switch -exact -- $prefix { > TAG { > # Create two procedures for the tag. These call > @@ -667,6 +670,57 @@ namespace eval Dwarf { > } $name $name $handler] > } > > + CFA { > + # Create procs for DW_CFA_* instructions, used in > + # .debug_frame CIE/FDE bodies. > + > + # DW_CFA_advance_loc, DW_CFA_offset and > + # DW_CFA_restore encode the operand in the low 6 > + # bits of the opcode byte. They need special > + # handling. > + switch -exact -- $name { > + DW_CFA_advance_loc { > + proc DW_CFA_advance_loc {delta} { > + _op .byte \ > + "$Dwarf::_constants(DW_CFA_advance_loc) + $delta" \ > + DW_CFA_advance_loc > + } > + } > + > + DW_CFA_offset { > + proc DW_CFA_offset {register offset} { > + _op .byte \ > + "$Dwarf::_constants(DW_CFA_offset) + $register" \ > + DW_CFA_offset > + _op .uleb128 $offset "offset" > + } > + } > + > + DW_CFA_restore { > + proc DW_CFA_restore {register} { > + _op .byte \ > + "$Dwarf::_constants(DW_CFA_restore) + $register" \ > + DW_CFA_restore > + } > + } > + > + default { > + # Standard CFA instruction: emit opcode > + # byte then delegate to handler. > + set handler _handle_default_CFA > + if {[llength [info procs _handle_$name]] > 0} { > + set handler _handle_$name > + } > + > + # tclint-disable-next-line command-args > + proc $name {args} [format { > + _op .byte $Dwarf::_constants(%s) %s > + %s {*}$args > + } $name $name $handler] > + } > + } > + } > + > default { > return > } > @@ -1456,6 +1510,127 @@ namespace eval Dwarf { > # error. > } > > + # Helper to emit a DWARF expression block (ULEB128 length followed > + # by the expression bytes) inside a .debug_frame CIE or FDE body. > + # BODY is a Tcl code containing DW_OP_* calls. > + proc _emit_cfa_expression {body} { > + set start [new_label "cfa_expr_start"] > + set end [new_label "cfa_expr_end"] > + _op .uleb128 "$end - $start" "expression length" > + define_label $start > + > + # Pass 5 as the DWARF version, since we need to pass something, but it > + # doesn't matter. The DWARF version is checked only for DW_OP_* ops > + # that don't make sense in CFI. > + _location $body 5 $Dwarf::_frame_addr_size $Dwarf::_frame_offset_size > + define_label $end > + } > + > + # > + # Handlers for DW_CFA_* instructions. > + # > + # A handler is only needed if the instruction requires operands. > + # Generic code handles emitting the opcode byte itself, so a > + # handler should not do this. > + # > + # Handlers are found by name when processing the .def file. If a > + # handler isn't found, the default (_handle_default_CFA) is used. > + # > + > + proc _handle_default_CFA {} { > + # Do nothing; if arguments are passed, Tcl will cause an > + # error. > + } > + > + proc _handle_DW_CFA_set_loc {address} { > + _op .${Dwarf::_frame_addr_size}byte $address "address" > + } > + > + proc _handle_DW_CFA_advance_loc1 {delta} { > + _op .byte $delta "delta" > + } > + > + proc _handle_DW_CFA_advance_loc2 {delta} { > + _op .2byte $delta "delta" > + } > + > + proc _handle_DW_CFA_advance_loc4 {delta} { > + _op .4byte $delta "delta" > + } > + > + proc _handle_DW_CFA_offset_extended {register offset} { > + _op .uleb128 $register "register" > + _op .uleb128 $offset "offset" > + } > + > + proc _handle_DW_CFA_restore_extended {register} { > + _op .uleb128 $register "register" > + } > + > + proc _handle_DW_CFA_undefined {register} { > + _op .uleb128 $register "register" > + } > + > + proc _handle_DW_CFA_same_value {register} { > + _op .uleb128 $register "register" > + } > + > + proc _handle_DW_CFA_register {register1 register2} { > + _op .uleb128 $register1 "register" > + _op .uleb128 $register2 "register" > + } > + > + proc _handle_DW_CFA_def_cfa {register offset} { > + _op .uleb128 $register "register" > + _op .uleb128 $offset "offset" > + } > + > + proc _handle_DW_CFA_def_cfa_register {register} { > + _op .uleb128 $register "register" > + } > + > + proc _handle_DW_CFA_def_cfa_offset {offset} { > + _op .uleb128 $offset "offset" > + } > + > + proc _handle_DW_CFA_def_cfa_expression {body} { > + _emit_cfa_expression $body > + } > + > + proc _handle_DW_CFA_expression {register body} { > + _op .uleb128 $register "register" > + _emit_cfa_expression $body > + } > + > + proc _handle_DW_CFA_offset_extended_sf {register offset} { > + _op .uleb128 $register "register" > + _op .sleb128 $offset "offset" > + } > + > + proc _handle_DW_CFA_def_cfa_sf {register offset} { > + _op .uleb128 $register "register" > + _op .sleb128 $offset "offset" > + } > + > + proc _handle_DW_CFA_def_cfa_offset_sf {offset} { > + _op .sleb128 $offset "offset" > + } > + > + proc _handle_DW_CFA_val_offset {register offset} { > + _op .uleb128 $register "register" > + _op .uleb128 $offset "offset" > + } > + > + proc _handle_DW_CFA_val_offset_sf {register offset} { > + _op .uleb128 $register "register" > + _op .sleb128 $offset "offset" > + } > + > + proc _handle_DW_CFA_val_expression {register body} { > + _op .uleb128 $register "register" > + _emit_cfa_expression $body > + } > + > # This is a miniature assembler for location expressions. It is > # suitable for use in the attributes to a DIE. > # > @@ -3554,6 +3729,223 @@ namespace eval Dwarf { > debug_str_offsets_end: > } > > + # Emit a DWARF .debug_frame section. > + # > + # BODY is Tcl code that emits the CIEs and FDEs which make up the > + # section. It is evaluated in the caller's context. > + # > + # Within BODY, the following commands are available: > + # > + # CIE options body > + # -- emit a Common Information Entry. See _frame_CIE for details. > + # > + # FDE cie_label initial_location address_range body > + # -- emit a Frame Description Entry. See _frame_FDE for details. > + proc frame { body } { > + _section .debug_frame > + > + with_override Dwarf::CIE Dwarf::_frame_CIE { > + with_override Dwarf::FDE Dwarf::_frame_FDE { > + uplevel $Dwarf::_level $body > + } > + } > + } > + > + # Available as proc CIE when in the body of proc debug_frame. > + # > + # OPTIONS is a list of option-name/option-value pairs. Supported > + # options are (default values are shown in parentheses): > + # > + # is_64 (false) > + # -- if true, emit a 64-bit CIE. > + # > + # cie_id (default) > + # -- the CIE id value. When "default", uses 0xffffffff for > + # 32-bit and 0xffffffffffffffff for 64-bit. Should typically not be > + # used unless trying to craft an invalid CIE. > + # > + # version (4) > + # -- the CIE version number. Note that this is version independent > + # from the DWARF version. DWARF 4 and 5 both use .debug_frame > + # version 4. > + # > + # augmentation ("") > + # -- the augmentation string. > + # > + # addr_size (default) > + # -- the address size in bytes. When "default", use 8 for 64-bit > + # targets and 4 for 32-bit targets. > + # > + # segment_selector_size (0) > + # -- the segment selector size in bytes. > + # > + # code_alignment_factor (1) > + # -- the code alignment factor. > + # > + # data_alignment_factor (1) > + # -- the data alignment factor. > + # > + # return_address_register (0) > + # -- the number of the "column" containing the return address. > + # > + # BODY is Tcl code that emits the CIE's initial instructions using > + # DW_CFA_* operations. It is evaluated in the caller's context. > + proc _frame_CIE {options body} { > + parse_options { > + { is_64 false } > + { cie_id default } > + { version 4 } > + { augmentation "" } > + { addr_size default } > + { segment_selector_size 0 } > + { code_alignment_factor 1 } > + { data_alignment_factor 1 } > + { return_address_register 0 } > + } > + > + if { $is_64 } { > + set Dwarf::_frame_offset_size 8 > + } else { > + set Dwarf::_frame_offset_size 4 > + } > + > + if { $cie_id == "default" } { > + if { $is_64 } { > + set cie_id 0xffffffffffffffff > + } else { > + set cie_id 0xffffffff > + } > + } > + > + if {$addr_size == "default"} { > + if {[is_64_target]} { > + set Dwarf::_frame_addr_size 8 > + } else { > + set Dwarf::_frame_addr_size 4 > + } > + } else { > + set Dwarf::_frame_addr_size $addr_size > + } > + > + declare_labels cie_post_length cie_end > + > + # Length. > + if { $is_64 } { > + _op .4byte 0xffffffff "length 1/2" > + _op .8byte "$cie_end - $cie_post_length" "length 2/2" > + } else { > + _op .4byte "$cie_end - $cie_post_length" "length" > + } > + > + define_label $cie_post_length > + > + # CIE_id > + _op .${Dwarf::_frame_offset_size}byte $cie_id "CIE_id" > + > + # Version. > + _op .byte $version "version" > + > + # Augmentation string. > + _op .ascii [_quote $augmentation] "augmentation" > + > + # Address size. > + _op .byte $Dwarf::_frame_addr_size "address_size" > + > + # Segment selector size. > + _op .byte 0 "segment_size" > + > + # Code alignment factor. > + _op .uleb128 $code_alignment_factor "code_alignment_factor" > + > + # Data alignment factor. > + _op .sleb128 $data_alignment_factor "data_alignment_factor" > + > + # Return address register. > + _op .uleb128 $return_address_register "return_address_register" > + > + # Initial instructions. > + uplevel $Dwarf::_level $body > + > + # Padding up to the address size. Fill with DW_CFA_nop (zeroes). > + _op .align $Dwarf::_frame_addr_size "padding" > + > + define_label $cie_end > + } > + > + # Available as proc FDE when in the body of proc debug_frame. > + # > + # CIE_LABEL is the label of the CIE this FDE refers to. > + # > + # INITIAL_LOCATION is the address of the first instruction covered > + # by this FDE. > + # > + # ADDRESS_RANGE is the number of bytes of instructions covered by > + # this FDE. > + # > + # OPTIONS is a list of option-name/option-value pairs. Supported > + # options are (default values are shown in parentheses): > + # > + # is_64 (false) > + # -- if true, emit a 64-bit CIE. > + # > + # addr_size (default) > + # -- the address size in bytes. When "default", use 8 for 64-bit > + # targets and 4 for 32-bit targets. > + # > + # BODY is Tcl code that emits the FDE's call frame instructions using > + # DW_CFA_* operations. It is evaluated in the caller's context. > + proc _frame_FDE { cie_label initial_location address_range options > + body } { > + parse_options { > + { is_64 false } > + { addr_size default } > + } > + > + if { $is_64 } { > + set Dwarf::_frame_offset_size 8 > + } else { > + set Dwarf::_frame_offset_size 4 > + } > + > + if {$addr_size == "default"} { > + if {[is_64_target]} { > + set Dwarf::_frame_addr_size 8 > + } else { > + set Dwarf::_frame_addr_size 4 > + } > + } else { > + set Dwarf::_frame_addr_size $addr_size > + } > + > + declare_labels fde_post_length fde_end > + > + # Length. > + if { $is_64 } { > + _op .4byte 0xffffffff "length 1/2" > + _op .8byte "$fde_end - $fde_post_length" "length 2/2" > + } else { > + _op .4byte "$fde_end - $fde_post_length" "length" > + } > + define_label $fde_post_length > + > + # CIE pointer, offset of the CIE into the .debug_frame section. > + _op .${Dwarf::_frame_offset_size}byte $cie_label "CIE pointer" > + > + # Initial location. > + _op .${Dwarf::_frame_addr_size}byte $initial_location "initial_location" > + > + # Address range. > + _op .${Dwarf::_frame_addr_size}byte $address_range "address_range" > + > + # Instructions. > + uplevel $Dwarf::_level $body > + > + # Padding up to the address size. Fill with DW_CFA_nop (zeroes). > + _op .align $Dwarf::_frame_addr_size "padding" > + > + define_label $fde_end > + } > + > # The top-level interface to the DWARF assembler. > # OPTIONS is a list with an even number of elements containing > # option-name and option-value pairs. > > base-commit: bd40fc073ae0c30f8ad40623e9f40da1be09b0e5