Automatic Copyright Year update after running gdb/copyright.py
[binutils-gdb.git] / gdb / testsuite / lib / dwarf.exp
blob6e8b1ccbe7f30b8a7a00830e3b9b30e9536e0902
1 # Copyright 2010-2022 Free Software Foundation, Inc.
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 3 of the License, or
6 # (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 # Return true if the target supports DWARF-2 and uses gas.
17 # For now pick a sampling of likely targets.
18 proc dwarf2_support {} {
19     if {[istarget *-*-linux*]
20         || [istarget *-*-gnu*]
21         || [istarget *-*-elf*]
22         || [istarget *-*-openbsd*]
23         || [istarget arm*-*-eabi*]
24         || [istarget powerpc-*-eabi*]} {
25         return 1
26     }
28     return 0
31 # Use 'objcopy --extract-dwo to extract DWO information from
32 # OBJECT_FILE and place it into DWO_FILE.
34 # Return 0 on success, otherwise, return -1.
35 proc extract_dwo_information { object_file dwo_file } {
36     set objcopy [gdb_find_objcopy]
37     set command "$objcopy --extract-dwo $object_file $dwo_file"
38     verbose -log "Executing $command"
39     set result [catch "exec $command" output]
40     verbose -log "objcopy --extract-dwo output: $output"
41     if { $result == 1 } {
42         return -1
43     }
44     return 0
47 # Use 'objcopy --strip-dwo to remove DWO information from
48 # FILENAME.
50 # Return 0 on success, otherwise, return -1.
51 proc strip_dwo_information { filename } {
52     set objcopy [gdb_find_objcopy]
53     set command "$objcopy --strip-dwo $filename"
54     verbose -log "Executing $command"
55     set result [catch "exec $command" output]
56     verbose -log "objcopy --strip-dwo output: $output"
57     if { $result == 1 } {
58         return -1
59     }
60     return 0
63 # Build an executable, with the debug information split out into a
64 # separate .dwo file.
66 # This function is based on build_executable_from_specs in
67 # lib/gdb.exp, but with threading support, and rust support removed.
69 # TESTNAME is the name of the test; this is passed to 'untested' if
70 # something fails.
72 # EXECUTABLE is the executable to create, this can be an absolute
73 # path, or a relative path, in which case the EXECUTABLE will be
74 # created in the standard output directory.
76 # OPTIONS is passed to the final link, using gdb_compile.  If OPTIONS
77 # contains any option that indicates threads is required, of if the
78 # option rust is included, then this function will return failure.
80 # ARGS is a series of lists.  Each list is a spec for one source file
81 # that will be compiled to make EXECUTABLE.  Each spec in ARGS has the
82 # form:
83 #       [ SOURCE OPTIONS ]
84 # or:
85 #       [ SOURCE OPTIONS OBJFILE ]
87 # Where SOURCE is the path to the source file to compile.  This can be
88 # absolute, or relative to the standard global ${subdir}/${srcdir}/
89 # path.
91 # OPTIONS are the options to use when compiling SOURCE into an object
92 # file.
94 # OBJFILE is optional, if present this is the name of the object file
95 # to create for SOURCE.  If this is not provided then a suitable name
96 # will be auto-generated.
98 # If OPTIONS contains the option 'split-dwo' then the debug
99 # information is extracted from the object file created by compiling
100 # SOURCE and placed into a file with a dwo extension.  The name of
101 # this file is generated based on the name of the object file that was
102 # created (with the .o replaced with .dwo).
103 proc build_executable_and_dwo_files { testname executable options args } {
104     global subdir
105     global srcdir
107     if { ! [regexp "^/" "$executable"] } then {
108         set binfile [standard_output_file $executable]
109     } else {
110         set binfile $executable
111     }
113     set info_options ""
114     if { [lsearch -exact $options "c++"] >= 0 } {
115         set info_options "c++"
116     }
117     if [get_compiler_info ${info_options}] {
118         return -1
119     }
121     set func gdb_compile
122     if {[lsearch -regexp $options \
123              {^(pthreads|shlib|shlib_pthreads|openmp)$}] != -1} {
124         # Currently don't support compiling thread based tests here.
125         # If this is required then look to build_executable_from_specs
126         # for inspiration.
127         return -1
128     }
129     if {[lsearch -exact $options rust] != -1} {
130         # Currently don't support compiling rust tests here.  If this
131         # is required then look to build_executable_from_specs for
132         # inspiration.
133         return -1
134     }
136     # Must be run on local host due to use of objcopy.
137     if [is_remote host] {
138         return -1
139     }
141     set objects {}
142     set i 0
143     foreach spec $args {
144         if {[llength $spec] < 2} {
145             error "invalid spec length"
146             return -1
147         }
149         verbose -log "APB: SPEC: $spec"
151         set s [lindex $spec 0]
152         set local_options [lindex $spec 1]
154         if { ! [regexp "^/" "$s"] } then {
155             set s "$srcdir/$subdir/$s"
156         }
158         if {[llength $spec] > 2} {
159             set objfile [lindex $spec 2]
160         } else {
161             set objfile "${binfile}${i}.o"
162             incr i
163         }
165         if  { [$func "${s}" "${objfile}" object $local_options] != "" } {
166             untested $testname
167             return -1
168         }
170         lappend objects "$objfile"
172         if {[lsearch -exact $local_options "split-dwo"] >= 0} {
173             # Split out the DWO file.
174             set dwo_file "[file rootname ${objfile}].dwo"
176             if { [extract_dwo_information $objfile $dwo_file] == -1 } {
177                 untested $testname
178                 return -1
179             }
181             if { [strip_dwo_information $objfile] == -1 } {
182                 untested $testname
183                 return -1
184             }
185         }
186     }
188     verbose -log "APB: OBJECTS = $objects"
190     set ret [$func $objects "${binfile}" executable $options]
191     if  { $ret != "" } {
192         untested $testname
193         return -1
194     }
196     return 0
199 # Utility function for procs shared_gdb_*.
201 proc init_shared_gdb {} {
202     global shared_gdb_enabled
203     global shared_gdb_started
205     if { ! [info exists shared_gdb_enabled] } {
206         set shared_gdb_enabled 0
207         set shared_gdb_started 0
208     }
211 # Cluster of four procs:
212 # - shared_gdb_enable
213 # - shared_gdb_disable
214 # - shared_gdb_start_use SRC OPTIONS
215 # - shared_gdb_end_use
217 # Can be used like so:
219 #   {
220 #     if { $share } shared_gdb_enable
221 #     ...
222 #     shared_gdb_start_use $src $options
223 #     ...
224 #     shared_gdb_end_use
225 #     ...
226 #     shared_gdb_start_use $src $options
227 #     ...
228 #     shared_gdb_end_use
229 #     ...
230 #     if { $share } shared_gdb_disable
231 #   }
233 # to write functionalty that could share ($share == 1) or could not
234 # share ($share == 0) a gdb session between two uses.
236 proc shared_gdb_enable {} {
237     set me shared_gdb_enable
239     init_shared_gdb
240     global shared_gdb_enabled
241     global shared_gdb_started
243     if { $shared_gdb_enabled } {
244         error "$me: gdb sharing already enabled"
245     }
246     set shared_gdb_enabled 1
248     if { $shared_gdb_started } {
249         error "$me: gdb sharing not stopped"
250     }
253 # See above.
255 proc shared_gdb_disable {} {
256     init_shared_gdb
257     global shared_gdb_enabled
258     global shared_gdb_started
260     if { ! $shared_gdb_enabled } {
261         error "$me: gdb sharing not enabled"
262     }
263     set shared_gdb_enabled 0
265     if { $shared_gdb_started } {
266         gdb_exit
267         set shared_gdb_started 0
268     }
271 # See above.
273 proc shared_gdb_start_use { src options } {
274     set me shared_gdb_start_use
276     init_shared_gdb
277     global shared_gdb_enabled
278     global shared_gdb_started
279     global shared_gdb_src
280     global shared_gdb_options
282     set do_start 1
283     if { $shared_gdb_enabled && $shared_gdb_started } {
284         if { $shared_gdb_src != $src
285              || $shared_gdb_options != $options } {
286             error "$me: gdb sharing inconsistent"
287         }
289         set do_start 0
290     }
292     if { $do_start } {
293         set exe [standard_temp_file func_addr[pid].x]
295         gdb_compile $src $exe executable $options
297         gdb_exit
298         gdb_start
299         gdb_load "$exe"
301         if { $shared_gdb_enabled } {
302             set shared_gdb_started 1
303             set shared_gdb_src $src
304             set shared_gdb_options $options
305         }
306     }
309 # See above.
311 proc shared_gdb_end_use {} {
312     init_shared_gdb
313     global shared_gdb_enabled
315     if { ! $shared_gdb_enabled } {
316         gdb_exit
317     }
320 # Enable gdb session sharing within BODY.
322 proc with_shared_gdb { body } {
323     shared_gdb_enable
324     set code [catch { uplevel 1 $body } result]
325     shared_gdb_disable
327     # Return as appropriate.
328     if { $code == 1 } {
329         global errorInfo errorCode
330         return -code error -errorinfo $errorInfo -errorcode $errorCode $result
331     } elseif { $code > 1 } {
332         return -code $code $result
333     }
335     return $result
338 # Return a list of expressions about function FUNC's address and length.
339 # The first expression is the address of function FUNC, and the second
340 # one is FUNC's length.  SRC is the source file having function FUNC.
341 # An internal label ${func}_label must be defined inside FUNC:
343 #  int main (void)
344 #  {
345 #    asm ("main_label: .globl main_label");
346 #    return 0;
347 #  }
349 # This label is needed to compute the start address of function FUNC.
350 # If the compiler is gcc, we can do the following to get function start
351 # and end address too:
353 # asm ("func_start: .globl func_start");
354 # static void func (void) {}
355 # asm ("func_end: .globl func_end");
357 # however, this isn't portable, because other compilers, such as clang,
358 # may not guarantee the order of global asms and function.  The code
359 # becomes:
361 # asm ("func_start: .globl func_start");
362 # asm ("func_end: .globl func_end");
363 # static void func (void) {}
366 proc function_range { func src {options {debug}} } {
367     global decimal gdb_prompt
369     shared_gdb_start_use $src $options
371     # Compute the label offset, and we can get the function start address
372     # by "${func}_label - $func_label_offset".
373     set func_label_offset ""
374     set test "p ${func}_label - ${func}"
375     gdb_test_multiple $test $test {
376         -re ".* = ($decimal)\r\n$gdb_prompt $" {
377             set func_label_offset $expect_out(1,string)
378         }
379     }
381     # Compute the function length.
382     global hex
383     set func_length ""
384     set test "disassemble $func"
385     gdb_test_multiple $test $test {
386         -re ".*$hex <\\+($decimal)>:\[^\r\n\]+\r\nEnd of assembler dump\.\r\n$gdb_prompt $" {
387             set func_length $expect_out(1,string)
388         }
389     }
391     # Compute the size of the last instruction.
392     if { $func_length == 0 } then {
393         set func_pattern "$func"
394     } else {
395         set func_pattern "$func\\+$func_length"
396     }
397     set test "x/2i $func+$func_length"
398     gdb_test_multiple $test $test {
399         -re ".*($hex) <$func_pattern>:\[^\r\n\]+\r\n\[ \]+($hex).*\.\r\n$gdb_prompt $" {
400             set start $expect_out(1,string)
401             set end $expect_out(2,string)
403             set func_length [expr $func_length + $end - $start]
404         }
405     }
407     shared_gdb_end_use
409     return [list "${func}_label - $func_label_offset" $func_length]
412 # Extract the start, length, and end for function called NAME and
413 # create suitable variables in the callers scope.
414 # Return the list of created variables.
415 proc get_func_info { name {options {debug}} } {
416     global srcdir subdir srcfile
418     upvar 1 "${name}_start" func_start
419     upvar 1 "${name}_len" func_len
420     upvar 1 "${name}_end" func_end
422     lassign [function_range ${name} \
423                  [list ${srcdir}/${subdir}/$srcfile] \
424                  ${options}]  \
425         func_start func_len
426     set func_end "$func_start + $func_len"
428     return [list \
429                 "${name}_start" \
430                 "${name}_len" \
431                 "${name}_end"]
434 # A DWARF assembler.
436 # All the variables in this namespace are private to the
437 # implementation.  Also, any procedure whose name starts with "_" is
438 # private as well.  Do not use these.
440 # Exported functions are documented at their definition.
442 # In addition to the hand-written functions documented below, this
443 # module automatically generates a function for each DWARF tag.  For
444 # most tags, two forms are made: a full name, and one with the
445 # "DW_TAG_" prefix stripped.  For example, you can use either
446 # 'DW_TAG_compile_unit' or 'compile_unit' interchangeably.
448 # There are two exceptions to this rule: DW_TAG_variable and
449 # DW_TAG_namespace.  For these, the full name must always be used,
450 # as the short name conflicts with Tcl builtins.  (Should future
451 # versions of Tcl or DWARF add more conflicts, this list will grow.
452 # If you want to be safe you should always use the full names.)
454 # Each tag procedure is defined like:
456 # proc DW_TAG_mumble {{attrs {}} {children {}}} { ... }
458 # ATTRS is an optional list of attributes.
459 # It is run through 'subst' in the caller's context before processing.
461 # Each attribute in the list has one of two forms:
462 #   1. { NAME VALUE }
463 #   2. { NAME VALUE FORM }
465 # In each case, NAME is the attribute's name.
466 # This can either be the full name, like 'DW_AT_name', or a shortened
467 # name, like 'name'.  These are fully equivalent.
469 # Besides DWARF standard attributes, assembler supports 'macro' attribute
470 # which will be substituted by one or more standard or macro attributes.
471 # supported macro attributes are:
473 #  - MACRO_AT_range { FUNC }
474 #  It is substituted by DW_AT_low_pc and DW_AT_high_pc with the start and
475 #  end address of function FUNC in file $srcdir/$subdir/$srcfile.
477 #  - MACRO_AT_func { FUNC }
478 #  It is substituted by DW_AT_name with FUNC and MACRO_AT_range.
480 # If FORM is given, it should name a DW_FORM_ constant.
481 # This can either be the short form, like 'DW_FORM_addr', or a
482 # shortened version, like 'addr'.  If the form is given, VALUE
483 # is its value; see below.  In some cases, additional processing
484 # is done; for example, DW_FORM_strp manages the .debug_str
485 # section automatically.
487 # If FORM is 'SPECIAL_expr', then VALUE is treated as a location
488 # expression.  The effective form is then DW_FORM_block or DW_FORM_exprloc
489 # for DWARF version >= 4, and VALUE is passed to the (internal)
490 # '_location' proc to be translated.
491 # This proc implements a miniature DW_OP_ assembler.
493 # If FORM is not given, it is guessed:
494 # * If VALUE starts with the "@" character, the rest of VALUE is
495 #   looked up as a DWARF constant, and DW_FORM_sdata is used.  For
496 #   example, '@DW_LANG_c89' could be used.
497 # * If VALUE starts with the ":" character, then it is a label
498 #   reference.  The rest of VALUE is taken to be the name of a label,
499 #   and DW_FORM_ref4 is used.  See 'new_label' and 'define_label'.
500 # * If VALUE starts with the "%" character, then it is a label
501 #   reference too, but DW_FORM_ref_addr is used.
502 # * Otherwise, if the attribute name has a default form (f.i. DW_FORM_addr for
503 #   DW_AT_low_pc), then that one is used.
504 # * Otherwise, an error is reported.  Either specify a form explicitly, or
505 #   add a default for the the attribute name in _default_form.
507 # CHILDREN is just Tcl code that can be used to define child DIEs.  It
508 # is evaluated in the caller's context.
510 # Currently this code is missing nice support for CFA handling, and
511 # probably other things as well.
513 namespace eval Dwarf {
514     # True if the module has been initialized.
515     variable _initialized 0
517     # Constants from dwarf2.h.
518     variable _constants
519     # DW_AT short names.
520     variable _AT
521     # DW_FORM short names.
522     variable _FORM
523     # DW_OP short names.
524     variable _OP
526     # The current output file.
527     variable _output_file
529     # Note: The _cu_ values here also apply to type units (TUs).
530     # Think of a TU as a special kind of CU.
532     # Current CU count.
533     variable _cu_count
535     # The current CU's base label.
536     variable _cu_label
538     # The current CU's version.
539     variable _cu_version
541     # The current CU's address size.
542     variable _cu_addr_size
543     # The current CU's offset size.
544     variable _cu_offset_size
546     # Label generation number.
547     variable _label_num
549     # The deferred output array.  The index is the section name; the
550     # contents hold the data for that section.
551     variable _deferred_output
553     # If empty, we should write directly to the output file.
554     # Otherwise, this is the name of a section to write to.
555     variable _defer
557     # The abbrev section.  Typically .debug_abbrev but can be .debug_abbrev.dwo
558     # for Fission.
559     variable _abbrev_section
561     # The next available abbrev number in the current CU's abbrev
562     # table.
563     variable _abbrev_num
565     # The string table for this assembly.  The key is the string; the
566     # value is the label for that string.
567     variable _strings
569     # Current .debug_line unit count.
570     variable _line_count
572     # Whether a file_name entry was seen.
573     variable _line_saw_file
575     # Whether a line table program has been seen.
576     variable _line_saw_program
578     # A Label for line table header generation.
579     variable _line_header_end_label
581     # The address size for debug ranges section.
582     variable _debug_ranges_64_bit
584     # The index into the .debug_addr section (used for fission
585     # generation).
586     variable _debug_addr_index
588     # Flag, true if the current CU is contains fission information,
589     # otherwise false.
590     variable _cu_is_fission
592     proc _process_one_constant {name value} {
593         variable _constants
594         variable _AT
595         variable _FORM
596         variable _OP
598         set _constants($name) $value
600         if {![regexp "^DW_(\[A-Z\]+)_(\[A-Za-z0-9_\]+)$" $name \
601                   ignore prefix name2]} {
602             error "non-matching name: $name"
603         }
605         if {$name2 == "lo_user" || $name2 == "hi_user"} {
606             return
607         }
609         # We only try to shorten some very common things.
610         # FIXME: CFA?
611         switch -exact -- $prefix {
612             TAG {
613                 # Create two procedures for the tag.  These call
614                 # _handle_DW_TAG with the full tag name baked in; this
615                 # does all the actual work.
616                 proc $name {{attrs {}} {children {}}} \
617                     "_handle_DW_TAG $name \$attrs \$children"
619                 # Filter out ones that are known to clash.
620                 if {$name2 == "variable" || $name2 == "namespace"} {
621                     set name2 "tag_$name2"
622                 }
624                 if {[info commands $name2] != {}} {
625                     error "duplicate proc name: from $name"
626                 }
628                 proc $name2 {{attrs {}} {children {}}} \
629                     "_handle_DW_TAG $name \$attrs \$children"
630             }
632             AT {
633                 set _AT($name2) $name
634             }
636             FORM {
637                 set _FORM($name2) $name
638             }
640             OP {
641                 set _OP($name2) $name
642             }
644             default {
645                 return
646             }
647         }
648     }
650     proc _read_constants {} {
651         global srcdir hex decimal
653         # DWARF name-matching regexp.
654         set dwrx "DW_\[a-zA-Z0-9_\]+"
655         # Whitespace regexp.
656         set ws "\[ \t\]+"
658         set fd [open [file join $srcdir .. .. include dwarf2.h]]
659         while {![eof $fd]} {
660             set line [gets $fd]
661             if {[regexp -- "^${ws}($dwrx)${ws}=${ws}($hex|$decimal),?$" \
662                      $line ignore name value ignore2]} {
663                 _process_one_constant $name $value
664             }
665         }
666         close $fd
668         set fd [open [file join $srcdir .. .. include dwarf2.def]]
669         while {![eof $fd]} {
670             set line [gets $fd]
671             if {[regexp -- \
672                      "^DW_\[A-Z_\]+${ws}\\(($dwrx),${ws}($hex|$decimal)\\)$" \
673                      $line ignore name value ignore2]} {
674                 _process_one_constant $name $value
675             }
676         }
677         close $fd
678     }
680     proc _quote {string} {
681         # FIXME
682         return "\"${string}\\0\""
683     }
685     proc _nz_quote {string} {
686         # For now, no quoting is done.
687         return "\"${string}\""
688     }
690     proc _handle_DW_FORM {form value} {
691         switch -exact -- $form {
692             DW_FORM_string  {
693                 _op .ascii [_quote $value]
694             }
696             DW_FORM_flag_present {
697                 # We don't need to emit anything.
698             }
700             DW_FORM_data4 -
701             DW_FORM_ref4 {
702                 _op .4byte $value
703             }
705             DW_FORM_ref_addr {
706                 variable _cu_offset_size
707                 variable _cu_version
708                 variable _cu_addr_size
710                 if {$_cu_version == 2} {
711                     set size $_cu_addr_size
712                 } else {
713                     set size $_cu_offset_size
714                 }
716                 _op .${size}byte $value
717             }
719             DW_FORM_GNU_ref_alt -
720             DW_FORM_GNU_strp_alt -
721             DW_FORM_sec_offset {
722                 variable _cu_offset_size
723                 _op_offset $_cu_offset_size $value
724             }
726             DW_FORM_ref1 -
727             DW_FORM_flag -
728             DW_FORM_data1 {
729                 _op .byte $value
730             }
732             DW_FORM_sdata {
733                 _op .sleb128 $value
734             }
736             DW_FORM_ref_udata -
737             DW_FORM_udata -
738             DW_FORM_loclistx -
739             DW_FORM_rnglistx {
740                 _op .uleb128 $value
741             }
743             DW_FORM_addr {
744                 variable _cu_addr_size
746                 _op .${_cu_addr_size}byte $value
747             }
749             DW_FORM_GNU_addr_index {
750                 variable _debug_addr_index
751                 variable _cu_addr_size
753                 _op .uleb128 ${_debug_addr_index}
754                 incr _debug_addr_index
756                 _defer_output .debug_addr {
757                     _op .${_cu_addr_size}byte $value
758                 }
759             }
761             DW_FORM_data2 -
762             DW_FORM_ref2 {
763                 _op .2byte $value
764             }
766             DW_FORM_data8 -
767             DW_FORM_ref8 -
768             DW_FORM_ref_sig8 {
769                 _op .8byte $value
770             }
772             DW_FORM_data16 {
773                 _op .8byte $value
774             }
776             DW_FORM_strp {
777                 variable _strings
778                 variable _cu_offset_size
780                 if {![info exists _strings($value)]} {
781                     set _strings($value) [new_label strp]
782                     _defer_output .debug_str {
783                         define_label $_strings($value)
784                         _op .ascii [_quote $value]
785                     }
786                 }
788                 _op_offset $_cu_offset_size $_strings($value) "strp: $value"
789             }
791             SPECIAL_expr {
792                 variable _cu_version
793                 variable _cu_addr_size
794                 variable _cu_offset_size
796                 set l1 [new_label "expr_start"]
797                 set l2 [new_label "expr_end"]
798                 _op .uleb128 "$l2 - $l1" "expression"
799                 define_label $l1
800                 _location $value $_cu_version $_cu_addr_size $_cu_offset_size
801                 define_label $l2
802             }
804             DW_FORM_block1 {
805                 set len [string length $value]
806                 if {$len > 255} {
807                     error "DW_FORM_block1 length too long"
808                 }
809                 _op .byte $len
810                 _op .ascii [_nz_quote $value]
811             }
813             DW_FORM_block2 -
814             DW_FORM_block4 -
816             DW_FORM_block -
818             DW_FORM_ref2 -
819             DW_FORM_indirect -
820             DW_FORM_exprloc -
822             DW_FORM_strx -
823             DW_FORM_strx1 -
824             DW_FORM_strx2 -
825             DW_FORM_strx3 -
826             DW_FORM_strx4 -
828             DW_FORM_GNU_str_index -
830             default {
831                 error "unhandled form $form"
832             }
833         }
834     }
836     proc _guess_form {value varname} {
837         upvar $varname new_value
839         switch -exact -- [string range $value 0 0] {
840             @ {
841                 # Constant reference.
842                 variable _constants
844                 set new_value $_constants([string range $value 1 end])
845                 # Just the simplest.
846                 return DW_FORM_sdata
847             }
849             : {
850                 # Label reference.
851                 variable _cu_label
853                 set new_value "[string range $value 1 end] - $_cu_label"
855                 return DW_FORM_ref4
856             }
858             % {
859                 # Label reference, an offset from .debug_info.
860                 set new_value "[string range $value 1 end]"
862                 return DW_FORM_ref_addr
863             }
865             default {
866                 return ""
867             }
868         }
869     }
871     proc _default_form { attr } {
872         switch -exact -- $attr {
873             DW_AT_low_pc  {
874                 return DW_FORM_addr
875             }
876             DW_AT_producer -
877             DW_AT_comp_dir -
878             DW_AT_linkage_name -
879             DW_AT_MIPS_linkage_name -
880             DW_AT_name {
881                 return DW_FORM_string
882             }
883             DW_AT_GNU_addr_base {
884                 return DW_FORM_sec_offset
885             }
886         }
887         return ""
888     }
890     # Map NAME to its canonical form.
891     proc _map_name {name ary} {
892         variable $ary
894         if {[info exists ${ary}($name)]} {
895             set name [set ${ary}($name)]
896         }
898         return $name
899     }
901     proc _handle_attribute { attr_name attr_value attr_form } {
902         variable _abbrev_section
903         variable _constants
904         variable _cu_version
906         _handle_DW_FORM $attr_form $attr_value
908         _defer_output $_abbrev_section {
909             if { $attr_form eq "SPECIAL_expr" } {
910                 if { $_cu_version < 4 } {
911                     set attr_form_comment "DW_FORM_block"
912                 } else {
913                     set attr_form_comment "DW_FORM_exprloc"
914                 }
915             } else {
916                 set attr_form_comment $attr_form
917             }
918             _op .uleb128 $_constants($attr_name) $attr_name
919             _op .uleb128 $_constants($attr_form) $attr_form_comment
920         }
921     }
923     # Handle macro attribute MACRO_AT_range.
925     proc _handle_macro_at_range { attr_value } {
926         variable _cu_is_fission
928         if {[llength $attr_value] != 1} {
929             error "usage: MACRO_AT_range { func }"
930         }
932         set func [lindex $attr_value 0]
933         global srcdir subdir srcfile
934         set src ${srcdir}/${subdir}/${srcfile}
935         set result [function_range $func $src]
937         set form DW_FORM_addr
938         if { $_cu_is_fission } {
939             set form DW_FORM_GNU_addr_index
940         }
942         _handle_attribute DW_AT_low_pc [lindex $result 0] $form
943         _handle_attribute DW_AT_high_pc \
944             "[lindex $result 0] + [lindex $result 1]" $form
945     }
947     # Handle macro attribute MACRO_AT_func.
949     proc _handle_macro_at_func { attr_value } {
950         if {[llength $attr_value] != 1} {
951             error "usage: MACRO_AT_func { func file }"
952         }
953         _handle_attribute DW_AT_name [lindex $attr_value 0] DW_FORM_string
954         _handle_macro_at_range $attr_value
955     }
957     proc _handle_DW_TAG {tag_name {attrs {}} {children {}}} {
958         variable _abbrev_section
959         variable _abbrev_num
960         variable _constants
962         set has_children [expr {[string length $children] > 0}]
963         set my_abbrev [incr _abbrev_num]
965         # We somewhat wastefully emit a new abbrev entry for each tag.
966         # There's no reason for this other than laziness.
967         _defer_output $_abbrev_section {
968             _op .uleb128 $my_abbrev "Abbrev start"
969             _op .uleb128 $_constants($tag_name) $tag_name
970             _op .byte $has_children "has_children"
971         }
973         _op .uleb128 $my_abbrev "Abbrev ($tag_name)"
975         foreach attr $attrs {
976             set attr_name [_map_name [lindex $attr 0] _AT]
978             # When the length of ATTR is greater than 2, the last
979             # element of the list must be a form.  The second through
980             # the penultimate elements are joined together and
981             # evaluated using subst.  This allows constructs such as
982             # [gdb_target_symbol foo] to be used.
984             if {[llength $attr] > 2} {
985                 set attr_value [uplevel 2 [list subst [join [lrange $attr 1 end-1]]]]
986             } else {
987                 set attr_value [uplevel 2 [list subst [lindex $attr 1]]]
988             }
990             if { [string equal "MACRO_AT_func" $attr_name] } {
991                 _handle_macro_at_func $attr_value
992             } elseif { [string equal "MACRO_AT_range" $attr_name] } {
993                 _handle_macro_at_range $attr_value
994             } else {
995                 if {[llength $attr] > 2} {
996                     set attr_form [uplevel 2 [list subst [lindex $attr end]]]
998                     if { [string index $attr_value 0] == ":" } {
999                         # It is a label, get its value.
1000                         _guess_form $attr_value attr_value
1001                     }
1002                 } else {
1003                     set attr_form [_guess_form $attr_value attr_value]
1004                     if { $attr_form eq "" } {
1005                         set attr_form [_default_form $attr_name]
1006                     }
1007                     if { $attr_form eq "" } {
1008                         error "No form for $attr_name $attr_value"
1009                     }
1010                 }
1011                 set attr_form [_map_name $attr_form _FORM]
1013                 _handle_attribute $attr_name $attr_value $attr_form
1014             }
1015         }
1017         _defer_output $_abbrev_section {
1018             # Terminator.
1019             _op .byte 0x0 "DW_AT - Terminator"
1020             _op .byte 0x0 "DW_FORM - Terminator"
1021         }
1023         if {$has_children} {
1024             uplevel 2 $children
1026             # Terminate children.
1027             _op .byte 0x0 "Terminate children"
1028         }
1029     }
1031     proc _emit {string} {
1032         variable _output_file
1033         variable _defer
1034         variable _deferred_output
1036         if {$_defer == ""} {
1037             puts $_output_file $string
1038         } else {
1039             append _deferred_output($_defer) ${string}\n
1040         }
1041     }
1043     proc _section {name {flags ""} {type ""}} {
1044         if {$flags == "" && $type == ""} {
1045             _emit "        .section $name"
1046         } elseif {$type == ""} {
1047             _emit "        .section $name, \"$flags\""
1048         } else {
1049             _emit "        .section $name, \"$flags\", %$type"
1050         }
1051     }
1053     # SECTION_SPEC is a list of arguments to _section.
1054     proc _defer_output {section_spec body} {
1055         variable _defer
1056         variable _deferred_output
1058         set old_defer $_defer
1059         set _defer [lindex $section_spec 0]
1061         if {![info exists _deferred_output($_defer)]} {
1062             set _deferred_output($_defer) ""
1063             eval _section $section_spec
1064         }
1066         uplevel $body
1068         set _defer $old_defer
1069     }
1071     proc _defer_to_string {body} {
1072         variable _defer
1073         variable _deferred_output
1075         set old_defer $_defer
1076         set _defer temp
1078         set _deferred_output($_defer) ""
1080         uplevel $body
1082         set result $_deferred_output($_defer)
1083         unset _deferred_output($_defer)
1085         set _defer $old_defer
1086         return $result
1087     }
1089     proc _write_deferred_output {} {
1090         variable _output_file
1091         variable _deferred_output
1093         foreach section [array names _deferred_output] {
1094             # The data already has a newline.
1095             puts -nonewline $_output_file $_deferred_output($section)
1096         }
1098         # Save some memory.
1099         unset _deferred_output
1100     }
1102     proc _op {name value {comment ""}} {
1103         set text "        ${name}        ${value}"
1104         if {$comment != ""} {
1105             # Try to make stuff line up nicely.
1106             while {[string length $text] < 40} {
1107                 append text " "
1108             }
1109             append text "/* ${comment} */"
1110         }
1111         _emit $text
1112     }
1114     proc _op_offset { size offset {comment ""} } {
1115         if { $size == 4 } {
1116             _op .4byte $offset $comment
1117         } elseif { $size == 8 } {
1118             if {[is_64_target]} {
1119                 _op .8byte $offset $comment
1120             } else {
1121                 # This allows us to emit 64-bit dwarf for
1122                 # 32-bit targets.
1123                 if { [target_endianness] == "little" } {
1124                     _op .4byte $offset "$comment (lsw)"
1125                     _op .4byte 0 "$comment (msw)"
1126                 } else {
1127                     _op .4byte 0 "$comment (msw)"
1128                     _op .4byte $offset "$comment (lsw)"
1129                 }
1130             }
1131         } else {
1132             error "Don't know how to handle offset size $size"
1133         }
1134     }
1136     proc _compute_label {name} {
1137         return ".L${name}"
1138     }
1140     # Return a name suitable for use as a label.  If BASE_NAME is
1141     # specified, it is incorporated into the label name; this is to
1142     # make debugging the generated assembler easier.  If BASE_NAME is
1143     # not specified a generic default is used.  This proc does not
1144     # define the label; see 'define_label'.  'new_label' attempts to
1145     # ensure that label names are unique.
1146     proc new_label {{base_name label}} {
1147         variable _label_num
1149         return [_compute_label ${base_name}[incr _label_num]]
1150     }
1152     # Define a label named NAME.  Ordinarily, NAME comes from a call
1153     # to 'new_label', but this is not required.
1154     proc define_label {name} {
1155         _emit "${name}:"
1156     }
1158     # A higher-level interface to label handling.
1159     #
1160     # ARGS is a list of label descriptors.  Each one is either a
1161     # single element, or a list of two elements -- a name and some
1162     # text.  For each descriptor, 'new_label' is invoked.  If the list
1163     # form is used, the second element in the list is passed as an
1164     # argument.  The label name is used to define a variable in the
1165     # enclosing scope; this can be used to refer to the label later.
1166     # The label name is also used to define a new proc whose name is
1167     # the label name plus a trailing ":".  This proc takes a body as
1168     # an argument and can be used to define the label at that point;
1169     # then the body, if any, is evaluated in the caller's context.
1170     #
1171     # For example:
1172     #
1173     # declare_labels int_label
1174     # something { ... $int_label }   ;# refer to the label
1175     # int_label: constant { ... }    ;# define the label
1176     proc declare_labels {args} {
1177         foreach arg $args {
1178             set name [lindex $arg 0]
1179             set text [lindex $arg 1]
1181             if { $text == "" } {
1182                 set text $name
1183             }
1185             upvar $name label_var
1186             set label_var [new_label $text]
1188             proc ${name}: {args} [format {
1189                 define_label %s
1190                 uplevel $args
1191             } $label_var]
1192         }
1193     }
1195     # Assign elements from LINE to the elements of an array named
1196     # "argvec" in the caller scope.  The keys used are named in ARGS.
1197     # If the wrong number of elements appear in LINE, error.
1198     proc _get_args {line op args} {
1199         if {[llength $line] != [llength $args] + 1} {
1200             error "usage: $op [string toupper $args]"
1201         }
1203         upvar argvec argvec
1204         foreach var $args value [lreplace $line 0 0] {
1205             set argvec($var) $value
1206         }
1207     }
1209     # This is a miniature assembler for location expressions.  It is
1210     # suitable for use in the attributes to a DIE.  Its output is
1211     # prefixed with "=" to make it automatically use DW_FORM_block.
1212     #
1213     # BODY is split by lines, and each line is taken to be a list.
1214     #
1215     # DWARF_VERSION is the DWARF version for the section where the location
1216     # description is found.
1217     #
1218     # ADDR_SIZE is the length in bytes (4 or 8) of an address on the target
1219     # machine (typically found in the header of the section where the location
1220     # description is found).
1221     #
1222     # OFFSET_SIZE is the length in bytes (4 or 8) of an offset into a DWARF
1223     # section.  This typically depends on whether 32-bit or 64-bit DWARF is
1224     # used, as indicated in the header of the section where the location
1225     # description is found.
1226     #
1227     # (FIXME should use 'info complete' here.)
1228     # Each list's first element is the opcode, either short or long
1229     # forms are accepted.
1230     # FIXME argument handling
1231     # FIXME move docs
1232     proc _location { body dwarf_version addr_size offset_size } {
1233         variable _constants
1235         foreach line [split $body \n] {
1236             # Ignore blank lines, and allow embedded comments.
1237             if {[lindex $line 0] == "" || [regexp -- {^[ \t]*#} $line]} {
1238                 continue
1239             }
1240             set opcode [_map_name [lindex $line 0] _OP]
1241             _op .byte $_constants($opcode) $opcode
1243             array unset argvec *
1244             switch -exact -- $opcode {
1245                 DW_OP_addr {
1246                     _get_args $line $opcode size
1247                     _op .${addr_size}byte $argvec(size)
1248                 }
1250                 DW_OP_GNU_addr_index {
1251                     variable _debug_addr_index
1252                     variable _cu_addr_size
1254                     _op .uleb128 ${_debug_addr_index}
1255                     incr _debug_addr_index
1257                     _defer_output .debug_addr {
1258                         _op .${_cu_addr_size}byte [lindex $line 1]
1259                     }
1260                 }
1262                 DW_OP_regx {
1263                     _get_args $line $opcode register
1264                     _op .uleb128 $argvec(register)
1265                 }
1267                 DW_OP_pick -
1268                 DW_OP_const1u -
1269                 DW_OP_const1s {
1270                     _get_args $line $opcode const
1271                     _op .byte $argvec(const)
1272                 }
1274                 DW_OP_const2u -
1275                 DW_OP_const2s {
1276                     _get_args $line $opcode const
1277                     _op .2byte $argvec(const)
1278                 }
1280                 DW_OP_const4u -
1281                 DW_OP_const4s {
1282                     _get_args $line $opcode const
1283                     _op .4byte $argvec(const)
1284                 }
1286                 DW_OP_const8u -
1287                 DW_OP_const8s {
1288                     _get_args $line $opcode const
1289                     _op .8byte $argvec(const)
1290                 }
1292                 DW_OP_constu {
1293                     _get_args $line $opcode const
1294                     _op .uleb128 $argvec(const)
1295                 }
1296                 DW_OP_consts {
1297                     _get_args $line $opcode const
1298                     _op .sleb128 $argvec(const)
1299                 }
1301                 DW_OP_plus_uconst {
1302                     _get_args $line $opcode const
1303                     _op .uleb128 $argvec(const)
1304                 }
1306                 DW_OP_piece {
1307                     _get_args $line $opcode size
1308                     _op .uleb128 $argvec(size)
1309                 }
1311                 DW_OP_bit_piece {
1312                     _get_args $line $opcode size offset
1313                     _op .uleb128 $argvec(size)
1314                     _op .uleb128 $argvec(offset)
1315                 }
1317                 DW_OP_skip -
1318                 DW_OP_bra {
1319                     _get_args $line $opcode label
1320                     _op .2byte $argvec(label)
1321                 }
1323                 DW_OP_implicit_value {
1324                     set l1 [new_label "value_start"]
1325                     set l2 [new_label "value_end"]
1326                     _op .uleb128 "$l2 - $l1"
1327                     define_label $l1
1328                     foreach value [lrange $line 1 end] {
1329                         switch -regexp -- $value {
1330                             {^0x[[:xdigit:]]{1,2}$} {_op .byte $value}
1331                             {^0x[[:xdigit:]]{4}$} {_op .2byte $value}
1332                             {^0x[[:xdigit:]]{8}$} {_op .4byte $value}
1333                             {^0x[[:xdigit:]]{16}$} {_op .8byte $value}
1334                             default {
1335                                 error "bad value '$value' in DW_OP_implicit_value"
1336                             }
1337                         }
1338                     }
1339                     define_label $l2
1340                 }
1342                 DW_OP_implicit_pointer -
1343                 DW_OP_GNU_implicit_pointer {
1344                     _get_args $line $opcode label offset
1346                     # Here label is a section offset.
1347                     if { $dwarf_version == 2 } {
1348                         _op .${addr_size}byte $argvec(label)
1349                     } else {
1350                         _op_offset $offset_size $argvec(label)
1351                     }
1352                     _op .sleb128 $argvec(offset)
1353                 }
1355                 DW_OP_GNU_variable_value {
1356                     _get_args $line $opcode label
1358                     # Here label is a section offset.
1359                     if { $dwarf_version == 2 } {
1360                         _op .${addr_size}byte $argvec(label)
1361                     } else {
1362                         _op_offset $offset_size $argvec(label)
1363                     }
1364                 }
1366                 DW_OP_deref_size {
1367                     _get_args $line $opcode size
1368                     _op .byte $argvec(size)
1369                 }
1371                 DW_OP_bregx {
1372                     _get_args $line $opcode register offset
1373                     _op .uleb128 $argvec(register)
1374                     _op .sleb128 $argvec(offset)
1375                 }
1377                 DW_OP_fbreg {
1378                     _get_args $line $opcode offset
1379                     _op .sleb128 $argvec(offset)
1380                 }
1382                 DW_OP_fbreg {
1383                     _op .sleb128 [lindex $line 1]
1384                 }
1386                 default {
1387                     if {[llength $line] > 1} {
1388                         error "Unimplemented: operands in location for $opcode"
1389                     }
1390                 }
1391             }
1392         }
1393     }
1395     # Return a label that references the current position in the
1396     # .debug_addr table.  When a user is creating split DWARF they
1397     # will define two CUs, the first will be the split DWARF content,
1398     # and the second will be the non-split stub CU.  The split DWARF
1399     # CU fills in the .debug_addr section, but the non-split CU
1400     # includes a reference to the start of the section.  The label
1401     # returned by this proc provides that reference.
1402     proc debug_addr_label {} {
1403         variable _debug_addr_index
1405         set lbl [new_label "debug_addr_idx_${_debug_addr_index}_"]
1406         _defer_output .debug_addr {
1407             define_label $lbl
1408         }
1409         return $lbl
1410     }
1412     # Emit a DWARF CU.
1413     # OPTIONS is a list with an even number of elements containing
1414     # option-name and option-value pairs.
1415     # Current options are:
1416     # is_64 0|1    - boolean indicating if you want to emit 64-bit DWARF
1417     #                default = 0 (32-bit)
1418     # version n    - DWARF version number to emit
1419     #                default = 4
1420     # addr_size n  - the size of addresses in bytes: 4, 8, or default
1421     #                default = default
1422     # fission 0|1  - boolean indicating if generating Fission debug info
1423     #                default = 0
1424     # label <label>
1425     #              - string indicating label to be defined at the start
1426     #                of the CU header.
1427     #                default = ""
1428     # BODY is Tcl code that emits the DIEs which make up the body of
1429     # the CU.  It is evaluated in the caller's context.
1430     proc cu {options body} {
1431         variable _constants
1432         variable _cu_count
1433         variable _abbrev_section
1434         variable _abbrev_num
1435         variable _cu_label
1436         variable _cu_version
1437         variable _cu_addr_size
1438         variable _cu_offset_size
1439         variable _cu_is_fission
1441         # Establish the defaults.
1442         set is_64 0
1443         set _cu_version 4
1444         set _cu_addr_size default
1445         set _cu_is_fission 0
1446         set section ".debug_info"
1447         set _abbrev_section ".debug_abbrev"
1448         set label ""
1450         foreach { name value } $options {
1451             set value [uplevel 1 "subst \"$value\""]
1452             switch -exact -- $name {
1453                 is_64 { set is_64 $value }
1454                 version { set _cu_version $value }
1455                 addr_size { set _cu_addr_size $value }
1456                 fission { set _cu_is_fission $value }
1457                 label { set label $value }
1458                 default { error "unknown option $name" }
1459             }
1460         }
1461         if {$_cu_addr_size == "default"} {
1462             if {[is_64_target]} {
1463                 set _cu_addr_size 8
1464             } else {
1465                 set _cu_addr_size 4
1466             }
1467         }
1468         set _cu_offset_size [expr { $is_64 ? 8 : 4 }]
1469         if { $_cu_is_fission } {
1470             set section ".debug_info.dwo"
1471             set _abbrev_section ".debug_abbrev.dwo"
1472         }
1474         if {$_cu_version < 4} {
1475             set _constants(SPECIAL_expr) $_constants(DW_FORM_block)
1476         } else {
1477             set _constants(SPECIAL_expr) $_constants(DW_FORM_exprloc)
1478         }
1480         _section $section
1482         set cu_num [incr _cu_count]
1483         set my_abbrevs [_compute_label "abbrev${cu_num}_begin"]
1484         set _abbrev_num 1
1486         set _cu_label [_compute_label "cu${cu_num}_begin"]
1487         set start_label [_compute_label "cu${cu_num}_start"]
1488         set end_label [_compute_label "cu${cu_num}_end"]
1490         if { $label != "" } {
1491             upvar $label my_label
1492             set my_label $_cu_label
1493         }
1495         define_label $_cu_label
1496         if {$is_64} {
1497             _op .4byte 0xffffffff
1498             _op .8byte "$end_label - $start_label"
1499         } else {
1500             _op .4byte "$end_label - $start_label"
1501         }
1502         define_label $start_label
1503         _op .2byte $_cu_version Version
1505         # The CU header for DWARF 4 and 5 are slightly different.
1506         if { $_cu_version == 5 } {
1507             _op .byte 0x1 "DW_UT_compile"
1508             _op .byte $_cu_addr_size "Pointer size"
1509             _op_offset $_cu_offset_size $my_abbrevs Abbrevs
1510         } else {
1511             _op_offset $_cu_offset_size $my_abbrevs Abbrevs
1512             _op .byte $_cu_addr_size "Pointer size"
1513         }
1515         _defer_output $_abbrev_section {
1516             define_label $my_abbrevs
1517         }
1519         uplevel $body
1521         _defer_output $_abbrev_section {
1522             # Emit the terminator.
1523             _op .byte 0x0 "Abbrev end - Terminator"
1524         }
1526         define_label $end_label
1527     }
1529     # Emit a DWARF TU.
1530     # OPTIONS is a list with an even number of elements containing
1531     # option-name and option-value pairs.
1532     # Current options are:
1533     # is_64 0|1    - boolean indicating if you want to emit 64-bit DWARF
1534     #                default = 0 (32-bit)
1535     # version n    - DWARF version number to emit
1536     #                default = 4
1537     # addr_size n  - the size of addresses in bytes: 4, 8, or default
1538     #                default = default
1539     # fission 0|1  - boolean indicating if generating Fission debug info
1540     #                default = 0
1541     # SIGNATURE is the 64-bit signature of the type.
1542     # TYPE_LABEL is the label of the type defined by this TU,
1543     # or "" if there is no type (i.e., type stubs in Fission).
1544     # BODY is Tcl code that emits the DIEs which make up the body of
1545     # the TU.  It is evaluated in the caller's context.
1546     proc tu {options signature type_label body} {
1547         variable _cu_count
1548         variable _abbrev_section
1549         variable _abbrev_num
1550         variable _cu_label
1551         variable _cu_version
1552         variable _cu_addr_size
1553         variable _cu_offset_size
1554         variable _cu_is_fission
1556         # Establish the defaults.
1557         set is_64 0
1558         set _cu_version 4
1559         set _cu_addr_size default
1560         set _cu_is_fission 0
1561         set section ".debug_types"
1562         set _abbrev_section ".debug_abbrev"
1564         foreach { name value } $options {
1565             switch -exact -- $name {
1566                 is_64 { set is_64 $value }
1567                 version { set _cu_version $value }
1568                 addr_size { set _cu_addr_size $value }
1569                 fission { set _cu_is_fission $value }
1570                 default { error "unknown option $name" }
1571             }
1572         }
1573         if {$_cu_addr_size == "default"} {
1574             if {[is_64_target]} {
1575                 set _cu_addr_size 8
1576             } else {
1577                 set _cu_addr_size 4
1578             }
1579         }
1580         set _cu_offset_size [expr { $is_64 ? 8 : 4 }]
1581         if { $_cu_is_fission } {
1582             set section ".debug_types.dwo"
1583             set _abbrev_section ".debug_abbrev.dwo"
1584         }
1586         _section $section
1588         set cu_num [incr _cu_count]
1589         set my_abbrevs [_compute_label "abbrev${cu_num}_begin"]
1590         set _abbrev_num 1
1592         set _cu_label [_compute_label "cu${cu_num}_begin"]
1593         set start_label [_compute_label "cu${cu_num}_start"]
1594         set end_label [_compute_label "cu${cu_num}_end"]
1596         define_label $_cu_label
1597         if {$is_64} {
1598             _op .4byte 0xffffffff
1599             _op .8byte "$end_label - $start_label"
1600         } else {
1601             _op .4byte "$end_label - $start_label"
1602         }
1603         define_label $start_label
1604         _op .2byte $_cu_version Version
1605         _op_offset $_cu_offset_size $my_abbrevs Abbrevs
1606         _op .byte $_cu_addr_size "Pointer size"
1607         _op .8byte $signature Signature
1608         if { $type_label != "" } {
1609             uplevel declare_labels $type_label
1610             upvar $type_label my_type_label
1611             if {$is_64} {
1612                 _op .8byte "$my_type_label - $_cu_label"
1613             } else {
1614                 _op .4byte "$my_type_label - $_cu_label"
1615             }
1616         } else {
1617             if {$is_64} {
1618                 _op .8byte 0
1619             } else {
1620                 _op .4byte 0
1621             }
1622         }
1624         _defer_output $_abbrev_section {
1625             define_label $my_abbrevs
1626         }
1628         uplevel $body
1630         _defer_output $_abbrev_section {
1631             # Emit the terminator.
1632             _op .byte 0x0 "Abbrev end - Terminator"
1633         }
1635         define_label $end_label
1636     }
1638     # Emit a DWARF .debug_ranges unit.
1639     # OPTIONS is a list with an even number of elements containing
1640     # option-name and option-value pairs.
1641     # Current options are:
1642     # is_64 0|1    - boolean indicating if you want to emit 64-bit DWARF
1643     #                default = 0 (32-bit)
1644     #
1645     # BODY is Tcl code that emits the content of the .debug_ranges
1646     # unit, it is evaluated in the caller's context.
1647     proc ranges {options body} {
1648         variable _debug_ranges_64_bit
1650         foreach { name value } $options {
1651             switch -exact -- $name {
1652                 is_64 { set _debug_ranges_64_bit [subst $value] }
1653                 default { error "unknown option $name" }
1654             }
1655         }
1657         set section ".debug_ranges"
1658         _section $section
1660         proc sequence { body } {
1661             variable _debug_ranges_64_bit
1663             # Emit the sequence of addresses.
1665             proc base { addr } {
1666                 variable _debug_ranges_64_bit
1668                 if { $_debug_ranges_64_bit } then {
1669                     _op .8byte 0xffffffffffffffff "Base Marker"
1670                     _op .8byte $addr "Base Address"
1671                 } else {
1672                     _op .4byte 0xffffffff "Base Marker"
1673                     _op .4byte $addr "Base Address"
1674                 }
1675             }
1677             proc range { start end } {
1678                 variable _debug_ranges_64_bit
1680                 if { $_debug_ranges_64_bit } then {
1681                     _op .8byte $start "Start Address"
1682                     _op .8byte $end "End Address"
1683                 } else {
1684                     _op .4byte $start "Start Address"
1685                     _op .4byte $end "End Address"
1686                 }
1687             }
1689             uplevel $body
1691             # End of the sequence.
1692             if { $_debug_ranges_64_bit } then {
1693                 _op .8byte 0x0 "End of Sequence Marker (Part 1)"
1694                 _op .8byte 0x0 "End of Sequence Marker (Part 2)"
1695             } else {
1696                 _op .4byte 0x0 "End of Sequence Marker (Part 1)"
1697                 _op .4byte 0x0 "End of Sequence Marker (Part 2)"
1698             }
1699         }
1701         uplevel $body
1702     }
1704     # Emit a DWARF .debug_rnglists section.
1705     #
1706     # The target address size is based on the current target's address size.
1707     #
1708     # BODY must be Tcl code that emits the content of the section.  It is
1709     # evaluated in the caller's context.
1710     #
1711     # The `is-64 true|false` options tells whether to use 64-bit DWARF instead
1712     # of 32-bit DWARF.  The default is 32-bit.
1714     proc rnglists { options body } {
1715         variable _debug_rnglists_addr_size
1716         variable _debug_rnglists_offset_size
1717         variable _debug_rnglists_is_64_dwarf
1719         parse_options {{"is-64" "false"}}
1721         if [is_64_target] {
1722             set _debug_rnglists_addr_size 8
1723         } else {
1724             set _debug_rnglists_addr_size 4
1725         }
1727         if { ${is-64} } {
1728             set _debug_rnglists_offset_size 8
1729             set _debug_rnglists_is_64_dwarf true
1730         } else {
1731             set _debug_rnglists_offset_size 4
1732             set _debug_rnglists_is_64_dwarf false
1733         }
1735         _section ".debug_rnglists"
1737         # Count of tables in the section.
1738         variable _debug_rnglists_table_count 0
1740         # Compute the label name for list at index LIST_IDX, for the current
1741         # table.
1743         proc _compute_list_label { list_idx } {
1744             variable _debug_rnglists_table_count
1746             return ".Lrnglists_table_${_debug_rnglists_table_count}_list_${list_idx}"
1747         }
1749         with_override Dwarf::table Dwarf::_rnglists_table {
1750             uplevel $body
1751         }
1752     }
1754     # Generate one rnglists table (header + offset array + range lists).
1755     #
1756     # This proc is meant to be used within proc rnglists' body.  It is made
1757     # available as `table` while inside proc rnglists' body.
1758     #
1759     # BODY must be Tcl code that emits the content of the table.  It may call
1760     # the LIST_ procedure to generate rnglists.  It is evaluated in the
1761     # caller's context.
1762     #
1763     # The `post-header-label` option can be used to define a label just after
1764     # the header of the table.  This is the label that a DW_AT_rnglists_base
1765     # attribute will usually refer to.
1766     #
1767     # The `with-offset-array true|false` option can be used to control whether
1768     # the headers of the location list tables have an array of offset.  The
1769     # default is true.
1771     proc _rnglists_table { options body } {
1772         variable _debug_rnglists_table_count
1773         variable _debug_rnglists_addr_size
1774         variable _debug_rnglists_offset_size
1775         variable _debug_rnglists_is_64_dwarf
1777         parse_options {
1778             {post-header-label ""}
1779             {with-offset-array true}
1780         }
1782         # Count of lists in the table.
1783         variable _debug_rnglists_list_count 0
1785         # Generate the lists ops first, because we need to know how many
1786         # lists there are to generate the header and offset table.
1787         set lists_ops [_defer_to_string {
1788             with_override Dwarf::list_ Dwarf::_rnglists_list {
1789                 uplevel $body
1790             }
1791         }]
1793         set post_unit_len_label \
1794             [_compute_label "rnglists_table_${_debug_rnglists_table_count}_post_unit_len"]
1795         set post_header_label \
1796             [_compute_label "rnglists_table_${_debug_rnglists_table_count}_post_header"]
1797         set table_end_label \
1798             [_compute_label "rnglists_table_${_debug_rnglists_table_count}_end"]
1800         # Emit the table header.
1801         if { $_debug_rnglists_is_64_dwarf } {
1802             _op .4byte 0xffffffff "unit length 1/2"
1803             _op .8byte "$table_end_label - $post_unit_len_label" "unit length 2/2"
1804         } else {
1805             _op .4byte "$table_end_label - $post_unit_len_label" "unit length"
1806         }
1808         define_label $post_unit_len_label
1810         _op .2byte 5 "dwarf version"
1811         _op .byte $_debug_rnglists_addr_size "address size"
1812         _op .byte 0 "segment selector size"
1814         if { ${with-offset-array} } {
1815           _op .4byte "$_debug_rnglists_list_count" "offset entry count"
1816         } else {
1817           _op .4byte 0 "offset entry count"
1818         }
1820         define_label $post_header_label
1822         # Define the user post-header label, if provided.
1823         if { ${post-header-label} != "" } {
1824             define_label ${post-header-label}
1825         }
1827         # Emit the offset array.
1828         if { ${with-offset-array} } {
1829             for {set list_idx 0} {$list_idx < $_debug_rnglists_list_count} {incr list_idx} {
1830                 set list_label [_compute_list_label $list_idx]
1831                 _op_offset $_debug_rnglists_offset_size \
1832                     "$list_label - $post_header_label" \
1833                     "offset of list $list_idx"
1834             }
1835         }
1837         # Emit the actual list data.
1838         _emit "$lists_ops"
1840         define_label $table_end_label
1842         incr _debug_rnglists_table_count
1843     }
1845     # Generate one rnglists range list.
1846     #
1847     # This proc is meant to be used within proc _rnglists_table's body.  It is
1848     # made available as `list_` while inside proc _rnglists_table's body.
1849     #
1850     # BODY may call the various procs defined below to generate list entries.
1851     # They correspond to the range list entry kinds described in section 2.17.3
1852     # of the DWARF 5 spec.
1853     #
1854     # To define a label pointing to the beginning of the list, use the
1855     # conventional way of declaring and defining labels:
1856     #
1857     #   declare_labels the_list
1858     #
1859     #   the_list: list_ { ...  }
1861     proc _rnglists_list { body } {
1862         variable _debug_rnglists_list_count
1864         # Define a label for this list.  It is used to build the offset
1865         # array later.
1866         set list_label [_compute_list_label $_debug_rnglists_list_count]
1867         define_label $list_label
1869         with_override Dwarf::start_end Dwarf::_rnglists_start_end {
1870             uplevel $body
1871         }
1873         # Emit end of list.
1874         _op .byte 0x00 "DW_RLE_end_of_list"
1876         incr _debug_rnglists_list_count
1877     }
1879     # Emit a rnglists DW_RLE_start_end entry.
1880     #
1881     # This proc is meant to be used within proc _rnglists_list's body.  It is
1882     # made available as `start_end` while inside proc _rnglists_list's body.
1884     proc _rnglists_start_end { start end } {
1885         variable _debug_rnglists_addr_size
1887         _op .byte 0x06 "DW_RLE_start_end"
1888         _op .${_debug_rnglists_addr_size}byte $start "start"
1889         _op .${_debug_rnglists_addr_size}byte $end "end"
1890     }
1892     # Emit a DWARF .debug_loclists section.
1893     #
1894     # The target address size is based on the current target's address size.
1895     #
1896     # BODY must be Tcl code that emits the content of the section.  It is
1897     # evaluated in the caller's context.
1898     #
1899     # The `is-64 true|false` options tells whether to use 64-bit DWARF instead
1900     # of 32-bit DWARF.  The default is 32-bit.
1902     proc loclists { options body } {
1903         variable _debug_loclists_addr_size
1904         variable _debug_loclists_offset_size
1905         variable _debug_loclists_is_64_dwarf
1907         parse_options {{"is-64" "false"}}
1909         if [is_64_target] {
1910             set _debug_loclists_addr_size 8
1911         } else {
1912             set _debug_loclists_addr_size 4
1913         }
1915         if { ${is-64} } {
1916             set _debug_loclists_offset_size 8
1917             set _debug_loclists_is_64_dwarf true
1918         } else {
1919             set _debug_loclists_offset_size 4
1920             set _debug_loclists_is_64_dwarf false
1921         }
1923         _section ".debug_loclists"
1925         # Count of tables in the section.
1926         variable _debug_loclists_table_count 0
1928         # Compute the label name for list at index LIST_IDX, for the current
1929         # table.
1931         proc _compute_list_label { list_idx } {
1932             variable _debug_loclists_table_count
1934             return ".Lloclists_table_${_debug_loclists_table_count}_list_${list_idx}"
1935         }
1937         with_override Dwarf::table Dwarf::_loclists_table {
1938             uplevel $body
1939         }
1940     }
1942     # Generate one loclists table (header + offset array + location lists).
1943     #
1944     # This proc is meant to be used within proc loclists' body.  It is made
1945     # available as `table` while inside proc rnglists' body.
1946     #
1947     # BODY must be Tcl code that emits the content of the table.  It may call
1948     # the LIST_ procedure to generate rnglists.  It is evaluated in the
1949     # caller's context.
1950     #
1951     # The `post-header-label` option can be used to define a label just after
1952     # the header of the table.  This is the label that a DW_AT_loclists_base
1953     # attribute will usually refer to.
1954     #
1955     # The `with-offset-array true|false` option can be used to control
1956     # whether the headers of the location list tables have an array of
1957     # offset.  The default is true.
1959     proc _loclists_table { options body } {
1960         variable _debug_loclists_table_count
1961         variable _debug_loclists_addr_size
1962         variable _debug_loclists_offset_size
1963         variable _debug_loclists_is_64_dwarf
1965         parse_options {
1966             {post-header-label ""}
1967             {with-offset-array true}
1968         }
1970         # Count of lists in the table.
1971         variable _debug_loclists_list_count 0
1973         # Generate the lists ops first, because we need to know how many
1974         # lists there are to generate the header and offset table.
1975         set lists_ops [_defer_to_string {
1976             with_override Dwarf::list_ Dwarf::_loclists_list {
1977                 uplevel $body
1978             }
1979         }]
1981         set post_unit_len_label \
1982             [_compute_label "loclists_table_${_debug_loclists_table_count}_post_unit_len"]
1983         set post_header_label \
1984             [_compute_label "loclists_table_${_debug_loclists_table_count}_post_header"]
1985         set table_end_label \
1986             [_compute_label "loclists_table_${_debug_loclists_table_count}_end"]
1988         # Emit the table header.
1989         if { $_debug_loclists_is_64_dwarf } {
1990             _op .4byte 0xffffffff "unit length 1/2"
1991             _op .8byte "$table_end_label - $post_unit_len_label" "unit length 2/2"
1992         } else {
1993             _op .4byte "$table_end_label - $post_unit_len_label" "unit length"
1994         }
1996         define_label $post_unit_len_label
1998         _op .2byte 5 "DWARF version"
1999         _op .byte $_debug_loclists_addr_size "address size"
2000         _op .byte 0 "segment selector size"
2002         if { ${with-offset-array} } {
2003           _op .4byte "$_debug_loclists_list_count" "offset entry count"
2004         } else {
2005           _op .4byte 0 "offset entry count"
2006         }
2008         define_label $post_header_label
2010         # Define the user post-header label, if provided.
2011         if { ${post-header-label} != "" } {
2012             define_label ${post-header-label}
2013         }
2015         # Emit the offset array.
2016         if { ${with-offset-array} } {
2017             for {set list_idx 0} {$list_idx < $_debug_loclists_list_count} {incr list_idx} {
2018                 set list_label [_compute_list_label $list_idx]
2019                 _op_offset $_debug_loclists_offset_size \
2020                     "$list_label - $post_header_label" \
2021                     "offset of list $list_idx"
2022             }
2023         }
2025         # Emit the actual list data.
2026         _emit "$lists_ops"
2028         define_label $table_end_label
2030         incr _debug_loclists_table_count
2031     }
2033     # Generate one loclists location list.
2034     #
2035     # This proc is meant to be used within proc _loclists_table's body.  It is
2036     # made available as `list_` while inside proc _loclists_table's body.
2037     #
2038     # BODY may call the various procs defined below to generate list
2039     # entries.  They correspond to the location list entry kinds
2040     # described in section 2.6.2 of the DWARF 5 spec.
2041     #
2042     # To define a label pointing to the beginning of the list, use
2043     # the conventional way of declaring and defining labels:
2044     #
2045     #   declare_labels the_list
2046     #
2047     #   the_list: list_ {
2048     #     ...
2049     #   }
2051     proc _loclists_list { body } {
2052         variable _debug_loclists_list_count
2054         # Count the location descriptions in this list.
2055         variable _debug_loclists_locdesc_count 0
2057         # Define a label for this list.  It is used to build the offset
2058         # array later.
2059         set list_label [_compute_list_label $_debug_loclists_list_count]
2060         define_label $list_label
2062         with_override Dwarf::start_length Dwarf::_loclists_start_length {
2063         with_override Dwarf::base_address Dwarf::_loclists_base_address {
2064         with_override Dwarf::start_end Dwarf::_loclists_start_end {
2065             uplevel $body
2066         }}}
2068         # Emit end of list.
2069         _op .byte 0x00 "DW_LLE_end_of_list"
2071         incr _debug_loclists_list_count
2072     }
2074     # Emit a DW_LLE_start_length entry.
2075     #
2076     # This proc is meant to be used within proc _loclists_list's body.  It is
2077     # made available as `start_length` while inside proc _loclists_list's body.
2079     proc _loclists_start_length { start length locdesc } {
2080         variable _debug_loclists_is_64_dwarf
2081         variable _debug_loclists_addr_size
2082         variable _debug_loclists_offset_size
2083         variable _debug_loclists_table_count
2084         variable _debug_loclists_list_count
2085         variable _debug_loclists_locdesc_count
2087         set locdesc [uplevel [list subst $locdesc]]
2089         _op .byte 0x08 "DW_LLE_start_length"
2091         # Start and end of the address range.
2092         _op .${_debug_loclists_addr_size}byte $start "start"
2093         _op .uleb128 $length "length"
2095         # Length of location description.
2096         set locdesc_start_label ".Lloclists_table_${_debug_loclists_table_count}_list_${_debug_loclists_list_count}_locdesc_${_debug_loclists_locdesc_count}_start"
2097         set locdesc_end_label ".Lloclists_table_${_debug_loclists_table_count}_list_${_debug_loclists_list_count}_locdesc_${_debug_loclists_locdesc_count}_end"
2098         _op .uleb128 "$locdesc_end_label - $locdesc_start_label" "locdesc length"
2100         define_label $locdesc_start_label
2101         set dwarf_version 5
2102         _location $locdesc $dwarf_version $_debug_loclists_addr_size $_debug_loclists_offset_size
2103         define_label $locdesc_end_label
2105         incr _debug_loclists_locdesc_count
2106     }
2108     # Emit a DW_LLE_start_end entry.
2109     #
2110     # This proc is meant to be used within proc _loclists_list's body.  It is
2111     # made available as `start_end` while inside proc _loclists_list's body.
2113     proc _loclists_start_end { start end locdesc } {
2114         variable _debug_loclists_is_64_dwarf
2115         variable _debug_loclists_addr_size
2116         variable _debug_loclists_offset_size
2117         variable _debug_loclists_table_count
2118         variable _debug_loclists_list_count
2119         variable _debug_loclists_locdesc_count
2121         set locdesc [uplevel [list subst $locdesc]]
2123         _op .byte 0x07 "DW_LLE_start_end"
2125         # Start and end of the address range.
2126         _op .${_debug_loclists_addr_size}byte $start "start"
2127         _op .${_debug_loclists_addr_size}byte $end "end"
2129         # Length of location description.
2130         set locdesc_start_label ".Lloclists_table_${_debug_loclists_table_count}_list_${_debug_loclists_list_count}_locdesc_${_debug_loclists_locdesc_count}_start"
2131         set locdesc_end_label ".Lloclists_table_${_debug_loclists_table_count}_list_${_debug_loclists_list_count}_locdesc_${_debug_loclists_locdesc_count}_end"
2132         _op .uleb128 "$locdesc_end_label - $locdesc_start_label" "locdesc length"
2134         define_label $locdesc_start_label
2135         set dwarf_version 5
2136         _location $locdesc $dwarf_version $_debug_loclists_addr_size $_debug_loclists_offset_size
2137         define_label $locdesc_end_label
2139         incr _debug_loclists_locdesc_count
2140     }
2142     # Emit a DW_LLE_base_address entry.
2143     proc _loclists_base_address {addr} {
2144         variable _debug_loclists_addr_size
2145         variable _debug_loclists_locdesc_count
2146         _op .byte 0x06 "DW_LLE_base_address"
2147         _op .${_debug_loclists_addr_size}byte $addr "base_address"
2148         incr _debug_loclists_locdesc_count
2149     }
2151     # Emit a DWARF .debug_line unit.
2152     # OPTIONS is a list with an even number of elements containing
2153     # option-name and option-value pairs.
2154     # Current options are:
2155     # is_64 0|1    - boolean indicating if you want to emit 64-bit DWARF
2156     #                default = 0 (32-bit)
2157     # version n    - DWARF version number to emit
2158     #                default = 4
2159     # addr_size n  - the size of addresses in bytes: 4, 8, or default
2160     #                default = default
2161     # seg_sel_size n
2162     #              - the size of segment selector_size in bytes:
2163     #                default = 0
2164     #
2165     # LABEL is the label of the current unit (which is probably
2166     # referenced by a DW_AT_stmt_list), or "" if there is no such
2167     # label.
2168     #
2169     # BODY is Tcl code that emits the parts which make up the body of
2170     # the line unit.  It is evaluated in the caller's context.  The
2171     # following commands are available for the BODY section:
2172     #
2173     #   include_dir "dirname" -- adds a new include directory
2174     #
2175     #   file_name "file.c" idx -- adds a new file name.  IDX is a
2176     #   1-based index referencing an include directory or 0 for
2177     #   current directory.
2179     proc lines {options label body} {
2180         variable _line_count
2181         variable _line_saw_file
2182         variable _line_include_dirs
2183         variable _line_file_names
2184         variable _line_header_finalized
2185         variable _line_saw_program
2186         variable _line_header_end_label
2187         variable _line_unit_version
2188         variable _line_is_64
2189         variable _line_string_form
2191         # Establish the defaults.
2192         set _line_is_64 0
2193         set _line_unit_version 4
2194         set _unit_addr_size default
2195         set _line_saw_program 0
2196         set _line_saw_file 0
2197         set _line_include_dirs {}
2198         set _line_file_names {}
2199         set _line_header_finalized 0
2200         set _default_is_stmt 1
2201         set _seg_sel_size 0
2202         #set _line_string_form string
2203         set _line_string_form line_strp
2205         foreach { name value } $options {
2206             switch -exact -- $name {
2207                 is_64 { set _line_is_64 $value }
2208                 version { set _line_unit_version $value }
2209                 addr_size { set _unit_addr_size $value }
2210                 seg_sel_size { set _seg_sel_size $value }
2211                 default_is_stmt { set _default_is_stmt $value }
2212                 string_form { set _line_string_form $value }
2213                 default { error "unknown option $name" }
2214             }
2215         }
2216         if {$_unit_addr_size == "default"} {
2217             if {[is_64_target]} {
2218                 set _unit_addr_size 8
2219             } else {
2220                 set _unit_addr_size 4
2221             }
2222         }
2224         set unit_num [incr _line_count]
2226         set section ".debug_line"
2227         _section $section
2229         if { "$label" != "" } {
2230             # Define the user-provided label at this point.
2231             $label:
2232         }
2234         set unit_len_label [_compute_label "line${_line_count}_start"]
2235         set unit_end_label [_compute_label "line${_line_count}_end"]
2236         set header_len_label [_compute_label "line${_line_count}_header_start"]
2237         set _line_header_end_label [_compute_label "line${_line_count}_header_end"]
2239         if {$_line_is_64} {
2240             _op .4byte 0xffffffff
2241             _op .8byte "$unit_end_label - $unit_len_label" "unit_length"
2242         } else {
2243             _op .4byte "$unit_end_label - $unit_len_label" "unit_length"
2244         }
2246         define_label $unit_len_label
2248         _op .2byte $_line_unit_version version
2250         if { $_line_unit_version >= 5 } {
2251             _op .byte $_unit_addr_size "address_size"
2252             # Hardcode to 0 for now.
2253             _op .byte $_seg_sel_size "seg_sel_size"
2254         }
2256         if {$_line_is_64} {
2257             _op .8byte "$_line_header_end_label - $header_len_label" "header_length"
2258         } else {
2259             _op .4byte "$_line_header_end_label - $header_len_label" "header_length"
2260         }
2262         define_label $header_len_label
2264         _op .byte 1 "minimum_instruction_length"
2265         if { $_line_unit_version >= 4 } {
2266             # Assume non-VLIW for now.
2267             _op .byte 1 "maximum_operations_per_instruction"
2268         }
2269         _op .byte $_default_is_stmt "default_is_stmt"
2270         _op .byte 1 "line_base"
2271         _op .byte 1 "line_range"
2272         _op .byte 10 "opcode_base"
2274         # The standard_opcode_lengths table.  The number of arguments
2275         # for each of the standard opcodes.  Generating 9 entries here
2276         # matches the use of 10 in the opcode_base above.  These 9
2277         # entries match the 9 standard opcodes for DWARF2, making use
2278         # of only 9 should be fine, even if we are generating DWARF3
2279         # or DWARF4.
2280         _op .byte 0 "standard opcode 1"
2281         _op .byte 1 "standard opcode 2"
2282         _op .byte 1 "standard opcode 3"
2283         _op .byte 1 "standard opcode 4"
2284         _op .byte 1 "standard opcode 5"
2285         _op .byte 0 "standard opcode 6"
2286         _op .byte 0 "standard opcode 7"
2287         _op .byte 0 "standard opcode 8"
2288         _op .byte 1 "standard opcode 9"
2290         proc include_dir {dirname} {
2291             variable _line_include_dirs
2292             lappend _line_include_dirs $dirname
2293         }
2295         proc file_name {filename diridx} {
2296             variable _line_file_names
2297             lappend _line_file_names $filename $diridx
2299             variable _line_saw_file 1
2300             set _line_saw_file 1
2301         }
2303         proc _line_finalize_header {} {
2304             variable _line_header_finalized
2305             if { $_line_header_finalized } {
2306                 return
2307             }
2308             set _line_header_finalized 1
2310             variable _line_include_dirs
2311             variable _line_file_names
2313             variable _line_unit_version
2314             variable _line_is_64
2315             variable _line_string_form
2316             if { $_line_unit_version >= 5 } {
2317                 _op .byte 1 "directory_entry_format_count"
2318                 _op .uleb128 1 \
2319                     "directory_entry_format (content type code: DW_LNCT_path)"
2320                 switch $_line_string_form {
2321                     string {
2322                         _op .uleb128 0x08 \
2323                             "directory_entry_format (form: DW_FORM_string)"
2324                     }
2325                     line_strp {
2326                         _op .uleb128 0x1f \
2327                             "directory_entry_format (form: DW_FORM_line_strp)"
2328                     }
2329                 }
2331                 set nr_dirs [llength $_line_include_dirs]
2332                 # For entry 0.
2333                 set nr_dirs [expr $nr_dirs + 1]
2334                 _op .byte $nr_dirs "directory_count"
2336                 # Entry 0.
2337                 set dirname [lindex $_line_include_dirs 0]
2338                 set _line_include_dirs \
2339                     [concat [list $dirname] $_line_include_dirs]
2341                 foreach dirname $_line_include_dirs {
2342                     switch $_line_string_form {
2343                         string {
2344                             _op .ascii [_quote $dirname]
2345                         }
2346                         line_strp {
2347                             declare_labels string_ptr
2348                             _defer_output .debug_line_str {
2349                                 string_ptr:
2350                                 _op .ascii [_quote $dirname]
2351                             }
2352                             _op_offset [expr $_line_is_64 ? 8 : 4] $string_ptr
2353                         }
2354                     }
2355                 }
2357                 _op .byte 2 "file_name_entry_format_count"
2358                 _op .uleb128 1 \
2359                     "file_name_entry_format (content type code: DW_LNCT_path)"
2360                 switch $_line_string_form {
2361                     string {
2362                         _op .uleb128 0x08 \
2363                             "directory_entry_format (form: DW_FORM_string)"
2364                     }
2365                     line_strp {
2366                         _op .uleb128 0x1f \
2367                             "directory_entry_format (form: DW_FORM_line_strp)"
2368                     }
2369                 }
2370                 _op .uleb128 2 \
2371                     "file_name_entry_format (content type code: DW_LNCT_directory_index)"
2372                 _op .uleb128 0x0f \
2373                     "file_name_entry_format (form: DW_FORM_udata)"
2375                 set nr_files [expr [llength $_line_file_names] / 2]
2376                 # For entry 0.
2377                 set nr_files [expr $nr_files + 1]
2378                 _op .byte $nr_files "file_names_count"
2380                 # Entry 0.
2381                 set filename [lindex $_line_file_names 0]
2382                 set diridx [lindex $_line_file_names 1]
2383                 set _line_file_names \
2384                     [concat [list $filename $diridx] $_line_file_names]
2386                 foreach { filename diridx } $_line_file_names {
2387                     switch $_line_string_form {
2388                         string {
2389                             _op .ascii [_quote $filename]
2390                         }
2391                         line_strp {
2392                             declare_labels string_ptr
2393                             _defer_output .debug_line_str {
2394                                 string_ptr:
2395                                 _op .ascii [_quote $filename]
2396                             }
2397                             _op_offset [expr $_line_is_64 ? 8 : 4] $string_ptr
2398                         }
2399                     }
2400                     _op .uleb128 $diridx
2401                 }
2402             } else {
2403                 foreach dirname $_line_include_dirs {
2404                     _op .ascii [_quote $dirname]
2405                 }
2407                 _op .byte 0 "Terminator (include_directories)"
2409                 foreach { filename diridx } $_line_file_names {
2410                     _op .ascii [_quote $filename]
2411                     _op .sleb128 $diridx
2412                     _op .sleb128 0 "mtime"
2413                     _op .sleb128 0 "length"
2414                 }
2416                 _op .byte 0 "Terminator (file_names)"
2417             }
2419             set _line_include_dirs {}
2420             set _line_file_names {}
2422             variable _line_header_end_label
2423             define_label $_line_header_end_label
2424         }
2426         proc program {statements} {
2427             variable _line_saw_program
2428             variable _line_header_end_label
2429             variable _line
2431             set _line_saw_program 1
2433             set _line 1
2435             _line_finalize_header
2437             proc DW_LNE_set_address {addr} {
2438                 _op .byte 0
2439                 set start [new_label "set_address_start"]
2440                 set end [new_label "set_address_end"]
2441                 _op .uleb128 "${end} - ${start}"
2442                 define_label ${start}
2443                 _op .byte 2
2444                 if {[is_64_target]} {
2445                     _op .8byte ${addr}
2446                 } else {
2447                     _op .4byte ${addr}
2448                 }
2449                 define_label ${end}
2450             }
2452             proc DW_LNE_end_sequence {} {
2453                 variable _line
2454                 _op .byte 0
2455                 _op .uleb128 1
2456                 _op .byte 1
2457                 set _line 1
2458             }
2460             proc DW_LNE_user { len opcode } {
2461                 set DW_LNE_lo_usr 0x80
2462                 set DW_LNE_hi_usr 0xff
2463                 if { $DW_LNE_lo_usr <= $opcode
2464                      && $opcode <= $DW_LNE_hi_usr } {
2465                     _op .byte 0
2466                     _op .uleb128 $len
2467                     _op .byte $opcode
2468                     for {set i 1} {$i < $len} {incr i} {
2469                         _op .byte 0
2470                     }
2471                 } else {
2472                     error "unknown vendor specific extended opcode: $opcode"
2473                 }
2474             }
2476             proc DW_LNS_copy {} {
2477                 _op .byte 1
2478             }
2480             proc DW_LNS_negate_stmt {} {
2481                 _op .byte 6
2482             }
2484             proc DW_LNS_advance_pc {offset} {
2485                 _op .byte 2
2486                 _op .uleb128 ${offset}
2487             }
2489             proc DW_LNS_advance_line {offset} {
2490                 variable _line
2491                 _op .byte 3
2492                 _op .sleb128 ${offset}
2493                 set _line [expr $_line + $offset]
2494             }
2496             # A pseudo line number program instruction, that can be used instead
2497             # of DW_LNS_advance_line.  Rather than writing:
2498             #   {DW_LNS_advance_line [expr $line1 - 1]}
2499             #   {DW_LNS_advance_line [expr $line2 - $line1]}
2500             #   {DW_LNS_advance_line [expr $line3 - $line2]}
2501             # we can just write:
2502             #   {line $line1}
2503             #   {line $line2}
2504             #   {line $line3}
2505             proc line {line} {
2506                 variable _line
2507                 set offset [expr $line - $_line]
2508                 DW_LNS_advance_line $offset
2509             }
2511             proc DW_LNS_set_file {num} {
2512                 _op .byte 4
2513                 _op .sleb128 ${num}
2514             }
2516             foreach statement $statements {
2517                 uplevel 1 $statement
2518             }
2519         }
2521         uplevel $body
2523         rename include_dir ""
2524         rename file_name ""
2526         _line_finalize_header
2528         define_label $unit_end_label
2529     }
2531     # Emit a DWARF .debug_aranges entry.
2533     proc arange { options arange_start arange_length } {
2534         parse_options {
2535             { comment "" }
2536             { seg_sel "" }
2537         }
2539         if { $comment != "" } {
2540             # Wrap
2541             set comment " ($comment)"
2542         }
2544         if { $seg_sel != "" } {
2545             variable _seg_size
2546             if { $_seg_size == 8 } {
2547                 set seg_op .8byte
2548             } elseif { $_seg_size == 4 } {
2549                 set seg_op .4byte
2550             } else {
2551                 error \
2552                     "Don't know how to handle segment selector size $_seg_size"
2553             }
2554             _op $seg_op $seg_sel "Address range segment selector$comment"
2555         }
2557         variable _addr_size
2558         if { $_addr_size == 8 } {
2559             set addr_op .8byte
2560         } elseif { $_addr_size == 4 } {
2561             set addr_op .4byte
2562         }
2564         _op $addr_op $arange_start "Address range start$comment"
2565         _op $addr_op $arange_length "Address range length$comment"
2566     }
2568     # Emit a DWARF .debug_aranges unit.
2569     #
2570     # OPTIONS is a list with an even number of elements containing
2571     # option-name and option-value pairs.
2572     # Current options are:
2573     # is_64 0|1    - boolean indicating if you want to emit 64-bit DWARF
2574     #                default = 0 (32-bit)
2575     # cu_is_64 0|1 - boolean indicating if LABEL refers to a 64-bit DWARF CU
2576     #                default = 0 (32-bit)
2577     # section_version n
2578     #                - section version number to emit
2579     #                default = 2
2580     # seg_size n   - the size of the adress selector in bytes: 0, 4, or 8
2581     #                default = 0
2582     #
2583     # LABEL is the label of the corresponding CU.
2584     #
2585     # BODY is Tcl code that emits the parts which make up the body of
2586     # the aranges unit.  It is evaluated in the caller's context.  The
2587     # following commands are available for the BODY section:
2588     #
2589     #   arange [-c <comment>] [<segment selector>] <start> <length>
2590     #     -- adds an address range.
2592     proc aranges { options label body } {
2593         variable _addr_size
2594         variable _seg_size
2596         # Handle options.
2597         parse_options {
2598             { is_64 0 }
2599             { cu_is_64 0 }
2600             { section_version 2 }
2601             { seg_size 0 }
2602         }
2603         set _seg_size $seg_size
2605         if { [is_64_target] } {
2606             set _addr_size 8
2607         } else {
2608             set _addr_size 4
2609         }
2611         # Switch to .debug_aranges section.
2612         _section .debug_aranges
2614         # Keep track of offset from start of section entry to determine
2615         # padding amount.
2616         set offset 0
2618         # Initial length.
2619         declare_labels aranges_start aranges_end
2620         set length "$aranges_end - $aranges_start"
2621         set comment "Length"
2622         if { $is_64 } {
2623             _op .4byte 0xffffffff
2624             _op .8byte $length $comment
2625             incr offset 12
2626         } else {
2627             _op .4byte $length $comment
2628             incr offset 4
2629         }
2631         # Start label.
2632         aranges_start:
2634         # Section version.
2635         _op .2byte $section_version "Section version"
2636         incr offset 2
2638         # Offset into .debug_info.
2639         upvar $label my_label
2640         if { $cu_is_64 } {
2641             _op .8byte $my_label "Offset into .debug_info"
2642             incr offset 8
2643         } else {
2644             _op .4byte $my_label "Offset into .debug_info"
2645             incr offset 4
2646         }
2648         # Address size.
2649         _op .byte $_addr_size "Address size"
2650         incr offset
2652         # Segment selector size.
2653         _op .byte $_seg_size "Segment selector size"
2654         incr offset
2656         # Padding.
2657         set tuple_size [expr 2 * $_addr_size + $_seg_size]
2658         while { 1 } {
2659             if { [expr $offset % $tuple_size] == 0 } {
2660                 break
2661             }
2662             _op .byte 0 "Pad to $tuple_size byte boundary"
2663             incr offset
2664         }
2666         # Range tuples.
2667         uplevel $body
2669         # Terminator tuple.
2670         set comment "Terminator"
2671         if { $_seg_size == 0 } {
2672             arange {comment $comment} 0 0
2673         } else {
2674             arange {comment $comment seg_sel 0} 0 0
2675         }
2677         # End label.
2678         aranges_end:
2679     }
2681     # Emit a .debug_loc entry.
2683     proc _loc_entry { start end location_description } {
2684         # Determine how to emit addresses.
2685         variable _addr_size
2686         if { $_addr_size == 8 } {
2687             set addr_op .8byte
2688         } elseif { $_addr_size == 4 } {
2689             set addr_op .4byte
2690         }
2692         # Emit start and end address.
2693         _op $addr_op $start "Start address"
2694         _op $addr_op $end "End address"
2696         declare_labels location_description_start
2697         declare_labels location_description_end
2699         # Emit length of location description.
2700         set len "$location_description_end - $location_description_start"
2701         _op .2byte $len "Location description length"
2703         # Tag start of location description.
2704         define_label $location_description_start
2706         # Emit location description.
2707         variable _cu_version
2708         variable _cu_offset_size
2709         _location $location_description $_cu_version $_addr_size \
2710             $_cu_offset_size
2712         # Tag end of location description.
2713         define_label $location_description_end
2714     }
2716     # Emit a DWARF .debug_loc contribution.
2717     #
2718     # OPTIONS is a list with an even number of elements containing
2719     # option-name and option-value pairs.
2720     # Current options are:
2721     # cu_is_64 0|1 - boolean indicating if references from location
2722     #                descriptions refer to a 64-bit DWARF CU.
2723     #                default = 0 (32-bit)
2724     # cu_version n - section version of DWARF CU referenced from location
2725     #                descriptions.
2726     #                default = 4
2727     #
2728     # BODY is Tcl code that emits the parts which make up the body of
2729     # the debug_loc contribution.  It is evaluated in the caller's context.
2730     # The following command is available for the BODY section:
2731     #
2732     #   entry <start> <end> <location description>
2733     #     -- emit a .debug_loc entry
2735     proc loc { options body } {
2736         # Handle options.
2737         parse_options {
2738             { cu_version 4 }
2739             { cu_is_64 0 }
2740         }
2742         # Export for use in BODY.
2743         variable _addr_size
2744         if { [is_64_target] } {
2745             set _addr_size 8
2746         } else {
2747             set _addr_size 4
2748         }
2749         variable _cu_version
2750         set _cu_version $cu_version
2751         variable _cu_offset_size
2752         if { $cu_is_64 == 1 } {
2753             set _cu_offset_size 8
2754         } else {
2755             set _cu_offset_size 4
2756         }
2758         # Switch to .debug_loc section.
2759         _section .debug_loc
2761         # Introduce command 'entry'.
2762         with_override Dwarf::entry Dwarf::_loc_entry {
2763             # Emit entries.
2764             uplevel $body
2765         }
2767         # Determine how to emit addresses.
2768         if { $_addr_size == 8 } {
2769             set addr_op .8byte
2770         } elseif { $_addr_size == 4 } {
2771             set addr_op .4byte
2772         }
2774         # Emit <End of list>.
2775         set comment "<End of list>"
2776         _op $addr_op 0 "$comment (Part 1/2)"
2777         _op $addr_op 0 "$comment (Part 2/2)"
2778     }
2780     proc _empty_array {name} {
2781         upvar $name the_array
2783         catch {unset the_array}
2784         set the_array(_) {}
2785         unset the_array(_)
2786     }
2788     # Emit a .gnu_debugaltlink section with the given file name and
2789     # build-id.  The buildid should be represented as a hexadecimal
2790     # string, like "ffeeddcc".
2791     proc gnu_debugaltlink {filename buildid} {
2792         _defer_output .gnu_debugaltlink {
2793             _op .ascii [_quote $filename]
2794             foreach {a b} [split $buildid {}] {
2795                 _op .byte 0x$a$b
2796             }
2797         }
2798     }
2800     proc _note {type name hexdata} {
2801         set namelen [expr [string length $name] + 1]
2803         # Name size.
2804         _op .4byte $namelen
2805         # Data size.
2806         _op .4byte [expr [string length $hexdata] / 2]
2807         # Type.
2808         _op .4byte $type
2809         # The name.
2810         _op .ascii [_quote $name]
2811         # Alignment.
2812         set align 2
2813         set total [expr {($namelen + (1 << $align) - 1) & -(1 << $align)}]
2814         for {set i $namelen} {$i < $total} {incr i} {
2815             _op .byte 0
2816         }
2817         # The data.
2818         foreach {a b} [split $hexdata {}] {
2819             _op .byte 0x$a$b
2820         }
2821     }
2823     # Emit a note section holding the given build-id.
2824     proc build_id {buildid} {
2825         _defer_output {.note.gnu.build-id a note} {
2826             # From elf/common.h.
2827             set NT_GNU_BUILD_ID 3
2829             _note $NT_GNU_BUILD_ID GNU $buildid
2830         }
2831     }
2833     # Emit a dummy CU.
2834     proc dummy_cu {} {
2835         # Generate a CU with default options and empty body.
2836         cu {label dummy_cu} {
2837         }
2839         # Generate an .debug_aranges entry for the dummy CU.
2840         aranges {} dummy_cu {
2841         }
2842     }
2844     # The top-level interface to the DWARF assembler.
2845     # FILENAME is the name of the file where the generated assembly
2846     # code is written.
2847     # BODY is Tcl code to emit the assembly.  It is evaluated via
2848     # "eval" -- not uplevel as you might expect, because it is
2849     # important to run the body in the Dwarf namespace.
2850     #
2851     # A typical invocation is something like:
2852     #    Dwarf::assemble $file {
2853     #        cu 0 2 8 {
2854     #            compile_unit {
2855     #            ...
2856     #            }
2857     #        }
2858     #        cu 0 2 8 {
2859     #        ...
2860     #        }
2861     #    }
2862     proc assemble {filename body} {
2863         variable _initialized
2864         variable _output_file
2865         variable _deferred_output
2866         variable _defer
2867         variable _label_num
2868         variable _strings
2869         variable _cu_count
2870         variable _line_count
2871         variable _line_saw_file
2872         variable _line_saw_program
2873         variable _line_header_end_label
2874         variable _debug_ranges_64_bit
2875         variable _debug_addr_index
2877         if {!$_initialized} {
2878             _read_constants
2879             set _initialized 1
2880         }
2882         set _output_file [open $filename w]
2883         set _cu_count -1
2884         _empty_array _deferred_output
2885         set _defer ""
2886         set _label_num 0
2887         _empty_array _strings
2889         set _line_count 0
2890         set _line_saw_file 0
2891         set _line_saw_program 0
2892         set _debug_ranges_64_bit [is_64_target]
2894         set _debug_addr_index 0
2896         # Dummy CU at the start to ensure that the first CU in $body is not
2897         # the first in .debug_info.
2898         dummy_cu
2900         with_shared_gdb {
2901             # Not "uplevel" here, because we want to evaluate in this
2902             # namespace.  This is somewhat bad because it means we can't
2903             # readily refer to outer variables.
2904             eval $body
2905         }
2907         # Dummy CU at the end to ensure that the last CU in $body is not
2908         # the last in .debug_info.
2909         dummy_cu
2911         _write_deferred_output
2913         catch {close $_output_file}
2914         set _output_file {}
2915     }