aboutsummaryrefslogtreecommitdiff
path: root/src/boot/me/dwarf.ml
diff options
context:
space:
mode:
authorGraydon Hoare <[email protected]>2010-06-23 21:03:09 -0700
committerGraydon Hoare <[email protected]>2010-06-23 21:03:09 -0700
commitd6b7c96c3eb29b9244ece0c046d3f372ff432d04 (patch)
treeb425187e232966063ffc2f0d14c04a55d8f004ef /src/boot/me/dwarf.ml
parentInitial git commit. (diff)
downloadrust-d6b7c96c3eb29b9244ece0c046d3f372ff432d04.tar.xz
rust-d6b7c96c3eb29b9244ece0c046d3f372ff432d04.zip
Populate tree.
Diffstat (limited to 'src/boot/me/dwarf.ml')
-rw-r--r--src/boot/me/dwarf.ml3019
1 files changed, 3019 insertions, 0 deletions
diff --git a/src/boot/me/dwarf.ml b/src/boot/me/dwarf.ml
new file mode 100644
index 00000000..9423d4ee
--- /dev/null
+++ b/src/boot/me/dwarf.ml
@@ -0,0 +1,3019 @@
+(*
+ * Walk crate and generate DWARF-3 records. This file might also go in
+ * the be/ directory; it's half-middle-end, half-back-end. Debug info is
+ * like that.
+ *
+ * Some notes about DWARF:
+ *
+ * - Records form an ownership tree. The tree is serialized in
+ * depth-first pre-order with child lists ending with null
+ * records. When a node type is defined to have no children, no null
+ * child record is provided; it's implied.
+ *
+ * [parent]
+ * / \
+ * [child1] [child2]
+ * |
+ * [grandchild1]
+ *
+ * serializes as:
+ *
+ * [parent][child1][grandchild1][null][child2][null][null]
+ *
+ * - Sometimes you want to make it possible to scan through a sibling
+ * list quickly while skipping the sub-children of each (such as
+ * skipping the 'grandchild' above); this can be done with a
+ * DW_AT_sibling attribute that points forward to the next same-level
+ * sibling.
+ *
+ * - A DWARF consumer contains a little stack-machine interpreter for
+ * a micro-language that you can embed in DWARF records to compute
+ * values algorithmically.
+ *
+ * - DWARF is not "officially" supported by any Microsoft tools in
+ * PE files, but the Microsoft debugging information formats are
+ * proprietary and ever-shifting, and not clearly sufficient for
+ * our needs; by comparison DWARF is widely supported, stable,
+ * flexible, and required everywhere *else*. We are using DWARF to
+ * support major components of the rust runtime (reflection,
+ * unwinding, profiling) so it's helpful to not have to span
+ * technologies, just focus on DWARF. Luckily the MINGW/Cygwin
+ * communities have worked out a convention for PE, and taught BFD
+ * (thus most tools) how to digest DWARF sections trailing after
+ * the .idata section of a normal PE file. Seems to work fine.
+ *
+ * - DWARF supports variable-length coding using LEB128, and in the
+ * cases where these are symbolic or self-contained numbers, we
+ * support them in the assembler. Inter-DWARF-record references
+ * can be done via fixed-size DW_FORM_ref{1,2,4,8} or
+ * DW_FORM_ref_addr; or else via variable-size (LEB128)
+ * DW_FORM_ref_udata. It is hazardous to use the LEB128 form in
+ * our implementation of references, since we use a generic 2-pass
+ * (+ relaxation) fixup mechanism in our assembler which in
+ * general may present an information-dependency cycle for LEB128
+ * coding of offsets: you need to know the offset before you can
+ * work out the LEB128 size, and you may need to know several
+ * LEB128-sizes before you can work out the offsets of other
+ * LEB128s (possibly even the one you're currently coding). In
+ * general the assembler makes no attempt to resolve such
+ * cycles. It'll just throw if it can't handle what you ask
+ * for. So it's best to pay a little extra space and use
+ * DW_FORM_ref_addr or DW_FORM_ref{1,2,4,8} values, in all cases.
+ *)
+
+open Semant;;
+open Common;;
+open Asm;;
+
+let log cx = Session.log "dwarf"
+ cx.ctxt_sess.Session.sess_log_dwarf
+ cx.ctxt_sess.Session.sess_log_out
+;;
+
+type dw_tag =
+ DW_TAG_array_type
+ | DW_TAG_class_type
+ | DW_TAG_entry_point
+ | DW_TAG_enumeration_type
+ | DW_TAG_formal_parameter
+ | DW_TAG_imported_declaration
+ | DW_TAG_label
+ | DW_TAG_lexical_block
+ | DW_TAG_member
+ | DW_TAG_pointer_type
+ | DW_TAG_reference_type
+ | DW_TAG_compile_unit
+ | DW_TAG_string_type
+ | DW_TAG_structure_type
+ | DW_TAG_subroutine_type
+ | DW_TAG_typedef
+ | DW_TAG_union_type
+ | DW_TAG_unspecified_parameters
+ | DW_TAG_variant
+ | DW_TAG_common_block
+ | DW_TAG_common_inclusion
+ | DW_TAG_inheritance
+ | DW_TAG_inlined_subroutine
+ | DW_TAG_module
+ | DW_TAG_ptr_to_member_type
+ | DW_TAG_set_type
+ | DW_TAG_subrange_type
+ | DW_TAG_with_stmt
+ | DW_TAG_access_declaration
+ | DW_TAG_base_type
+ | DW_TAG_catch_block
+ | DW_TAG_const_type
+ | DW_TAG_constant
+ | DW_TAG_enumerator
+ | DW_TAG_file_type
+ | DW_TAG_friend
+ | DW_TAG_namelist
+ | DW_TAG_namelist_item
+ | DW_TAG_packed_type
+ | DW_TAG_subprogram
+ | DW_TAG_template_type_parameter
+ | DW_TAG_template_value_parameter
+ | DW_TAG_thrown_type
+ | DW_TAG_try_block
+ | DW_TAG_variant_part
+ | DW_TAG_variable
+ | DW_TAG_volatile_type
+ | DW_TAG_dwarf_procedure
+ | DW_TAG_restrict_type
+ | DW_TAG_interface_type
+ | DW_TAG_namespace
+ | DW_TAG_imported_module
+ | DW_TAG_unspecified_type
+ | DW_TAG_partial_unit
+ | DW_TAG_imported_unit
+ | DW_TAG_condition
+ | DW_TAG_shared_type
+ | DW_TAG_lo_user
+ | DW_TAG_rust_meta
+ | DW_TAG_hi_user
+;;
+
+
+let dw_tag_to_int (tag:dw_tag) : int =
+ match tag with
+ DW_TAG_array_type -> 0x01
+ | DW_TAG_class_type -> 0x02
+ | DW_TAG_entry_point -> 0x03
+ | DW_TAG_enumeration_type -> 0x04
+ | DW_TAG_formal_parameter -> 0x05
+ | DW_TAG_imported_declaration -> 0x08
+ | DW_TAG_label -> 0x0a
+ | DW_TAG_lexical_block -> 0x0b
+ | DW_TAG_member -> 0x0d
+ | DW_TAG_pointer_type -> 0x0f
+ | DW_TAG_reference_type -> 0x10
+ | DW_TAG_compile_unit -> 0x11
+ | DW_TAG_string_type -> 0x12
+ | DW_TAG_structure_type -> 0x13
+ | DW_TAG_subroutine_type -> 0x15
+ | DW_TAG_typedef -> 0x16
+ | DW_TAG_union_type -> 0x17
+ | DW_TAG_unspecified_parameters -> 0x18
+ | DW_TAG_variant -> 0x19
+ | DW_TAG_common_block -> 0x1a
+ | DW_TAG_common_inclusion -> 0x1b
+ | DW_TAG_inheritance -> 0x1c
+ | DW_TAG_inlined_subroutine -> 0x1d
+ | DW_TAG_module -> 0x1e
+ | DW_TAG_ptr_to_member_type -> 0x1f
+ | DW_TAG_set_type -> 0x20
+ | DW_TAG_subrange_type -> 0x21
+ | DW_TAG_with_stmt -> 0x22
+ | DW_TAG_access_declaration -> 0x23
+ | DW_TAG_base_type -> 0x24
+ | DW_TAG_catch_block -> 0x25
+ | DW_TAG_const_type -> 0x26
+ | DW_TAG_constant -> 0x27
+ | DW_TAG_enumerator -> 0x28
+ | DW_TAG_file_type -> 0x29
+ | DW_TAG_friend -> 0x2a
+ | DW_TAG_namelist -> 0x2b
+ | DW_TAG_namelist_item -> 0x2c
+ | DW_TAG_packed_type -> 0x2d
+ | DW_TAG_subprogram -> 0x2e
+ | DW_TAG_template_type_parameter -> 0x2f
+ | DW_TAG_template_value_parameter -> 0x30
+ | DW_TAG_thrown_type -> 0x31
+ | DW_TAG_try_block -> 0x32
+ | DW_TAG_variant_part -> 0x33
+ | DW_TAG_variable -> 0x34
+ | DW_TAG_volatile_type -> 0x35
+ | DW_TAG_dwarf_procedure -> 0x36
+ | DW_TAG_restrict_type -> 0x37
+ | DW_TAG_interface_type -> 0x38
+ | DW_TAG_namespace -> 0x39
+ | DW_TAG_imported_module -> 0x3a
+ | DW_TAG_unspecified_type -> 0x3b
+ | DW_TAG_partial_unit -> 0x3c
+ | DW_TAG_imported_unit -> 0x3d
+ | DW_TAG_condition -> 0x3f
+ | DW_TAG_shared_type -> 0x40
+ | DW_TAG_lo_user -> 0x4080
+ | DW_TAG_rust_meta -> 0x4300
+ | DW_TAG_hi_user -> 0xffff
+;;
+
+let dw_tag_of_int (i:int) : dw_tag =
+ match i with
+ 0x01 -> DW_TAG_array_type
+ | 0x02 -> DW_TAG_class_type
+ | 0x03 -> DW_TAG_entry_point
+ | 0x04 -> DW_TAG_enumeration_type
+ | 0x05 -> DW_TAG_formal_parameter
+ | 0x08 -> DW_TAG_imported_declaration
+ | 0x0a -> DW_TAG_label
+ | 0x0b -> DW_TAG_lexical_block
+ | 0x0d -> DW_TAG_member
+ | 0x0f -> DW_TAG_pointer_type
+ | 0x10 -> DW_TAG_reference_type
+ | 0x11 -> DW_TAG_compile_unit
+ | 0x12 -> DW_TAG_string_type
+ | 0x13 -> DW_TAG_structure_type
+ | 0x15 -> DW_TAG_subroutine_type
+ | 0x16 -> DW_TAG_typedef
+ | 0x17 -> DW_TAG_union_type
+ | 0x18 -> DW_TAG_unspecified_parameters
+ | 0x19 -> DW_TAG_variant
+ | 0x1a -> DW_TAG_common_block
+ | 0x1b -> DW_TAG_common_inclusion
+ | 0x1c -> DW_TAG_inheritance
+ | 0x1d -> DW_TAG_inlined_subroutine
+ | 0x1e -> DW_TAG_module
+ | 0x1f -> DW_TAG_ptr_to_member_type
+ | 0x20 -> DW_TAG_set_type
+ | 0x21 -> DW_TAG_subrange_type
+ | 0x22 -> DW_TAG_with_stmt
+ | 0x23 -> DW_TAG_access_declaration
+ | 0x24 -> DW_TAG_base_type
+ | 0x25 -> DW_TAG_catch_block
+ | 0x26 -> DW_TAG_const_type
+ | 0x27 -> DW_TAG_constant
+ | 0x28 -> DW_TAG_enumerator
+ | 0x29 -> DW_TAG_file_type
+ | 0x2a -> DW_TAG_friend
+ | 0x2b -> DW_TAG_namelist
+ | 0x2c -> DW_TAG_namelist_item
+ | 0x2d -> DW_TAG_packed_type
+ | 0x2e -> DW_TAG_subprogram
+ | 0x2f -> DW_TAG_template_type_parameter
+ | 0x30 -> DW_TAG_template_value_parameter
+ | 0x31 -> DW_TAG_thrown_type
+ | 0x32 -> DW_TAG_try_block
+ | 0x33 -> DW_TAG_variant_part
+ | 0x34 -> DW_TAG_variable
+ | 0x35 -> DW_TAG_volatile_type
+ | 0x36 -> DW_TAG_dwarf_procedure
+ | 0x37 -> DW_TAG_restrict_type
+ | 0x38 -> DW_TAG_interface_type
+ | 0x39 -> DW_TAG_namespace
+ | 0x3a -> DW_TAG_imported_module
+ | 0x3b -> DW_TAG_unspecified_type
+ | 0x3c -> DW_TAG_partial_unit
+ | 0x3d -> DW_TAG_imported_unit
+ | 0x3f -> DW_TAG_condition
+ | 0x40 -> DW_TAG_shared_type
+ | 0x4080 -> DW_TAG_lo_user
+ | 0x4300 -> DW_TAG_rust_meta
+ | 0xffff -> DW_TAG_hi_user
+ | _ -> bug () "bad DWARF tag code: %d" i
+;;
+
+
+let dw_tag_to_string (tag:dw_tag) : string =
+ match tag with
+ DW_TAG_array_type -> "DW_TAG_array_type"
+ | DW_TAG_class_type -> "DW_TAG_class_type"
+ | DW_TAG_entry_point -> "DW_TAG_entry_point"
+ | DW_TAG_enumeration_type -> "DW_TAG_enumeration_type"
+ | DW_TAG_formal_parameter -> "DW_TAG_formal_parameter"
+ | DW_TAG_imported_declaration -> "DW_TAG_imported_declaration"
+ | DW_TAG_label -> "DW_TAG_label"
+ | DW_TAG_lexical_block -> "DW_TAG_lexical_block"
+ | DW_TAG_member -> "DW_TAG_member"
+ | DW_TAG_pointer_type -> "DW_TAG_pointer_type"
+ | DW_TAG_reference_type -> "DW_TAG_reference_type"
+ | DW_TAG_compile_unit -> "DW_TAG_compile_unit"
+ | DW_TAG_string_type -> "DW_TAG_string_type"
+ | DW_TAG_structure_type -> "DW_TAG_structure_type"
+ | DW_TAG_subroutine_type -> "DW_TAG_subroutine_type"
+ | DW_TAG_typedef -> "DW_TAG_typedef"
+ | DW_TAG_union_type -> "DW_TAG_union_type"
+ | DW_TAG_unspecified_parameters -> "DW_TAG_unspecified_parameters"
+ | DW_TAG_variant -> "DW_TAG_variant"
+ | DW_TAG_common_block -> "DW_TAG_common_block"
+ | DW_TAG_common_inclusion -> "DW_TAG_common_inclusion"
+ | DW_TAG_inheritance -> "DW_TAG_inheritance"
+ | DW_TAG_inlined_subroutine -> "DW_TAG_inlined_subroutine"
+ | DW_TAG_module -> "DW_TAG_module"
+ | DW_TAG_ptr_to_member_type -> "DW_TAG_ptr_to_member_type"
+ | DW_TAG_set_type -> "DW_TAG_set_type"
+ | DW_TAG_subrange_type -> "DW_TAG_subrange_type"
+ | DW_TAG_with_stmt -> "DW_TAG_with_stmt"
+ | DW_TAG_access_declaration -> "DW_TAG_access_declaration"
+ | DW_TAG_base_type -> "DW_TAG_base_type"
+ | DW_TAG_catch_block -> "DW_TAG_catch_block"
+ | DW_TAG_const_type -> "DW_TAG_const_type"
+ | DW_TAG_constant -> "DW_TAG_constant"
+ | DW_TAG_enumerator -> "DW_TAG_enumerator"
+ | DW_TAG_file_type -> "DW_TAG_file_type"
+ | DW_TAG_friend -> "DW_TAG_friend"
+ | DW_TAG_namelist -> "DW_TAG_namelist"
+ | DW_TAG_namelist_item -> "DW_TAG_namelist_item"
+ | DW_TAG_packed_type -> "DW_TAG_packed_type"
+ | DW_TAG_subprogram -> "DW_TAG_subprogram"
+ | DW_TAG_template_type_parameter -> "DW_TAG_template_type_parameter"
+ | DW_TAG_template_value_parameter -> "DW_TAG_template_value_parameter"
+ | DW_TAG_thrown_type -> "DW_TAG_thrown_type"
+ | DW_TAG_try_block -> "DW_TAG_try_block"
+ | DW_TAG_variant_part -> "DW_TAG_variant_part"
+ | DW_TAG_variable -> "DW_TAG_variable"
+ | DW_TAG_volatile_type -> "DW_TAG_volatile_type"
+ | DW_TAG_dwarf_procedure -> "DW_TAG_dwarf_procedure"
+ | DW_TAG_restrict_type -> "DW_TAG_restrict_type"
+ | DW_TAG_interface_type -> "DW_TAG_interface_type"
+ | DW_TAG_namespace -> "DW_TAG_namespace"
+ | DW_TAG_imported_module -> "DW_TAG_imported_module"
+ | DW_TAG_unspecified_type -> "DW_TAG_unspecified_type"
+ | DW_TAG_partial_unit -> "DW_TAG_partial_unit"
+ | DW_TAG_imported_unit -> "DW_TAG_imported_unit"
+ | DW_TAG_condition -> "DW_TAG_condition"
+ | DW_TAG_shared_type -> "DW_TAG_shared_type"
+ | DW_TAG_lo_user -> "DW_TAG_lo_user"
+ | DW_TAG_rust_meta -> "DW_TAG_rust_meta"
+ | DW_TAG_hi_user -> "DW_TAG_hi_user"
+;;
+
+
+type dw_children =
+ DW_CHILDREN_no
+ | DW_CHILDREN_yes
+;;
+
+
+let dw_children_to_int (ch:dw_children) : int =
+ match ch with
+ DW_CHILDREN_no -> 0x00
+ | DW_CHILDREN_yes -> 0x01
+;;
+
+let dw_children_of_int (i:int) : dw_children =
+ match i with
+ 0 -> DW_CHILDREN_no
+ | 1 -> DW_CHILDREN_yes
+ | _ -> bug () "bad DWARF children code: %d" i
+;;
+
+type dw_at =
+ DW_AT_sibling
+ | DW_AT_location
+ | DW_AT_name
+ | DW_AT_ordering
+ | DW_AT_byte_size
+ | DW_AT_bit_offset
+ | DW_AT_bit_size
+ | DW_AT_stmt_list
+ | DW_AT_low_pc
+ | DW_AT_high_pc
+ | DW_AT_language
+ | DW_AT_discr
+ | DW_AT_discr_value
+ | DW_AT_visibility
+ | DW_AT_import
+ | DW_AT_string_length
+ | DW_AT_common_reference
+ | DW_AT_comp_dir
+ | DW_AT_const_value
+ | DW_AT_containing_type
+ | DW_AT_default_value
+ | DW_AT_inline
+ | DW_AT_is_optional
+ | DW_AT_lower_bound
+ | DW_AT_producer
+ | DW_AT_prototyped
+ | DW_AT_return_addr
+ | DW_AT_start_scope
+ | DW_AT_bit_stride
+ | DW_AT_upper_bound
+ | DW_AT_abstract_origin
+ | DW_AT_accessibility
+ | DW_AT_address_class
+ | DW_AT_artificial
+ | DW_AT_base_types
+ | DW_AT_calling_convention
+ | DW_AT_count
+ | DW_AT_data_member_location
+ | DW_AT_decl_column
+ | DW_AT_decl_file
+ | DW_AT_decl_line
+ | DW_AT_declaration
+ | DW_AT_discr_list
+ | DW_AT_encoding
+ | DW_AT_external
+ | DW_AT_frame_base
+ | DW_AT_friend
+ | DW_AT_identifier_case
+ | DW_AT_macro_info
+ | DW_AT_namelist_item
+ | DW_AT_priority
+ | DW_AT_segment
+ | DW_AT_specification
+ | DW_AT_static_link
+ | DW_AT_type
+ | DW_AT_use_location
+ | DW_AT_variable_parameter
+ | DW_AT_virtuality
+ | DW_AT_vtable_elem_location
+ | DW_AT_allocated
+ | DW_AT_associated
+ | DW_AT_data_location
+ | DW_AT_byte_stride
+ | DW_AT_entry_pc
+ | DW_AT_use_UTF8
+ | DW_AT_extension
+ | DW_AT_ranges
+ | DW_AT_trampoline
+ | DW_AT_call_column
+ | DW_AT_call_file
+ | DW_AT_call_line
+ | DW_AT_description
+ | DW_AT_binary_scale
+ | DW_AT_decimal_scale
+ | DW_AT_small
+ | DW_AT_decimal_sign
+ | DW_AT_digit_count
+ | DW_AT_picture_string
+ | DW_AT_mutable
+ | DW_AT_threads_scaled
+ | DW_AT_explicit
+ | DW_AT_object_pointer
+ | DW_AT_endianity
+ | DW_AT_elemental
+ | DW_AT_pure
+ | DW_AT_recursive
+ | DW_AT_lo_user
+ | DW_AT_rust_type_code
+ | DW_AT_rust_type_param_index
+ | DW_AT_rust_iterator
+ | DW_AT_rust_native_type_id
+ | DW_AT_hi_user
+;;
+
+
+let dw_at_to_int (a:dw_at) : int =
+ match a with
+ DW_AT_sibling -> 0x01
+ | DW_AT_location -> 0x02
+ | DW_AT_name -> 0x03
+ | DW_AT_ordering -> 0x09
+ | DW_AT_byte_size -> 0x0b
+ | DW_AT_bit_offset -> 0x0c
+ | DW_AT_bit_size -> 0x0d
+ | DW_AT_stmt_list -> 0x10
+ | DW_AT_low_pc -> 0x11
+ | DW_AT_high_pc -> 0x12
+ | DW_AT_language -> 0x13
+ | DW_AT_discr -> 0x15
+ | DW_AT_discr_value -> 0x16
+ | DW_AT_visibility -> 0x17
+ | DW_AT_import -> 0x18
+ | DW_AT_string_length -> 0x19
+ | DW_AT_common_reference -> 0x1a
+ | DW_AT_comp_dir -> 0x1b
+ | DW_AT_const_value -> 0x1c
+ | DW_AT_containing_type -> 0x1d
+ | DW_AT_default_value -> 0x1e
+ | DW_AT_inline -> 0x20
+ | DW_AT_is_optional -> 0x21
+ | DW_AT_lower_bound -> 0x22
+ | DW_AT_producer -> 0x25
+ | DW_AT_prototyped -> 0x27
+ | DW_AT_return_addr -> 0x2a
+ | DW_AT_start_scope -> 0x2c
+ | DW_AT_bit_stride -> 0x2e
+ | DW_AT_upper_bound -> 0x2f
+ | DW_AT_abstract_origin -> 0x31
+ | DW_AT_accessibility -> 0x32
+ | DW_AT_address_class -> 0x33
+ | DW_AT_artificial -> 0x34
+ | DW_AT_base_types -> 0x35
+ | DW_AT_calling_convention -> 0x36
+ | DW_AT_count -> 0x37
+ | DW_AT_data_member_location -> 0x38
+ | DW_AT_decl_column -> 0x39
+ | DW_AT_decl_file -> 0x3a
+ | DW_AT_decl_line -> 0x3b
+ | DW_AT_declaration -> 0x3c
+ | DW_AT_discr_list -> 0x3d
+ | DW_AT_encoding -> 0x3e
+ | DW_AT_external -> 0x3f
+ | DW_AT_frame_base -> 0x40
+ | DW_AT_friend -> 0x41
+ | DW_AT_identifier_case -> 0x42
+ | DW_AT_macro_info -> 0x43
+ | DW_AT_namelist_item -> 0x44
+ | DW_AT_priority -> 0x45
+ | DW_AT_segment -> 0x46
+ | DW_AT_specification -> 0x47
+ | DW_AT_static_link -> 0x48
+ | DW_AT_type -> 0x49
+ | DW_AT_use_location -> 0x4a
+ | DW_AT_variable_parameter -> 0x4b
+ | DW_AT_virtuality -> 0x4c
+ | DW_AT_vtable_elem_location -> 0x4d
+ | DW_AT_allocated -> 0x4e
+ | DW_AT_associated -> 0x4f
+ | DW_AT_data_location -> 0x50
+ | DW_AT_byte_stride -> 0x51
+ | DW_AT_entry_pc -> 0x52
+ | DW_AT_use_UTF8 -> 0x53
+ | DW_AT_extension -> 0x54
+ | DW_AT_ranges -> 0x55
+ | DW_AT_trampoline -> 0x56
+ | DW_AT_call_column -> 0x57
+ | DW_AT_call_file -> 0x58
+ | DW_AT_call_line -> 0x59
+ | DW_AT_description -> 0x5a
+ | DW_AT_binary_scale -> 0x5b
+ | DW_AT_decimal_scale -> 0x5c
+ | DW_AT_small -> 0x5d
+ | DW_AT_decimal_sign -> 0x5e
+ | DW_AT_digit_count -> 0x5f
+ | DW_AT_picture_string -> 0x60
+ | DW_AT_mutable -> 0x61
+ | DW_AT_threads_scaled -> 0x62
+ | DW_AT_explicit -> 0x63
+ | DW_AT_object_pointer -> 0x64
+ | DW_AT_endianity -> 0x65
+ | DW_AT_elemental -> 0x66
+ | DW_AT_pure -> 0x67
+ | DW_AT_recursive -> 0x68
+ | DW_AT_lo_user -> 0x2000
+ | DW_AT_rust_type_code -> 0x2300
+ | DW_AT_rust_type_param_index -> 0x2301
+ | DW_AT_rust_iterator -> 0x2302
+ | DW_AT_rust_native_type_id -> 0x2303
+ | DW_AT_hi_user -> 0x3fff
+;;
+
+let dw_at_of_int (i:int) : dw_at =
+ match i with
+ 0x01 -> DW_AT_sibling
+ | 0x02 -> DW_AT_location
+ | 0x03 -> DW_AT_name
+ | 0x09 -> DW_AT_ordering
+ | 0x0b -> DW_AT_byte_size
+ | 0x0c -> DW_AT_bit_offset
+ | 0x0d -> DW_AT_bit_size
+ | 0x10 -> DW_AT_stmt_list
+ | 0x11 -> DW_AT_low_pc
+ | 0x12 -> DW_AT_high_pc
+ | 0x13 -> DW_AT_language
+ | 0x15 -> DW_AT_discr
+ | 0x16 -> DW_AT_discr_value
+ | 0x17 -> DW_AT_visibility
+ | 0x18 -> DW_AT_import
+ | 0x19 -> DW_AT_string_length
+ | 0x1a -> DW_AT_common_reference
+ | 0x1b -> DW_AT_comp_dir
+ | 0x1c -> DW_AT_const_value
+ | 0x1d -> DW_AT_containing_type
+ | 0x1e -> DW_AT_default_value
+ | 0x20 -> DW_AT_inline
+ | 0x21 -> DW_AT_is_optional
+ | 0x22 -> DW_AT_lower_bound
+ | 0x25 -> DW_AT_producer
+ | 0x27 -> DW_AT_prototyped
+ | 0x2a -> DW_AT_return_addr
+ | 0x2c -> DW_AT_start_scope
+ | 0x2e -> DW_AT_bit_stride
+ | 0x2f -> DW_AT_upper_bound
+ | 0x31 -> DW_AT_abstract_origin
+ | 0x32 -> DW_AT_accessibility
+ | 0x33 -> DW_AT_address_class
+ | 0x34 -> DW_AT_artificial
+ | 0x35 -> DW_AT_base_types
+ | 0x36 -> DW_AT_calling_convention
+ | 0x37 -> DW_AT_count
+ | 0x38 -> DW_AT_data_member_location
+ | 0x39 -> DW_AT_decl_column
+ | 0x3a -> DW_AT_decl_file
+ | 0x3b -> DW_AT_decl_line
+ | 0x3c -> DW_AT_declaration
+ | 0x3d -> DW_AT_discr_list
+ | 0x3e -> DW_AT_encoding
+ | 0x3f -> DW_AT_external
+ | 0x40 -> DW_AT_frame_base
+ | 0x41 -> DW_AT_friend
+ | 0x42 -> DW_AT_identifier_case
+ | 0x43 -> DW_AT_macro_info
+ | 0x44 -> DW_AT_namelist_item
+ | 0x45 -> DW_AT_priority
+ | 0x46 -> DW_AT_segment
+ | 0x47 -> DW_AT_specification
+ | 0x48 -> DW_AT_static_link
+ | 0x49 -> DW_AT_type
+ | 0x4a -> DW_AT_use_location
+ | 0x4b -> DW_AT_variable_parameter
+ | 0x4c -> DW_AT_virtuality
+ | 0x4d -> DW_AT_vtable_elem_location
+ | 0x4e -> DW_AT_allocated
+ | 0x4f -> DW_AT_associated
+ | 0x50 -> DW_AT_data_location
+ | 0x51 -> DW_AT_byte_stride
+ | 0x52 -> DW_AT_entry_pc
+ | 0x53 -> DW_AT_use_UTF8
+ | 0x54 -> DW_AT_extension
+ | 0x55 -> DW_AT_ranges
+ | 0x56 -> DW_AT_trampoline
+ | 0x57 -> DW_AT_call_column
+ | 0x58 -> DW_AT_call_file
+ | 0x59 -> DW_AT_call_line
+ | 0x5a -> DW_AT_description
+ | 0x5b -> DW_AT_binary_scale
+ | 0x5c -> DW_AT_decimal_scale
+ | 0x5d -> DW_AT_small
+ | 0x5e -> DW_AT_decimal_sign
+ | 0x5f -> DW_AT_digit_count
+ | 0x60 -> DW_AT_picture_string
+ | 0x61 -> DW_AT_mutable
+ | 0x62 -> DW_AT_threads_scaled
+ | 0x63 -> DW_AT_explicit
+ | 0x64 -> DW_AT_object_pointer
+ | 0x65 -> DW_AT_endianity
+ | 0x66 -> DW_AT_elemental
+ | 0x67 -> DW_AT_pure
+ | 0x68 -> DW_AT_recursive
+ | 0x2000 -> DW_AT_lo_user
+ | 0x2300 -> DW_AT_rust_type_code
+ | 0x2301 -> DW_AT_rust_type_param_index
+ | 0x2302 -> DW_AT_rust_iterator
+ | 0x2303 -> DW_AT_rust_native_type_id
+ | 0x3fff -> DW_AT_hi_user
+ | _ -> bug () "bad DWARF attribute code: 0x%x" i
+;;
+
+let dw_at_to_string (a:dw_at) : string =
+ match a with
+ DW_AT_sibling -> "DW_AT_sibling"
+ | DW_AT_location -> "DW_AT_location"
+ | DW_AT_name -> "DW_AT_name"
+ | DW_AT_ordering -> "DW_AT_ordering"
+ | DW_AT_byte_size -> "DW_AT_byte_size"
+ | DW_AT_bit_offset -> "DW_AT_bit_offset"
+ | DW_AT_bit_size -> "DW_AT_bit_size"
+ | DW_AT_stmt_list -> "DW_AT_stmt_list"
+ | DW_AT_low_pc -> "DW_AT_low_pc"
+ | DW_AT_high_pc -> "DW_AT_high_pc"
+ | DW_AT_language -> "DW_AT_language"
+ | DW_AT_discr -> "DW_AT_discr"
+ | DW_AT_discr_value -> "DW_AT_discr_value"
+ | DW_AT_visibility -> "DW_AT_visibility"
+ | DW_AT_import -> "DW_AT_import"
+ | DW_AT_string_length -> "DW_AT_string_length"
+ | DW_AT_common_reference -> "DW_AT_common_reference"
+ | DW_AT_comp_dir -> "DW_AT_comp_dir"
+ | DW_AT_const_value -> "DW_AT_const_value"
+ | DW_AT_containing_type -> "DW_AT_containing_type"
+ | DW_AT_default_value -> "DW_AT_default_value"
+ | DW_AT_inline -> "DW_AT_inline"
+ | DW_AT_is_optional -> "DW_AT_is_optional"
+ | DW_AT_lower_bound -> "DW_AT_lower_bound"
+ | DW_AT_producer -> "DW_AT_producer"
+ | DW_AT_prototyped -> "DW_AT_prototyped"
+ | DW_AT_return_addr -> "DW_AT_return_addr"
+ | DW_AT_start_scope -> "DW_AT_start_scope"
+ | DW_AT_bit_stride -> "DW_AT_bit_stride"
+ | DW_AT_upper_bound -> "DW_AT_upper_bound"
+ | DW_AT_abstract_origin -> "DW_AT_abstract_origin"
+ | DW_AT_accessibility -> "DW_AT_accessibility"
+ | DW_AT_address_class -> "DW_AT_address_class"
+ | DW_AT_artificial -> "DW_AT_artificial"
+ | DW_AT_base_types -> "DW_AT_base_types"
+ | DW_AT_calling_convention -> "DW_AT_calling_convention"
+ | DW_AT_count -> "DW_AT_count"
+ | DW_AT_data_member_location -> "DW_AT_data_member_location"
+ | DW_AT_decl_column -> "DW_AT_decl_column"
+ | DW_AT_decl_file -> "DW_AT_decl_file"
+ | DW_AT_decl_line -> "DW_AT_decl_line"
+ | DW_AT_declaration -> "DW_AT_declaration"
+ | DW_AT_discr_list -> "DW_AT_discr_list"
+ | DW_AT_encoding -> "DW_AT_encoding"
+ | DW_AT_external -> "DW_AT_external"
+ | DW_AT_frame_base -> "DW_AT_frame_base"
+ | DW_AT_friend -> "DW_AT_friend"
+ | DW_AT_identifier_case -> "DW_AT_identifier_case"
+ | DW_AT_macro_info -> "DW_AT_macro_info"
+ | DW_AT_namelist_item -> "DW_AT_namelist_item"
+ | DW_AT_priority -> "DW_AT_priority"
+ | DW_AT_segment -> "DW_AT_segment"
+ | DW_AT_specification -> "DW_AT_specification"
+ | DW_AT_static_link -> "DW_AT_static_link"
+ | DW_AT_type -> "DW_AT_type"
+ | DW_AT_use_location -> "DW_AT_use_location"
+ | DW_AT_variable_parameter -> "DW_AT_variable_parameter"
+ | DW_AT_virtuality -> "DW_AT_virtuality"
+ | DW_AT_vtable_elem_location -> "DW_AT_vtable_elem_location"
+ | DW_AT_allocated -> "DW_AT_allocated"
+ | DW_AT_associated -> "DW_AT_associated"
+ | DW_AT_data_location -> "DW_AT_data_location"
+ | DW_AT_byte_stride -> "DW_AT_byte_stride"
+ | DW_AT_entry_pc -> "DW_AT_entry_pc"
+ | DW_AT_use_UTF8 -> "DW_AT_use_UTF8"
+ | DW_AT_extension -> "DW_AT_extension"
+ | DW_AT_ranges -> "DW_AT_ranges"
+ | DW_AT_trampoline -> "DW_AT_trampoline"
+ | DW_AT_call_column -> "DW_AT_call_column"
+ | DW_AT_call_file -> "DW_AT_call_file"
+ | DW_AT_call_line -> "DW_AT_call_line"
+ | DW_AT_description -> "DW_AT_description"
+ | DW_AT_binary_scale -> "DW_AT_binary_scale"
+ | DW_AT_decimal_scale -> "DW_AT_decimal_scale"
+ | DW_AT_small -> "DW_AT_small"
+ | DW_AT_decimal_sign -> "DW_AT_decimal_sign"
+ | DW_AT_digit_count -> "DW_AT_digit_count"
+ | DW_AT_picture_string -> "DW_AT_picture_string"
+ | DW_AT_mutable -> "DW_AT_mutable"
+ | DW_AT_threads_scaled -> "DW_AT_threads_scaled"
+ | DW_AT_explicit -> "DW_AT_explicit"
+ | DW_AT_object_pointer -> "DW_AT_object_pointer"
+ | DW_AT_endianity -> "DW_AT_endianity"
+ | DW_AT_elemental -> "DW_AT_elemental"
+ | DW_AT_pure -> "DW_AT_pure"
+ | DW_AT_recursive -> "DW_AT_recursive"
+ | DW_AT_lo_user -> "DW_AT_lo_user"
+ | DW_AT_rust_type_code -> "DW_AT_rust_type_code"
+ | DW_AT_rust_type_param_index -> "DW_AT_rust_type_param_index"
+ | DW_AT_rust_iterator -> "DW_AT_rust_iterator"
+ | DW_AT_rust_native_type_id -> "DW_AT_native_type_id"
+ | DW_AT_hi_user -> "DW_AT_hi_user"
+;;
+
+(*
+ * We encode our 'built-in types' using DW_TAG_pointer_type and various
+ * DW_AT_pointer_type_codes. This seems to be more gdb-compatible than
+ * the DWARF-recommended way of using DW_TAG_unspecified_type.
+ *)
+type dw_rust_type =
+ DW_RUST_type_param
+ | DW_RUST_nil
+ | DW_RUST_vec
+ | DW_RUST_chan
+ | DW_RUST_port
+ | DW_RUST_task
+ | DW_RUST_tag
+ | DW_RUST_iso
+ | DW_RUST_type
+ | DW_RUST_native
+;;
+
+let dw_rust_type_to_int (pt:dw_rust_type) : int =
+ match pt with
+ DW_RUST_type_param -> 0x1
+ | DW_RUST_nil -> 0x2
+ | DW_RUST_vec -> 0x3
+ | DW_RUST_chan -> 0x4
+ | DW_RUST_port -> 0x5
+ | DW_RUST_task -> 0x6
+ | DW_RUST_tag -> 0x7
+ | DW_RUST_iso -> 0x8
+ | DW_RUST_type -> 0x9
+ | DW_RUST_native -> 0xa
+;;
+
+let dw_rust_type_of_int (i:int) : dw_rust_type =
+ match i with
+ 0x1 -> DW_RUST_type_param
+ | 0x2 -> DW_RUST_nil
+ | 0x3 -> DW_RUST_vec
+ | 0x4 -> DW_RUST_chan
+ | 0x5 -> DW_RUST_port
+ | 0x6 -> DW_RUST_task
+ | 0x7 -> DW_RUST_tag
+ | 0x8 -> DW_RUST_iso
+ | 0x9 -> DW_RUST_type
+ | 0xa -> DW_RUST_native
+ | _ -> bug () "bad DWARF rust-pointer-type code: %d" i
+;;
+
+type dw_ate =
+ DW_ATE_address
+ | DW_ATE_boolean
+ | DW_ATE_complex_float
+ | DW_ATE_float
+ | DW_ATE_signed
+ | DW_ATE_signed_char
+ | DW_ATE_unsigned
+ | DW_ATE_unsigned_char
+ | DW_ATE_imaginary_float
+ | DW_ATE_packed_decimal
+ | DW_ATE_numeric_string
+ | DW_ATE_edited
+ | DW_ATE_signed_fixed
+ | DW_ATE_unsigned_fixed
+ | DW_ATE_decimal_float
+ | DW_ATE_lo_user
+ | DW_ATE_hi_user
+;;
+
+let dw_ate_to_int (ate:dw_ate) : int =
+ match ate with
+ DW_ATE_address -> 0x01
+ | DW_ATE_boolean -> 0x02
+ | DW_ATE_complex_float -> 0x03
+ | DW_ATE_float -> 0x04
+ | DW_ATE_signed -> 0x05
+ | DW_ATE_signed_char -> 0x06
+ | DW_ATE_unsigned -> 0x07
+ | DW_ATE_unsigned_char -> 0x08
+ | DW_ATE_imaginary_float -> 0x09
+ | DW_ATE_packed_decimal -> 0x0a
+ | DW_ATE_numeric_string -> 0x0b
+ | DW_ATE_edited -> 0x0c
+ | DW_ATE_signed_fixed -> 0x0d
+ | DW_ATE_unsigned_fixed -> 0x0e
+ | DW_ATE_decimal_float -> 0x0f
+ | DW_ATE_lo_user -> 0x80
+ | DW_ATE_hi_user -> 0xff
+;;
+
+let dw_ate_of_int (i:int) : dw_ate =
+ match i with
+ 0x01 -> DW_ATE_address
+ | 0x02 -> DW_ATE_boolean
+ | 0x03 -> DW_ATE_complex_float
+ | 0x04 -> DW_ATE_float
+ | 0x05 -> DW_ATE_signed
+ | 0x06 -> DW_ATE_signed_char
+ | 0x07 -> DW_ATE_unsigned
+ | 0x08 -> DW_ATE_unsigned_char
+ | 0x09 -> DW_ATE_imaginary_float
+ | 0x0a -> DW_ATE_packed_decimal
+ | 0x0b -> DW_ATE_numeric_string
+ | 0x0c -> DW_ATE_edited
+ | 0x0d -> DW_ATE_signed_fixed
+ | 0x0e -> DW_ATE_unsigned_fixed
+ | 0x0f -> DW_ATE_decimal_float
+ | 0x80 -> DW_ATE_lo_user
+ | 0xff -> DW_ATE_hi_user
+ | _ -> bug () "bad DWARF attribute-encoding code: %d" i
+;;
+
+type dw_form =
+ | DW_FORM_addr
+ | DW_FORM_block2
+ | DW_FORM_block4
+ | DW_FORM_data2
+ | DW_FORM_data4
+ | DW_FORM_data8
+ | DW_FORM_string
+ | DW_FORM_block
+ | DW_FORM_block1
+ | DW_FORM_data1
+ | DW_FORM_flag
+ | DW_FORM_sdata
+ | DW_FORM_strp
+ | DW_FORM_udata
+ | DW_FORM_ref_addr
+ | DW_FORM_ref1
+ | DW_FORM_ref2
+ | DW_FORM_ref4
+ | DW_FORM_ref8
+ | DW_FORM_ref_udata
+ | DW_FORM_indirect
+;;
+
+
+let dw_form_to_int (f:dw_form) : int =
+ match f with
+ | DW_FORM_addr -> 0x01
+ | DW_FORM_block2 -> 0x03
+ | DW_FORM_block4 -> 0x04
+ | DW_FORM_data2 -> 0x05
+ | DW_FORM_data4 -> 0x06
+ | DW_FORM_data8 -> 0x07
+ | DW_FORM_string -> 0x08
+ | DW_FORM_block -> 0x09
+ | DW_FORM_block1 -> 0x0a
+ | DW_FORM_data1 -> 0x0b
+ | DW_FORM_flag -> 0x0c
+ | DW_FORM_sdata -> 0x0d
+ | DW_FORM_strp -> 0x0e
+ | DW_FORM_udata -> 0x0f
+ | DW_FORM_ref_addr -> 0x10
+ | DW_FORM_ref1 -> 0x11
+ | DW_FORM_ref2 -> 0x12
+ | DW_FORM_ref4 -> 0x13
+ | DW_FORM_ref8 -> 0x14
+ | DW_FORM_ref_udata -> 0x15
+ | DW_FORM_indirect -> 0x16
+;;
+
+let dw_form_of_int (i:int) : dw_form =
+ match i with
+ | 0x01 -> DW_FORM_addr
+ | 0x03 -> DW_FORM_block2
+ | 0x04 -> DW_FORM_block4
+ | 0x05 -> DW_FORM_data2
+ | 0x06 -> DW_FORM_data4
+ | 0x07 -> DW_FORM_data8
+ | 0x08 -> DW_FORM_string
+ | 0x09 -> DW_FORM_block
+ | 0x0a -> DW_FORM_block1
+ | 0x0b -> DW_FORM_data1
+ | 0x0c -> DW_FORM_flag
+ | 0x0d -> DW_FORM_sdata
+ | 0x0e -> DW_FORM_strp
+ | 0x0f -> DW_FORM_udata
+ | 0x10 -> DW_FORM_ref_addr
+ | 0x11 -> DW_FORM_ref1
+ | 0x12 -> DW_FORM_ref2
+ | 0x13 -> DW_FORM_ref4
+ | 0x14 -> DW_FORM_ref8
+ | 0x15 -> DW_FORM_ref_udata
+ | 0x16 -> DW_FORM_indirect
+ | _ -> bug () "bad DWARF form code: 0x%x" i
+;;
+
+let dw_form_to_string (f:dw_form) : string =
+ match f with
+ | DW_FORM_addr -> "DW_FORM_addr"
+ | DW_FORM_block2 -> "DW_FORM_block2"
+ | DW_FORM_block4 -> "DW_FORM_block4"
+ | DW_FORM_data2 -> "DW_FORM_data2"
+ | DW_FORM_data4 -> "DW_FORM_data4"
+ | DW_FORM_data8 -> "DW_FORM_data8"
+ | DW_FORM_string -> "DW_FORM_string"
+ | DW_FORM_block -> "DW_FORM_block"
+ | DW_FORM_block1 -> "DW_FORM_block1"
+ | DW_FORM_data1 -> "DW_FORM_data1"
+ | DW_FORM_flag -> "DW_FORM_flag"
+ | DW_FORM_sdata -> "DW_FORM_sdata"
+ | DW_FORM_strp -> "DW_FORM_strp"
+ | DW_FORM_udata -> "DW_FORM_udata"
+ | DW_FORM_ref_addr -> "DW_FORM_ref_addr"
+ | DW_FORM_ref1 -> "DW_FORM_ref1"
+ | DW_FORM_ref2 -> "DW_FORM_ref2"
+ | DW_FORM_ref4 -> "DW_FORM_ref4"
+ | DW_FORM_ref8 -> "DW_FORM_ref8"
+ | DW_FORM_ref_udata -> "DW_FORM_ref_udata"
+ | DW_FORM_indirect -> "DW_FORM_indirect"
+;;
+
+type dw_op =
+ DW_OP_lit of int
+ | DW_OP_addr of Asm.expr64
+ | DW_OP_const1u of Asm.expr64
+ | DW_OP_const1s of Asm.expr64
+ | DW_OP_const2u of Asm.expr64
+ | DW_OP_const2s of Asm.expr64
+ | DW_OP_const4u of Asm.expr64
+ | DW_OP_const4s of Asm.expr64
+ | DW_OP_const8u of Asm.expr64
+ | DW_OP_const8s of Asm.expr64
+ | DW_OP_constu of Asm.expr64
+ | DW_OP_consts of Asm.expr64
+ | DW_OP_fbreg of Asm.expr64
+ | DW_OP_reg of int
+ | DW_OP_regx of Asm.expr64
+ | DW_OP_breg of (int * Asm.expr64)
+ | DW_OP_bregx of (Asm.expr64 * Asm.expr64)
+ | DW_OP_dup
+ | DW_OP_drop
+ | DW_OP_pick of Asm.expr64
+ | DW_OP_over
+ | DW_OP_swap
+ | DW_OP_rot
+ | DW_OP_piece of Asm.expr64
+ | DW_OP_bit_piece of (Asm.expr64 * Asm.expr64)
+ | DW_OP_deref
+ | DW_OP_deref_size of Asm.expr64
+ | DW_OP_xderef
+ | DW_OP_xderef_size of Asm.expr64
+ | DW_OP_push_object_address
+ | DW_OP_form_tls_address
+ | DW_OP_call_frame_cfa
+ | DW_OP_abs
+ | DW_OP_and
+ | DW_OP_div
+ | DW_OP_minus
+ | DW_OP_mod
+ | DW_OP_mul
+ | DW_OP_neg
+ | DW_OP_not
+ | DW_OP_or
+ | DW_OP_plus
+ | DW_OP_plus_uconst of Asm.expr64
+ | DW_OP_shl
+ | DW_OP_shr
+ | DW_OP_shra
+ | DW_OP_xor
+ | DW_OP_le
+ | DW_OP_ge
+ | DW_OP_eq
+ | DW_OP_lt
+ | DW_OP_gt
+ | DW_OP_ne
+ | DW_OP_skip of Asm.expr64
+ | DW_OP_bra of Asm.expr64
+ | DW_OP_call2 of Asm.expr64
+ | DW_OP_call4 of Asm.expr64
+ | DW_OP_call_ref of Asm.expr64
+ | DW_OP_nop
+;;
+
+let dw_op_to_frag (abi:Abi.abi) (op:dw_op) : Asm.frag =
+ match op with
+
+ DW_OP_addr e -> SEQ [| BYTE 0x03; WORD (abi.Abi.abi_word_ty, e) |]
+ | DW_OP_deref -> BYTE 0x06
+ | DW_OP_const1u e -> SEQ [| BYTE 0x08; WORD (TY_u8, e) |]
+ | DW_OP_const1s e -> SEQ [| BYTE 0x09; WORD (TY_i8, e) |]
+ | DW_OP_const2u e -> SEQ [| BYTE 0x0a; WORD (TY_u16, e) |]
+ | DW_OP_const2s e -> SEQ [| BYTE 0x0b; WORD (TY_i16, e) |]
+ | DW_OP_const4u e -> SEQ [| BYTE 0x0c; WORD (TY_u32, e) |]
+ | DW_OP_const4s e -> SEQ [| BYTE 0x0d; WORD (TY_i32, e) |]
+ | DW_OP_const8u e -> SEQ [| BYTE 0x0e; WORD (TY_u64, e) |]
+ | DW_OP_const8s e -> SEQ [| BYTE 0x0f; WORD (TY_i64, e) |]
+ | DW_OP_constu e -> SEQ [| BYTE 0x10; ULEB128 e |]
+ | DW_OP_consts e -> SEQ [| BYTE 0x11; SLEB128 e |]
+ | DW_OP_dup -> BYTE 0x12
+ | DW_OP_drop -> BYTE 0x13
+ | DW_OP_over -> BYTE 0x14
+ | DW_OP_pick e -> SEQ [| BYTE 0x15; WORD (TY_u8, e) |]
+ | DW_OP_swap -> BYTE 0x16
+ | DW_OP_rot -> BYTE 0x17
+ | DW_OP_xderef -> BYTE 0x18
+ | DW_OP_abs -> BYTE 0x19
+ | DW_OP_and -> BYTE 0x1a
+ | DW_OP_div -> BYTE 0x1b
+ | DW_OP_minus -> BYTE 0x1c
+ | DW_OP_mod -> BYTE 0x1d
+ | DW_OP_mul -> BYTE 0x1e
+ | DW_OP_neg -> BYTE 0x1f
+ | DW_OP_not -> BYTE 0x20
+ | DW_OP_or -> BYTE 0x21
+ | DW_OP_plus -> BYTE 0x22
+ | DW_OP_plus_uconst e -> SEQ [| BYTE 0x23; ULEB128 e |]
+ | DW_OP_shl -> BYTE 0x24
+ | DW_OP_shr -> BYTE 0x25
+ | DW_OP_shra -> BYTE 0x26
+ | DW_OP_xor -> BYTE 0x27
+ | DW_OP_skip e -> SEQ [| BYTE 0x2f; WORD (TY_i16, e) |]
+ | DW_OP_bra e -> SEQ [| BYTE 0x28; WORD (TY_i16, e) |]
+ | DW_OP_eq -> BYTE 0x29
+ | DW_OP_ge -> BYTE 0x2a
+ | DW_OP_gt -> BYTE 0x2b
+ | DW_OP_le -> BYTE 0x2c
+ | DW_OP_lt -> BYTE 0x2d
+ | DW_OP_ne -> BYTE 0x2e
+
+ | DW_OP_lit i ->
+ assert (0 <= i && i < 32);
+ BYTE (i + 0x30)
+
+ | DW_OP_reg i ->
+ assert (0 <= i && i < 32);
+ BYTE (i + 0x50)
+
+ | DW_OP_breg (i, e) ->
+ assert (0 <= i && i < 32);
+ SEQ [| BYTE (i + 0x70); SLEB128 e |]
+
+ | DW_OP_regx e -> SEQ [| BYTE 0x90; ULEB128 e|]
+ | DW_OP_fbreg e -> SEQ [| BYTE 0x91; SLEB128 e |]
+ | DW_OP_bregx (r, off) -> SEQ [| BYTE 0x92; ULEB128 r; SLEB128 off |]
+ | DW_OP_piece e -> SEQ [| BYTE 0x93; ULEB128 e |]
+ | DW_OP_deref_size e -> SEQ [| BYTE 0x94; WORD (TY_u8, e) |]
+ | DW_OP_xderef_size e -> SEQ [| BYTE 0x95; WORD (TY_u8, e) |]
+ | DW_OP_nop -> BYTE 0x96
+ | DW_OP_push_object_address -> BYTE 0x97
+ | DW_OP_call2 e -> SEQ [| BYTE 0x98; WORD (TY_u16, e) |]
+ | DW_OP_call4 e -> SEQ [| BYTE 0x99; WORD (TY_u32, e) |]
+ | DW_OP_call_ref e -> SEQ [| BYTE 0x9a; WORD (abi.Abi.abi_word_ty, e) |]
+ | DW_OP_form_tls_address -> BYTE 0x9b
+ | DW_OP_call_frame_cfa -> BYTE 0x9c
+ | DW_OP_bit_piece (sz, off) ->
+ SEQ [| BYTE 0x9d; ULEB128 sz; ULEB128 off |]
+;;
+
+type dw_lns =
+ DW_LNS_copy
+ | DW_LNS_advance_pc
+ | DW_LNS_advance_line
+ | DW_LNS_set_file
+ | DW_LNS_set_column
+ | DW_LNS_negage_stmt
+ | DW_LNS_set_basic_block
+ | DW_LNS_const_add_pc
+ | DW_LNS_fixed_advance_pc
+ | DW_LNS_set_prologue_end
+ | DW_LNS_set_epilogue_begin
+ | DW_LNS_set_isa
+;;
+
+let int_to_dw_lns i =
+ match i with
+ 1 -> DW_LNS_copy
+ | 2 -> DW_LNS_advance_pc
+ | 3 -> DW_LNS_advance_line
+ | 4 -> DW_LNS_set_file
+ | 5 -> DW_LNS_set_column
+ | 6 -> DW_LNS_negage_stmt
+ | 7 -> DW_LNS_set_basic_block
+ | 8 -> DW_LNS_const_add_pc
+ | 9 -> DW_LNS_fixed_advance_pc
+ | 10 -> DW_LNS_set_prologue_end
+ | 11 -> DW_LNS_set_epilogue_begin
+ | 12 -> DW_LNS_set_isa
+ | _ -> bug () "Internal logic error: (Dwarf.int_to_dw_lns %d)" i
+;;
+
+let dw_lns_to_int lns =
+ match lns with
+ DW_LNS_copy -> 1
+ | DW_LNS_advance_pc -> 2
+ | DW_LNS_advance_line -> 3
+ | DW_LNS_set_file -> 4
+ | DW_LNS_set_column -> 5
+ | DW_LNS_negage_stmt -> 6
+ | DW_LNS_set_basic_block -> 7
+ | DW_LNS_const_add_pc -> 8
+ | DW_LNS_fixed_advance_pc -> 9
+ | DW_LNS_set_prologue_end -> 10
+ | DW_LNS_set_epilogue_begin -> 11
+ | DW_LNS_set_isa -> 12
+;;
+
+let max_dw_lns = 12;;
+
+let dw_lns_arity lns =
+ match lns with
+ DW_LNS_copy -> 0
+ | DW_LNS_advance_pc -> 1
+ | DW_LNS_advance_line -> 1
+ | DW_LNS_set_file -> 1
+ | DW_LNS_set_column -> 1
+ | DW_LNS_negage_stmt -> 0
+ | DW_LNS_set_basic_block -> 0
+ | DW_LNS_const_add_pc -> 0
+ | DW_LNS_fixed_advance_pc -> 1
+ | DW_LNS_set_prologue_end -> 0
+ | DW_LNS_set_epilogue_begin -> 0
+ | DW_LNS_set_isa -> 1
+;;
+
+type debug_records =
+ {
+ debug_aranges: Asm.frag;
+ debug_pubnames: Asm.frag;
+ debug_info: Asm.frag;
+ debug_abbrev: Asm.frag;
+ debug_line: Asm.frag;
+ debug_frame: Asm.frag;
+ }
+
+type abbrev = (dw_tag * dw_children * ((dw_at * dw_form) array));;
+
+let (abbrev_crate_cu:abbrev) =
+ (DW_TAG_compile_unit, DW_CHILDREN_yes,
+ [|
+ (DW_AT_producer, DW_FORM_string);
+ (DW_AT_language, DW_FORM_data4);
+ (DW_AT_name, DW_FORM_string);
+ (DW_AT_comp_dir, DW_FORM_string);
+ (DW_AT_low_pc, DW_FORM_addr);
+ (DW_AT_high_pc, DW_FORM_addr);
+ (DW_AT_use_UTF8, DW_FORM_flag)
+ |])
+ ;;
+
+let (abbrev_meta:abbrev) =
+ (DW_TAG_rust_meta, DW_CHILDREN_no,
+ [|
+ (DW_AT_name, DW_FORM_string);
+ (DW_AT_const_value, DW_FORM_string)
+ |])
+;;
+
+let (abbrev_srcfile_cu:abbrev) =
+ (DW_TAG_compile_unit, DW_CHILDREN_yes,
+ [|
+ (DW_AT_name, DW_FORM_string);
+ (DW_AT_comp_dir, DW_FORM_string);
+ (DW_AT_low_pc, DW_FORM_addr);
+ (DW_AT_high_pc, DW_FORM_addr);
+ |])
+;;
+
+
+let (abbrev_module:abbrev) =
+ (DW_TAG_module, DW_CHILDREN_yes,
+ [|
+ (DW_AT_name, DW_FORM_string);
+ |])
+;;
+
+let (abbrev_subprogram:abbrev) =
+ (DW_TAG_subprogram, DW_CHILDREN_yes,
+ [|
+ (DW_AT_name, DW_FORM_string);
+ (DW_AT_type, DW_FORM_ref_addr);
+ (DW_AT_low_pc, DW_FORM_addr);
+ (DW_AT_high_pc, DW_FORM_addr);
+ (DW_AT_frame_base, DW_FORM_block1);
+ (DW_AT_return_addr, DW_FORM_block1);
+ (DW_AT_mutable, DW_FORM_flag);
+ (DW_AT_pure, DW_FORM_flag);
+ |])
+;;
+
+let (abbrev_typedef:abbrev) =
+ (DW_TAG_typedef, DW_CHILDREN_yes,
+ [|
+ (DW_AT_name, DW_FORM_string);
+ (DW_AT_type, DW_FORM_ref_addr)
+ |])
+;;
+
+let (abbrev_lexical_block:abbrev) =
+ (DW_TAG_lexical_block, DW_CHILDREN_yes,
+ [|
+ (DW_AT_low_pc, DW_FORM_addr);
+ (DW_AT_high_pc, DW_FORM_addr);
+ |])
+;;
+
+let (abbrev_variable:abbrev) =
+ (DW_TAG_variable, DW_CHILDREN_no,
+ [|
+ (DW_AT_name, DW_FORM_string);
+ (DW_AT_location, DW_FORM_block1);
+ (DW_AT_type, DW_FORM_ref_addr)
+ |])
+;;
+
+(* NB: must have same abbrev-body as abbrev_variable. *)
+let (abbrev_formal:abbrev) =
+ (DW_TAG_formal_parameter, DW_CHILDREN_no,
+ [|
+ (DW_AT_name, DW_FORM_string);
+ (DW_AT_location, DW_FORM_block1);
+ (DW_AT_type, DW_FORM_ref_addr)
+ |])
+;;
+
+let (abbrev_unspecified_anon_structure_type:abbrev) =
+ (DW_TAG_structure_type, DW_CHILDREN_no,
+ [|
+ (DW_AT_declaration, DW_FORM_flag);
+ |])
+;;
+
+let (abbrev_unspecified_structure_type:abbrev) =
+ (DW_TAG_structure_type, DW_CHILDREN_no,
+ [|
+ (DW_AT_rust_type_code, DW_FORM_data1);
+ (DW_AT_declaration, DW_FORM_flag);
+ |])
+;;
+
+let (abbrev_unspecified_pointer_type:abbrev) =
+ (DW_TAG_pointer_type, DW_CHILDREN_no,
+ [|
+ (DW_AT_rust_type_code, DW_FORM_data1);
+ (DW_AT_declaration, DW_FORM_flag);
+ (DW_AT_type, DW_FORM_ref_addr)
+ |])
+;;
+
+let (abbrev_native_pointer_type:abbrev) =
+ (DW_TAG_pointer_type, DW_CHILDREN_no,
+ [|
+ (DW_AT_rust_type_code, DW_FORM_data1);
+ (DW_AT_rust_native_type_id, DW_FORM_data4)
+ |])
+;;
+
+let (abbrev_rust_type_param:abbrev) =
+ (DW_TAG_pointer_type, DW_CHILDREN_no,
+ [|
+ (DW_AT_rust_type_code, DW_FORM_data1);
+ (DW_AT_rust_type_param_index, DW_FORM_data4);
+ (DW_AT_mutable, DW_FORM_flag);
+ (DW_AT_pure, DW_FORM_flag);
+ |])
+;;
+
+let (abbrev_rust_type_param_decl:abbrev) =
+ (DW_TAG_formal_parameter, DW_CHILDREN_no,
+ [|
+ (DW_AT_rust_type_code, DW_FORM_data1);
+ (DW_AT_name, DW_FORM_string);
+ (DW_AT_rust_type_param_index, DW_FORM_data4);
+ (DW_AT_mutable, DW_FORM_flag);
+ (DW_AT_pure, DW_FORM_flag);
+ |])
+;;
+
+let (abbrev_base_type:abbrev) =
+ (DW_TAG_base_type, DW_CHILDREN_no,
+ [|
+ (DW_AT_name, DW_FORM_string);
+ (DW_AT_encoding, DW_FORM_data1);
+ (DW_AT_byte_size, DW_FORM_data1)
+ |])
+;;
+
+let (abbrev_alias_slot:abbrev) =
+ (DW_TAG_reference_type, DW_CHILDREN_no,
+ [|
+ (DW_AT_type, DW_FORM_ref_addr);
+ (DW_AT_mutable, DW_FORM_flag);
+ |])
+;;
+
+let (abbrev_exterior_slot:abbrev) =
+ (DW_TAG_reference_type, DW_CHILDREN_no,
+ [|
+ (DW_AT_type, DW_FORM_ref_addr);
+ (DW_AT_mutable, DW_FORM_flag);
+ (DW_AT_data_location, DW_FORM_block1);
+ |])
+;;
+
+let (abbrev_struct_type:abbrev) =
+ (DW_TAG_structure_type, DW_CHILDREN_yes,
+ [|
+ (DW_AT_byte_size, DW_FORM_block4)
+ |])
+;;
+
+let (abbrev_struct_type_member:abbrev) =
+ (DW_TAG_member, DW_CHILDREN_no,
+ [|
+ (DW_AT_name, DW_FORM_string);
+ (DW_AT_type, DW_FORM_ref_addr);
+ (DW_AT_mutable, DW_FORM_flag);
+ (DW_AT_data_member_location, DW_FORM_block4);
+ (DW_AT_byte_size, DW_FORM_block4)
+ |])
+;;
+
+let (abbrev_subroutine_type:abbrev) =
+ (DW_TAG_subroutine_type, DW_CHILDREN_yes,
+ [|
+ (* FIXME: model effects properly. *)
+ (DW_AT_type, DW_FORM_ref_addr); (* NB: output type. *)
+ (DW_AT_mutable, DW_FORM_flag);
+ (DW_AT_pure, DW_FORM_flag);
+ (DW_AT_rust_iterator, DW_FORM_flag);
+ |])
+;;
+
+let (abbrev_formal_type:abbrev) =
+ (DW_TAG_formal_parameter, DW_CHILDREN_no,
+ [|
+ (DW_AT_type, DW_FORM_ref_addr)
+ |])
+;;
+
+
+let (abbrev_obj_subroutine_type:abbrev) =
+ (DW_TAG_subroutine_type, DW_CHILDREN_yes,
+ [|
+ (* FIXME: model effects properly. *)
+ (DW_AT_name, DW_FORM_string);
+ (DW_AT_type, DW_FORM_ref_addr); (* NB: output type. *)
+ (DW_AT_mutable, DW_FORM_flag);
+ (DW_AT_pure, DW_FORM_flag);
+ (DW_AT_rust_iterator, DW_FORM_flag);
+ |])
+;;
+
+let (abbrev_obj_type:abbrev) =
+ (DW_TAG_interface_type, DW_CHILDREN_yes,
+ [|
+ (DW_AT_mutable, DW_FORM_flag);
+ (DW_AT_pure, DW_FORM_flag);
+ |])
+;;
+
+let (abbrev_string_type:abbrev) =
+ (DW_TAG_string_type, DW_CHILDREN_no,
+ [|
+ (DW_AT_string_length, DW_FORM_block1);
+ (DW_AT_data_location, DW_FORM_block1);
+ |])
+;;
+
+
+let prepend lref x = lref := x :: (!lref)
+;;
+
+
+let dwarf_visitor
+ (cx:ctxt)
+ (inner:Walk.visitor)
+ (path:Ast.name_component Stack.t)
+ (cu_info_section_fixup:fixup)
+ (cu_aranges:(frag list) ref)
+ (cu_pubnames:(frag list) ref)
+ (cu_infos:(frag list) ref)
+ (cu_abbrevs:(frag list) ref)
+ (cu_lines:(frag list) ref)
+ (cu_frames:(frag list) ref)
+ : Walk.visitor =
+
+ let (abi:Abi.abi) = cx.ctxt_abi in
+ let (word_sz:int64) = abi.Abi.abi_word_sz in
+ let (word_sz_int:int) = Int64.to_int word_sz in
+ let (word_bits:Il.bits) = abi.Abi.abi_word_bits in
+ let (word_ty_mach:ty_mach) =
+ match word_bits with
+ Il.Bits8 -> TY_u8
+ | Il.Bits16 -> TY_u16
+ | Il.Bits32 -> TY_u32
+ | Il.Bits64 -> TY_u64
+ in
+ let (signed_word_ty_mach:ty_mach) =
+ match word_bits with
+ Il.Bits8 -> TY_i8
+ | Il.Bits16 -> TY_i16
+ | Il.Bits32 -> TY_i32
+ | Il.Bits64 -> TY_i64
+ in
+
+ let path_name _ = Ast.fmt_to_str Ast.fmt_name (Walk.path_to_name path) in
+
+ let (abbrev_table:(abbrev, int) Hashtbl.t) = Hashtbl.create 0 in
+
+ let uleb i = ULEB128 (IMM (Int64.of_int i)) in
+
+ let get_abbrev_code
+ (ab:abbrev)
+ : int =
+ if Hashtbl.mem abbrev_table ab
+ then Hashtbl.find abbrev_table ab
+ else
+ let n = (Hashtbl.length abbrev_table) + 1 in
+ let (tag, children, attrs) = ab in
+ let attr_ulebs = Array.create ((Array.length attrs) * 2) MARK in
+ for i = 0 to (Array.length attrs) - 1 do
+ let (attr, form) = attrs.(i) in
+ attr_ulebs.(2*i) <- uleb (dw_at_to_int attr);
+ attr_ulebs.((2*i)+1) <- uleb (dw_form_to_int form)
+ done;
+ let ab_frag =
+ (SEQ [|
+ uleb n;
+ uleb (dw_tag_to_int tag);
+ BYTE (dw_children_to_int children);
+ SEQ attr_ulebs;
+ uleb 0; uleb 0;
+ |])
+ in
+ prepend cu_abbrevs ab_frag;
+ htab_put abbrev_table ab n;
+ n
+ in
+
+ let (curr_cu_aranges:(frag list) ref) = ref [] in
+ let (curr_cu_pubnames:(frag list) ref) = ref [] in
+ let (curr_cu_infos:(frag list) ref) = ref [] in
+ let (curr_cu_line:(frag list) ref) = ref [] in
+ let (curr_cu_frame:(frag list) ref) = ref [] in
+
+ let emit_die die = prepend curr_cu_infos die in
+ let emit_null_die _ = emit_die (BYTE 0) in
+
+ let dw_form_block1 (ops:dw_op array) : Asm.frag =
+ let frag = SEQ (Array.map (dw_op_to_frag abi) ops) in
+ let block_fixup = new_fixup "DW_FORM_block1 fixup" in
+ SEQ [| WORD (TY_u8, F_SZ block_fixup);
+ DEF (block_fixup, frag) |]
+ in
+
+ let dw_form_ref_addr (fix:fixup) : Asm.frag =
+ WORD (signed_word_ty_mach,
+ SUB ((M_POS fix), M_POS cu_info_section_fixup))
+ in
+
+ let encode_effect eff =
+ (* Note: weird encoding: mutable+pure = unsafe. *)
+ let mut_byte, pure_byte =
+ match eff with
+ Ast.UNSAFE -> (1,1)
+ | Ast.STATE -> (1,0)
+ | Ast.IO -> (0,0)
+ | Ast.PURE -> (0,1)
+ in
+ SEQ [|
+ (* DW_AT_mutable: DW_FORM_flag *)
+ BYTE mut_byte;
+ (* DW_AT_pure: DW_FORM_flag *)
+ BYTE pure_byte;
+ |]
+ in
+
+ (* Type-param DIEs. *)
+
+ let type_param_die (p:(ty_param_idx * Ast.effect)) =
+ let (idx, eff) = p in
+ SEQ [|
+ uleb (get_abbrev_code abbrev_rust_type_param);
+ (* DW_AT_rust_type_code: DW_FORM_data1 *)
+ BYTE (dw_rust_type_to_int DW_RUST_type_param);
+ (* DW_AT_rust_type_param_index: DW_FORM_data4 *)
+ WORD (word_ty_mach, IMM (Int64.of_int idx));
+ encode_effect eff;
+ |]
+ in
+
+ (* Type DIEs. *)
+
+ let (emitted_types:(Ast.ty, Asm.frag) Hashtbl.t) = Hashtbl.create 0 in
+ let (emitted_slots:(Ast.slot, Asm.frag) Hashtbl.t) = Hashtbl.create 0 in
+
+ let rec ref_slot_die
+ (slot:Ast.slot)
+ : frag =
+ if Hashtbl.mem emitted_slots slot
+ then Hashtbl.find emitted_slots slot
+ else
+ let ref_addr_for_fix fix =
+ let res = dw_form_ref_addr fix in
+ Hashtbl.add emitted_slots slot res;
+ res
+ in
+
+ match slot.Ast.slot_mode with
+ Ast.MODE_exterior ->
+ let fix = new_fixup "exterior DIE" in
+ let body_off =
+ word_sz_int * Abi.exterior_rc_slot_field_body
+ in
+ emit_die (DEF (fix, SEQ [|
+ uleb (get_abbrev_code abbrev_exterior_slot);
+ (* DW_AT_type: DW_FORM_ref_addr *)
+ (ref_type_die (slot_ty slot));
+ (* DW_AT_mutable: DW_FORM_flag *)
+ BYTE (if slot.Ast.slot_mutable
+ then 1 else 0);
+ (* DW_AT_data_location: DW_FORM_block1 *)
+ (* This is a DWARF expression for moving
+ from the address of an exterior
+ allocation to the address of its
+ body. *)
+ dw_form_block1
+ [| DW_OP_push_object_address;
+ DW_OP_lit body_off;
+ DW_OP_plus;
+ DW_OP_deref |]
+ |]));
+ ref_addr_for_fix fix
+
+ (* FIXME: encode mutable-ness of interiors. *)
+ | Ast.MODE_interior -> ref_type_die (slot_ty slot)
+
+ | Ast.MODE_alias ->
+ let fix = new_fixup "alias DIE" in
+ emit_die (DEF (fix, SEQ [|
+ uleb (get_abbrev_code abbrev_alias_slot);
+ (* DW_AT_type: DW_FORM_ref_addr *)
+ (ref_type_die (slot_ty slot));
+ (* DW_AT_mutable: DW_FORM_flag *)
+ BYTE (if slot.Ast.slot_mutable then 1 else 0)
+ |]));
+ ref_addr_for_fix fix
+
+
+ and size_block4 (sz:size) (add_to_base:bool) : frag =
+ (* NB: typarams = "words following implicit args" by convention in
+ * ABI/x86.
+ *)
+ let abi = cx.ctxt_abi in
+ let typarams =
+ Int64.add abi.Abi.abi_frame_base_sz abi.Abi.abi_implicit_args_sz
+ in
+ let word_n n = Int64.mul abi.Abi.abi_word_sz (Int64.of_int n) in
+ let param_n n = Int64.add typarams (word_n n) in
+ let param_n_field_k n k =
+ [ DW_OP_fbreg (IMM (param_n n));
+ DW_OP_deref;
+ DW_OP_constu (IMM (word_n k));
+ DW_OP_plus;
+ DW_OP_deref ]
+ in
+ let rec sz_ops (sz:size) : dw_op list =
+ match sz with
+ SIZE_fixed i ->
+ [ DW_OP_constu (IMM i) ]
+
+ | SIZE_fixup_mem_sz fix ->
+ [ DW_OP_constu (M_SZ fix) ]
+
+ | SIZE_fixup_mem_pos fix ->
+ [ DW_OP_constu (M_POS fix) ]
+
+ | SIZE_param_size i ->
+ param_n_field_k i Abi.tydesc_field_size
+
+ | SIZE_param_align i ->
+ param_n_field_k i Abi.tydesc_field_align
+
+ | SIZE_rt_neg s ->
+ (sz_ops s) @ [ DW_OP_neg ]
+
+ | SIZE_rt_add (a, b) ->
+ (sz_ops a) @ (sz_ops b) @ [ DW_OP_plus ]
+
+ | SIZE_rt_mul (a, b) ->
+ (sz_ops a) @ (sz_ops b) @ [ DW_OP_mul ]
+
+ | SIZE_rt_max (a, b) ->
+ (sz_ops a) @ (sz_ops b) @
+ [ DW_OP_over; (* ... a b a *)
+ DW_OP_over; (* ... a b a b *)
+ DW_OP_ge; (* ... a b (a>=b?1:0) *)
+
+ (* jump +1 byte of dwarf ops if 1 *)
+ DW_OP_bra (IMM 1L);
+
+ (* do this if 0, when b is max. *)
+ DW_OP_swap; (* ... b a *)
+
+ (* jump to here when a is max. *)
+ DW_OP_drop; (* ... max *)
+ ]
+
+ | SIZE_rt_align (align, off) ->
+ (*
+ * calculate off + pad where:
+ *
+ * pad = (align - (off mod align)) mod align
+ *
+ * In our case it's always a power of two,
+ * so we can just do:
+ *
+ * mask = align-1
+ * off += mask
+ * off &= ~mask
+ *
+ *)
+ (sz_ops off) @ (sz_ops align) @
+ [
+ DW_OP_lit 1; (* ... off align 1 *)
+ DW_OP_minus; (* ... off mask *)
+ DW_OP_dup; (* ... off mask mask *)
+ DW_OP_not; (* ... off mask ~mask *)
+ DW_OP_rot; (* ... ~mask off mask *)
+ DW_OP_plus; (* ... ~mask (off+mask) *)
+ DW_OP_and; (* ... aligned *)
+ ]
+ in
+ let ops = sz_ops sz in
+ let ops =
+ if add_to_base
+ then ops @ [ DW_OP_plus ]
+ else ops
+ in
+ let frag = SEQ (Array.map (dw_op_to_frag abi) (Array.of_list ops)) in
+ let block_fixup = new_fixup "DW_FORM_block4 fixup" in
+ SEQ [| WORD (TY_u32, F_SZ block_fixup);
+ DEF (block_fixup, frag) |]
+
+
+ and ref_type_die
+ (ty:Ast.ty)
+ : frag =
+ (* Returns a DW_FORM_ref_addr to the type. *)
+ if Hashtbl.mem emitted_types ty
+ then Hashtbl.find emitted_types ty
+ else
+ let ref_addr_for_fix fix =
+ let res = dw_form_ref_addr fix in
+ Hashtbl.add emitted_types ty res;
+ res
+ in
+
+ let record trec =
+ let rty = referent_type abi (Ast.TY_rec trec) in
+ let rty_sz = Il.referent_ty_size abi.Abi.abi_word_bits in
+ let fix = new_fixup "record type DIE" in
+ let die = DEF (fix, SEQ [|
+ uleb (get_abbrev_code abbrev_struct_type);
+ (* DW_AT_byte_size: DW_FORM_block4 *)
+ size_block4 (rty_sz rty) false
+ |]);
+ in
+ let rtys =
+ match rty with
+ Il.StructTy rtys -> rtys
+ | _ -> bug () "record type became non-struct referent_ty"
+ in
+ emit_die die;
+ Array.iteri
+ begin
+ fun i (ident, slot) ->
+ emit_die (SEQ [|
+ uleb (get_abbrev_code abbrev_struct_type_member);
+ (* DW_AT_name: DW_FORM_string *)
+ ZSTRING ident;
+ (* DW_AT_type: DW_FORM_ref_addr *)
+ (ref_slot_die slot);
+ (* DW_AT_mutable: DW_FORM_flag *)
+ BYTE (if slot.Ast.slot_mutable then 1 else 0);
+ (* DW_AT_data_member_location: DW_FORM_block4 *)
+ size_block4
+ (Il.get_element_offset word_bits rtys i)
+ true;
+ (* DW_AT_byte_size: DW_FORM_block4 *)
+ size_block4 (rty_sz rtys.(i)) false |]);
+ end
+ trec;
+ emit_null_die ();
+ ref_addr_for_fix fix
+ in
+
+ let string_type _ =
+ (*
+ * Strings, like vecs, are &[rc,alloc,fill,data...]
+ *)
+ let fix = new_fixup "string type DIE" in
+ let die =
+ DEF (fix, SEQ [|
+ uleb (get_abbrev_code abbrev_string_type);
+ (* (DW_AT_byte_size, DW_FORM_block1); *)
+ dw_form_block1 [| DW_OP_push_object_address;
+ DW_OP_deref;
+ DW_OP_lit (word_sz_int * 2);
+ DW_OP_plus; |];
+ (* (DW_AT_data_location, DW_FORM_block1); *)
+ dw_form_block1 [| DW_OP_push_object_address;
+ DW_OP_deref;
+ DW_OP_lit (word_sz_int * 3);
+ DW_OP_plus |]
+ |])
+ in
+ emit_die die;
+ ref_addr_for_fix fix
+ in
+
+ let base (name, encoding, byte_size) =
+ let fix = new_fixup ("base type DIE: " ^ name) in
+ let die =
+ DEF (fix, SEQ [|
+ uleb (get_abbrev_code abbrev_base_type);
+ (* DW_AT_name: DW_FORM_string *)
+ ZSTRING name;
+ (* DW_AT_encoding: DW_FORM_data1 *)
+ BYTE (dw_ate_to_int encoding);
+ (* DW_AT_byte_size: DW_FORM_data1 *)
+ BYTE byte_size
+ |])
+ in
+ emit_die die;
+ ref_addr_for_fix fix
+ in
+
+ let unspecified_anon_struct _ =
+ let fix = new_fixup "unspecified-anon-struct DIE" in
+ let die =
+ DEF (fix, SEQ [|
+ uleb (get_abbrev_code
+ abbrev_unspecified_anon_structure_type);
+ (* DW_AT_declaration: DW_FORM_flag *)
+ BYTE 1;
+ |])
+ in
+ emit_die die;
+ ref_addr_for_fix fix
+ in
+
+ let unspecified_struct rust_ty =
+ let fix = new_fixup "unspecified-struct DIE" in
+ let die =
+ DEF (fix, SEQ [|
+ uleb (get_abbrev_code abbrev_unspecified_structure_type);
+ (* DW_AT_rust_type_code: DW_FORM_data1 *)
+ BYTE (dw_rust_type_to_int rust_ty);
+ (* DW_AT_declaration: DW_FORM_flag *)
+ BYTE 1;
+ |])
+ in
+ emit_die die;
+ ref_addr_for_fix fix
+ in
+
+ let rust_type_param (p:(ty_param_idx * Ast.effect)) =
+ let fix = new_fixup "rust-type-param DIE" in
+ let die = DEF (fix, type_param_die p) in
+ emit_die die;
+ ref_addr_for_fix fix
+ in
+
+ let unspecified_ptr_with_ref rust_ty ref_addr =
+ let fix = new_fixup ("unspecified-pointer-type-with-ref DIE") in
+ let die =
+ DEF (fix, SEQ [|
+ uleb (get_abbrev_code abbrev_unspecified_pointer_type);
+ (* DW_AT_rust_type_code: DW_FORM_data1 *)
+ BYTE (dw_rust_type_to_int rust_ty);
+ (* DW_AT_declaration: DW_FORM_flag *)
+ BYTE 1;
+ (* DW_AT_type: DW_FORM_ref_addr *)
+ ref_addr
+ |])
+ in
+ emit_die die;
+ ref_addr_for_fix fix
+ in
+
+ let formal_type slot =
+ let fix = new_fixup "formal type" in
+ let die =
+ DEF (fix, SEQ [|
+ uleb (get_abbrev_code abbrev_formal_type);
+ (* DW_AT_type: DW_FORM_ref_addr *)
+ (ref_slot_die slot);
+ |])
+ in
+ emit_die die;
+ ref_addr_for_fix fix
+ in
+
+ let fn_type tfn =
+ let (tsig, taux) = tfn in
+ let fix = new_fixup "fn type" in
+ let die =
+ DEF (fix, SEQ [|
+ uleb (get_abbrev_code abbrev_subroutine_type);
+ (* DW_AT_type: DW_FORM_ref_addr *)
+ (ref_slot_die tsig.Ast.sig_output_slot);
+ encode_effect taux.Ast.fn_effect;
+ (* DW_AT_rust_iterator: DW_FORM_flag *)
+ BYTE (if taux.Ast.fn_is_iter then 1 else 0)
+ |])
+ in
+ emit_die die;
+ Array.iter
+ (fun s -> ignore (formal_type s))
+ tsig.Ast.sig_input_slots;
+ emit_null_die ();
+ ref_addr_for_fix fix
+ in
+
+ let obj_fn_type ident tfn =
+ let (tsig, taux) = tfn in
+ let fix = new_fixup "fn type" in
+ let die =
+ DEF (fix, SEQ [|
+ uleb (get_abbrev_code abbrev_obj_subroutine_type);
+ (* DW_AT_name: DW_FORM_string *)
+ ZSTRING ident;
+ (* DW_AT_type: DW_FORM_ref_addr *)
+ (ref_slot_die tsig.Ast.sig_output_slot);
+ encode_effect taux.Ast.fn_effect;
+ (* DW_AT_rust_iterator: DW_FORM_flag *)
+ BYTE (if taux.Ast.fn_is_iter then 1 else 0)
+ |])
+ in
+ emit_die die;
+ Array.iter
+ (fun s -> ignore (formal_type s))
+ tsig.Ast.sig_input_slots;
+ emit_null_die ();
+ ref_addr_for_fix fix
+ in
+
+ let obj_type (eff,ob) =
+ let fix = new_fixup "object type" in
+ let die =
+ DEF (fix, SEQ [|
+ uleb (get_abbrev_code abbrev_obj_type);
+ encode_effect eff;
+ |])
+ in
+ emit_die die;
+ Hashtbl.iter (fun k v -> ignore (obj_fn_type k v)) ob;
+ emit_null_die ();
+ ref_addr_for_fix fix
+ in
+
+ let unspecified_ptr_with_ref_ty rust_ty ty =
+ unspecified_ptr_with_ref rust_ty (ref_type_die ty)
+ in
+
+ let unspecified_ptr_with_ref_slot rust_ty slot =
+ unspecified_ptr_with_ref rust_ty (ref_slot_die slot)
+ in
+
+ let unspecified_ptr rust_ty =
+ unspecified_ptr_with_ref rust_ty (unspecified_anon_struct ())
+ in
+
+ let native_ptr_type oid =
+ let fix = new_fixup "native type" in
+ let die =
+ DEF (fix, SEQ [|
+ uleb (get_abbrev_code abbrev_native_pointer_type);
+ (* DW_AT_rust_type_code: DW_FORM_data1 *)
+ BYTE (dw_rust_type_to_int DW_RUST_native);
+ (* DW_AT_rust_native_type_id: DW_FORM_data4 *)
+ WORD (word_ty_mach, IMM (Int64.of_int (int_of_opaque oid)));
+ |])
+ in
+ emit_die die;
+ ref_addr_for_fix fix
+ in
+
+ match ty with
+ Ast.TY_nil -> unspecified_struct DW_RUST_nil
+ | Ast.TY_bool -> base ("bool", DW_ATE_boolean, 1)
+ | Ast.TY_mach (TY_u8) -> base ("u8", DW_ATE_unsigned, 1)
+ | Ast.TY_mach (TY_u16) -> base ("u16", DW_ATE_unsigned, 2)
+ | Ast.TY_mach (TY_u32) -> base ("u32", DW_ATE_unsigned, 4)
+ | Ast.TY_mach (TY_u64) -> base ("u64", DW_ATE_unsigned, 8)
+ | Ast.TY_mach (TY_i8) -> base ("i8", DW_ATE_signed, 1)
+ | Ast.TY_mach (TY_i16) -> base ("i16", DW_ATE_signed, 2)
+ | Ast.TY_mach (TY_i32) -> base ("i32", DW_ATE_signed, 4)
+ | Ast.TY_mach (TY_i64) -> base ("i64", DW_ATE_signed, 8)
+ | Ast.TY_int -> base ("int", DW_ATE_signed, word_sz_int)
+ | Ast.TY_uint -> base ("uint", DW_ATE_unsigned, word_sz_int)
+ | Ast.TY_char -> base ("char", DW_ATE_unsigned_char, 4)
+ | Ast.TY_str -> string_type ()
+ | Ast.TY_rec trec -> record trec
+ | Ast.TY_tup ttup ->
+ record (Array.mapi (fun i s ->
+ ("_" ^ (string_of_int i), s))
+ ttup)
+
+ | Ast.TY_vec s -> unspecified_ptr_with_ref_slot DW_RUST_vec s
+ | Ast.TY_chan t -> unspecified_ptr_with_ref_ty DW_RUST_chan t
+ | Ast.TY_port t -> unspecified_ptr_with_ref_ty DW_RUST_port t
+ | Ast.TY_task -> unspecified_ptr DW_RUST_task
+ | Ast.TY_fn fn -> fn_type fn
+ | Ast.TY_tag _ -> unspecified_ptr DW_RUST_tag
+ | Ast.TY_iso _ -> unspecified_ptr DW_RUST_iso
+ | Ast.TY_type -> unspecified_ptr DW_RUST_type
+ | Ast.TY_native i -> native_ptr_type i
+ | Ast.TY_param p -> rust_type_param p
+ | Ast.TY_obj ob -> obj_type ob
+ | _ ->
+ bug () "unimplemented dwarf encoding for type %a"
+ Ast.sprintf_ty ty
+ in
+
+ let finish_crate_cu_and_compose_headers _ =
+
+ let pubnames_header_and_curr_pubnames =
+ SEQ [| (BYTE 0) |]
+ in
+
+ let aranges_header_and_curr_aranges =
+ SEQ [| (BYTE 0) |]
+ in
+
+ let cu_info_fixup = new_fixup "CU debug_info fixup" in
+ let info_header_fixup = new_fixup "CU debug_info header" in
+ let info_header_and_curr_infos =
+ SEQ
+ [|
+ WORD (TY_u32, (* unit_length: *)
+ (ADD
+ ((F_SZ cu_info_fixup), (* including this header,*)
+ (F_SZ info_header_fixup)))); (* excluding this word. *)
+ DEF (info_header_fixup,
+ (SEQ [|
+ WORD (TY_u16, IMM 2L); (* DWARF version *)
+ (* Since we share abbrevs across all CUs,
+ * offset is always 0.
+ *)
+ WORD (TY_u32, IMM 0L); (* CU-abbrev offset. *)
+ BYTE 4; (* Size of an address. *)
+ |]));
+ DEF (cu_info_fixup,
+ SEQ (Array.of_list (List.rev (!curr_cu_infos))));
+ |]
+ in
+
+ let cu_line_fixup = new_fixup "CU debug_line fixup" in
+ let cu_line_header_fixup = new_fixup "CU debug_line header" in
+ let line_header_fixup = new_fixup "CU debug_line header" in
+ let line_header_and_curr_line =
+ SEQ
+ [|
+ WORD
+ (TY_u32, (* unit_length: *)
+ (ADD
+ ((F_SZ cu_line_fixup), (* including this header,*)
+ (F_SZ cu_line_header_fixup)))); (* excluding this word. *)
+ DEF (cu_line_header_fixup,
+ (SEQ [|
+ WORD (TY_u16, IMM 2L); (* DWARF version. *)
+ WORD
+ (TY_u32,
+ (F_SZ line_header_fixup)); (* Another header-length.*)
+ DEF (line_header_fixup,
+ SEQ [|
+ BYTE 1; (* Minimum insn length. *)
+ BYTE 1; (* default_is_stmt *)
+ BYTE 0; (* line_base *)
+ BYTE 0; (* line_range *)
+ BYTE (max_dw_lns + 1); (* opcode_base *)
+ BYTES (* opcode arity array. *)
+ (Array.init max_dw_lns
+ (fun i ->
+ (dw_lns_arity
+ (int_to_dw_lns
+ (i+1)))));
+ (BYTE 0); (* List of include dirs. *)
+ (BYTE 0); (* List of file entries. *)
+ |])|]));
+ DEF (cu_line_fixup,
+ SEQ (Array.of_list (List.rev (!curr_cu_line))));
+ |]
+ in
+ let frame_header_and_curr_frame =
+ SEQ [| (BYTE 0) |]
+ in
+ let prepend_and_reset (curr_ref, accum_ref, header_and_curr) =
+ prepend accum_ref header_and_curr;
+ curr_ref := []
+ in
+ List.iter prepend_and_reset
+ [ (curr_cu_aranges, cu_aranges, aranges_header_and_curr_aranges);
+ (curr_cu_pubnames, cu_pubnames, pubnames_header_and_curr_pubnames);
+ (curr_cu_infos, cu_infos, info_header_and_curr_infos);
+ (curr_cu_line, cu_lines, line_header_and_curr_line);
+ (curr_cu_frame, cu_frames, frame_header_and_curr_frame) ]
+ in
+
+ let image_base_rel (fix:fixup) : expr64 =
+ SUB (M_POS (fix), M_POS (cx.ctxt_image_base_fixup))
+ in
+
+ let addr_ranges (fix:fixup) : frag =
+ let image_is_relocated =
+ match cx.ctxt_sess.Session.sess_targ with
+ Win32_x86_pe ->
+ cx.ctxt_sess.Session.sess_library_mode
+ | _ -> true
+ in
+ let lo =
+ if image_is_relocated
+ then image_base_rel fix
+ else M_POS fix
+ in
+ SEQ [|
+ (* DW_AT_low_pc, DW_FORM_addr *)
+ WORD (word_ty_mach, lo);
+ (* DW_AT_high_pc, DW_FORM_addr *)
+ WORD (word_ty_mach, ADD ((lo),
+ (M_SZ fix)))
+ |]
+ in
+
+ let emit_srcfile_cu_die
+ (name:string)
+ (cu_text_fixup:fixup)
+ : unit =
+ let abbrev_code = get_abbrev_code abbrev_srcfile_cu in
+ let srcfile_cu_die =
+ (SEQ [|
+ uleb abbrev_code;
+ (* DW_AT_name: DW_FORM_string *)
+ ZSTRING (Filename.basename name);
+ (* DW_AT_comp_dir: DW_FORM_string *)
+ ZSTRING (Filename.concat (Sys.getcwd()) (Filename.dirname name));
+ addr_ranges cu_text_fixup;
+ |])
+ in
+ emit_die srcfile_cu_die
+ in
+
+ let emit_meta_die
+ (meta:(Ast.ident * string))
+ : unit =
+ let abbrev_code = get_abbrev_code abbrev_meta in
+ let die =
+ SEQ [| uleb abbrev_code;
+ (* DW_AT_name: DW_FORM_string *)
+ ZSTRING (fst meta);
+ (* DW_AT_const_value: DW_FORM_string *)
+ ZSTRING (snd meta);
+ |]
+ in
+ emit_die die
+ in
+
+ let begin_crate_cu_and_emit_cu_die
+ (name:string)
+
+ (cu_text_fixup:fixup)
+ : unit =
+ let abbrev_code = get_abbrev_code abbrev_crate_cu in
+ let crate_cu_die =
+ (SEQ [|
+ uleb abbrev_code;
+ (* DW_AT_producer: DW_FORM_string *)
+ ZSTRING "Rustboot pre-release";
+ (* DW_AT_language: DW_FORM_data4 *)
+ WORD (word_ty_mach, IMM 0x2L); (* DW_LANG_C *)
+ (* DW_AT_name: DW_FORM_string *)
+ ZSTRING (Filename.basename name);
+ (* DW_AT_comp_dir: DW_FORM_string *)
+ ZSTRING (Filename.concat (Sys.getcwd()) (Filename.dirname name));
+ addr_ranges cu_text_fixup;
+ (* DW_AT_use_UTF8, DW_FORM_flag *)
+ BYTE 1
+ |])
+ in
+ curr_cu_infos := [crate_cu_die];
+ curr_cu_line := []
+ in
+
+ let type_param_decl_die (p:(Ast.ident * (ty_param_idx * Ast.effect))) =
+ let (ident, (idx, eff)) = p in
+ SEQ [|
+ uleb (get_abbrev_code abbrev_rust_type_param_decl);
+ (* DW_AT_rust_type_code: DW_FORM_data1 *)
+ BYTE (dw_rust_type_to_int DW_RUST_type_param);
+ (* DW_AT_name: DW_FORM_string *)
+ ZSTRING (Filename.basename ident);
+ (* DW_AT_rust_type_param_index: DW_FORM_data4 *)
+ WORD (word_ty_mach, IMM (Int64.of_int idx));
+ encode_effect eff;
+ |]
+ in
+
+ let emit_type_param_decl_dies
+ (params:(Ast.ty_param identified) array)
+ : unit =
+ Array.iter
+ (fun p ->
+ emit_die (type_param_decl_die p.node))
+ params;
+ in
+
+ let emit_module_die
+ (id:Ast.ident)
+ : unit =
+ let abbrev_code = get_abbrev_code abbrev_module in
+ let module_die =
+ (SEQ [|
+ uleb abbrev_code;
+ (* DW_AT_name *)
+ ZSTRING id;
+ |])
+ in
+ emit_die module_die;
+ in
+
+ let emit_subprogram_die
+ (id:Ast.ident)
+ (ret_slot:Ast.slot)
+ (effect:Ast.effect)
+ (fix:fixup)
+ : unit =
+ (* NB: retpc = "top word of frame-base" by convention in ABI/x86. *)
+ let abi = cx.ctxt_abi in
+ let retpc = Int64.sub abi.Abi.abi_frame_base_sz abi.Abi.abi_word_sz in
+ let abbrev_code = get_abbrev_code abbrev_subprogram in
+ let subprogram_die =
+ (SEQ [|
+ uleb abbrev_code;
+ (* DW_AT_name *)
+ ZSTRING id;
+ (* DW_AT_type: DW_FORM_ref_addr *)
+ ref_slot_die ret_slot;
+ addr_ranges fix;
+ (* DW_AT_frame_base *)
+ dw_form_block1 [| DW_OP_reg abi.Abi.abi_dwarf_fp_reg |];
+ (* DW_AT_return_addr *)
+ dw_form_block1 [| DW_OP_fbreg (Asm.IMM retpc); |];
+ encode_effect effect;
+ |])
+ in
+ emit_die subprogram_die
+ in
+
+ let emit_typedef_die
+ (id:Ast.ident)
+ (ty:Ast.ty)
+ : unit =
+ let abbrev_code = get_abbrev_code abbrev_typedef in
+ let typedef_die =
+ (SEQ [|
+ uleb abbrev_code;
+ (* DW_AT_name: DW_FORM_string *)
+ ZSTRING id;
+ (* DW_AT_type: DW_FORM_ref_addr *)
+ (ref_type_die ty);
+ |])
+ in
+ emit_die typedef_die
+ in
+
+ let visit_crate_pre
+ (crate:Ast.crate)
+ : unit =
+ let filename = (Hashtbl.find cx.ctxt_item_files crate.id) in
+ log cx "walking crate CU '%s'" filename;
+ begin_crate_cu_and_emit_cu_die filename
+ (Hashtbl.find cx.ctxt_file_fixups crate.id);
+ Array.iter emit_meta_die crate.node.Ast.crate_meta;
+ inner.Walk.visit_crate_pre crate
+ in
+
+ let visit_mod_item_pre
+ (id:Ast.ident)
+ (params:(Ast.ty_param identified) array)
+ (item:Ast.mod_item)
+ : unit =
+ if Hashtbl.mem cx.ctxt_item_files item.id
+ then
+ begin
+ let filename = (Hashtbl.find cx.ctxt_item_files item.id) in
+ log cx "walking srcfile CU '%s'" filename;
+ emit_srcfile_cu_die filename
+ (Hashtbl.find cx.ctxt_file_fixups item.id);
+ end
+ else
+ ();
+ begin
+ match item.node.Ast.decl_item with
+ Ast.MOD_ITEM_mod _ ->
+ begin
+ log cx "walking module '%s' with %d type params"
+ (path_name())
+ (Array.length item.node.Ast.decl_params);
+ emit_module_die id;
+ emit_type_param_decl_dies item.node.Ast.decl_params;
+ end
+ | Ast.MOD_ITEM_fn _ ->
+ begin
+ let ty = Hashtbl.find cx.ctxt_all_item_types item.id in
+ let (tsig,taux) =
+ match ty with
+ Ast.TY_fn tfn -> tfn
+ | _ ->
+ bug ()
+ "non-fn type when emitting dwarf for MOD_ITEM_fn"
+ in
+ log cx "walking function '%s' with %d type params"
+ (path_name())
+ (Array.length item.node.Ast.decl_params);
+ emit_subprogram_die
+ id tsig.Ast.sig_output_slot taux.Ast.fn_effect
+ (Hashtbl.find cx.ctxt_fn_fixups item.id);
+ emit_type_param_decl_dies item.node.Ast.decl_params;
+ end
+ | Ast.MOD_ITEM_type _ ->
+ begin
+ log cx "walking typedef '%s' with %d type params"
+ (path_name())
+ (Array.length item.node.Ast.decl_params);
+ emit_typedef_die
+ id (Hashtbl.find cx.ctxt_all_type_items item.id);
+ emit_type_param_decl_dies item.node.Ast.decl_params;
+ end
+ | _ -> ()
+ end;
+ inner.Walk.visit_mod_item_pre id params item
+ in
+
+ let visit_crate_post
+ (crate:Ast.crate)
+ : unit =
+ inner.Walk.visit_crate_post crate;
+ assert (Hashtbl.mem cx.ctxt_item_files crate.id);
+ emit_null_die();
+ log cx
+ "finishing crate CU and composing headers (%d DIEs collected)"
+ (List.length (!curr_cu_infos));
+ finish_crate_cu_and_compose_headers ()
+ in
+
+ let visit_mod_item_post
+ (id:Ast.ident)
+ (params:(Ast.ty_param identified) array)
+ (item:Ast.mod_item)
+ : unit =
+ inner.Walk.visit_mod_item_post id params item;
+ begin
+ match item.node.Ast.decl_item with
+ Ast.MOD_ITEM_mod _
+ | Ast.MOD_ITEM_fn _
+ | Ast.MOD_ITEM_type _ -> emit_null_die ()
+ | _ -> ()
+ end;
+ if Hashtbl.mem cx.ctxt_item_files item.id
+ then emit_null_die()
+ in
+
+ let visit_block_pre (b:Ast.block) : unit =
+ log cx "entering lexical block";
+ let fix = Hashtbl.find cx.ctxt_block_fixups b.id in
+ let abbrev_code = get_abbrev_code abbrev_lexical_block in
+ let block_die =
+ SEQ [|
+ uleb abbrev_code;
+ addr_ranges fix;
+ |]
+ in
+ emit_die block_die;
+ inner.Walk.visit_block_pre b
+ in
+
+ let visit_block_post (b:Ast.block) : unit =
+ inner.Walk.visit_block_post b;
+ log cx "leaving lexical block, terminating with NULL DIE";
+ emit_null_die ()
+ in
+
+ let visit_slot_identified_pre (s:Ast.slot identified) : unit =
+ begin
+ match htab_search cx.ctxt_slot_keys s.id with
+ None
+ | Some Ast.KEY_temp _ -> ()
+ | Some Ast.KEY_ident ident ->
+ begin
+ let abbrev_code =
+ if Hashtbl.mem cx.ctxt_slot_is_arg s.id
+ then get_abbrev_code abbrev_formal
+ else get_abbrev_code abbrev_variable
+ in
+ let resolved_slot = referent_to_slot cx s.id in
+ let emit_var_die slot_loc =
+ let var_die =
+ SEQ [|
+ uleb abbrev_code;
+ (* DW_AT_name: DW_FORM_string *)
+ ZSTRING ident;
+ (* DW_AT_location: DW_FORM_block1 *)
+ dw_form_block1 slot_loc;
+ (* DW_AT_type: DW_FORM_ref_addr *)
+ ref_slot_die resolved_slot
+ |]
+ in
+ emit_die var_die;
+ in
+ match htab_search cx.ctxt_slot_offsets s.id with
+ Some off ->
+ begin
+ match Il.size_to_expr64 off with
+ (* FIXME: handle dynamic-size slots. *)
+ None -> ()
+ | Some off ->
+ emit_var_die
+ [| DW_OP_fbreg off |]
+ end
+ | None ->
+ (* FIXME (issue #28): handle slots assigned to
+ * vregs.
+ *)
+ ()
+ end
+ end;
+ inner.Walk.visit_slot_identified_pre s
+ in
+
+ { inner with
+ Walk.visit_crate_pre = visit_crate_pre;
+ Walk.visit_crate_post = visit_crate_post;
+ Walk.visit_mod_item_pre = visit_mod_item_pre;
+ Walk.visit_mod_item_post = visit_mod_item_post;
+ Walk.visit_block_pre = visit_block_pre;
+ Walk.visit_block_post = visit_block_post;
+ Walk.visit_slot_identified_pre = visit_slot_identified_pre
+ }
+;;
+
+
+let process_crate
+ (cx:ctxt)
+ (crate:Ast.crate)
+ : debug_records =
+
+ let cu_aranges = ref [] in
+ let cu_pubnames = ref [] in
+ let cu_infos = ref [] in
+ let cu_abbrevs = ref [] in
+ let cu_lines = ref [] in
+ let cu_frames = ref [] in
+
+ let path = Stack.create () in
+
+ let passes =
+ [|
+ dwarf_visitor cx Walk.empty_visitor path
+ cx.ctxt_debug_info_fixup
+ cu_aranges cu_pubnames
+ cu_infos cu_abbrevs
+ cu_lines cu_frames
+ |];
+ in
+
+ log cx "emitting DWARF records";
+ run_passes cx "dwarf" path passes (log cx "%s") crate;
+
+ (* Terminate the tables. *)
+ {
+ debug_aranges = SEQ (Array.of_list (List.rev (!cu_aranges)));
+ debug_pubnames = SEQ (Array.of_list (List.rev (!cu_pubnames)));
+ debug_info = SEQ (Array.of_list (List.rev (!cu_infos)));
+ debug_abbrev = SEQ (Array.of_list (List.rev (!cu_abbrevs)));
+ debug_line = SEQ (Array.of_list (List.rev (!cu_lines)));
+ debug_frame = SEQ (Array.of_list (List.rev (!cu_frames)));
+ }
+;;
+
+(*
+ * Support for reconstituting a DWARF tree from a file, and various
+ * artifacts we can distill back from said DWARF.
+ *)
+
+let log sess = Session.log "dwarf"
+ sess.Session.sess_log_dwarf
+ sess.Session.sess_log_out
+;;
+
+
+let iflog (sess:Session.sess) (thunk:(unit -> unit)) : unit =
+ if sess.Session.sess_log_dwarf
+ then thunk ()
+ else ()
+;;
+
+let read_abbrevs
+ (sess:Session.sess)
+ (ar:asm_reader)
+ ((off:int),(sz:int))
+ : (int,abbrev) Hashtbl.t =
+ ar.asm_seek off;
+ let abs = Hashtbl.create 0 in
+ let rec read_abbrevs _ =
+ if ar.asm_get_off() >= (off + sz)
+ then abs
+ else
+ begin
+ let n = ar.asm_get_uleb() in
+ let tag = ar.asm_get_uleb() in
+ let has_children = ar.asm_get_u8() in
+ let pairs = ref [] in
+ let _ =
+ log sess "abbrev: %d, tag: %d, has_children: %d"
+ n tag has_children
+ in
+ let rec read_pairs _ =
+ let attr = ar.asm_get_uleb() in
+ let form = ar.asm_get_uleb() in
+ let _ = log sess "attr: %d, form: %d" attr form in
+ match (attr,form) with
+ (0,0) -> Array.of_list (List.rev (!pairs))
+ | _ ->
+ begin
+ pairs := (dw_at_of_int attr,
+ dw_form_of_int form) :: (!pairs);
+ read_pairs()
+ end
+ in
+ let pairs = read_pairs() in
+ Hashtbl.add abs n (dw_tag_of_int tag,
+ dw_children_of_int has_children,
+ pairs);
+ read_abbrevs()
+ end;
+ in
+ read_abbrevs()
+;;
+
+type data =
+ DATA_str of string
+ | DATA_num of int
+ | DATA_other
+;;
+
+type die =
+ { die_off: int;
+ die_tag: dw_tag;
+ die_attrs: (dw_at * (dw_form * data)) array;
+ die_children: die array; }
+;;
+
+type rooted_dies = (int * (int,die) Hashtbl.t)
+;;
+
+let fmt_dies
+ (ff:Format.formatter)
+ (dies:rooted_dies)
+ : unit =
+ let ((root:int),(dies:(int,die) Hashtbl.t)) = dies in
+ let rec fmt_die die =
+ Ast.fmt ff "@\nDIE <0x%x> %s" die.die_off (dw_tag_to_string die.die_tag);
+ Array.iter
+ begin
+ fun (at,(form,data)) ->
+ Ast.fmt ff "@\n %s = " (dw_at_to_string at);
+ begin
+ match data with
+ DATA_num n -> Ast.fmt ff "0x%x" n
+ | DATA_str s -> Ast.fmt ff "\"%s\"" s
+ | DATA_other -> Ast.fmt ff "<other>"
+ end;
+ Ast.fmt ff " (%s)" (dw_form_to_string form)
+ end
+ die.die_attrs;
+ if (Array.length die.die_children) != 0
+ then
+ begin
+ Ast.fmt ff "@\n";
+ Ast.fmt_obox ff;
+ Ast.fmt ff " children: ";
+ Ast.fmt_obr ff;
+ Array.iter fmt_die die.die_children;
+ Ast.fmt_cbb ff
+ end;
+ in
+ fmt_die (Hashtbl.find dies root)
+;;
+
+let read_dies
+ (sess:Session.sess)
+ (ar:asm_reader)
+ ((off:int),(sz:int))
+ (abbrevs:(int,abbrev) Hashtbl.t)
+ : (int * ((int,die) Hashtbl.t)) =
+ ar.asm_seek off;
+ let cu_len = ar.asm_get_u32() in
+ let _ = log sess "debug_info cu_len: %d, section size %d" cu_len sz in
+ let _ = assert ((cu_len + 4) = sz) in
+ let dwarf_vers = ar.asm_get_u16() in
+ let _ = assert (dwarf_vers >= 2) in
+ let cu_abbrev_off = ar.asm_get_u32() in
+ let _ = assert (cu_abbrev_off = 0) in
+ let sizeof_addr = ar.asm_get_u8() in
+ let _ = assert (sizeof_addr = 4) in
+
+ let adv_block1 _ =
+ let len = ar.asm_get_u8() in
+ ar.asm_adv len
+ in
+
+ let adv_block4 _ =
+ let len = ar.asm_get_u32() in
+ ar.asm_adv len
+ in
+
+ let all_dies = Hashtbl.create 0 in
+ let root = (ar.asm_get_off()) - off in
+
+ let rec read_dies (dies:(die list) ref) =
+ let die_arr _ = Array.of_list (List.rev (!dies)) in
+ if ar.asm_get_off() >= (off + sz)
+ then die_arr()
+ else
+ begin
+ let die_off = (ar.asm_get_off()) - off in
+ let abbrev_num = ar.asm_get_uleb() in
+ if abbrev_num = 0
+ then die_arr()
+ else
+ let _ =
+ log sess "DIE at off <%d> with abbrev %d"
+ die_off abbrev_num
+ in
+ let abbrev = Hashtbl.find abbrevs abbrev_num in
+ let (tag, children, attrs) = abbrev in
+ let attrs =
+ Array.map
+ begin
+ fun (attr,form) ->
+ let data =
+ match form with
+ DW_FORM_string -> DATA_str (ar.asm_get_zstr())
+ | DW_FORM_addr -> DATA_num (ar.asm_get_u32())
+ | DW_FORM_ref_addr -> DATA_num (ar.asm_get_u32())
+ | DW_FORM_data1 -> DATA_num (ar.asm_get_u8())
+ | DW_FORM_data4 -> DATA_num (ar.asm_get_u32())
+ | DW_FORM_flag -> DATA_num (ar.asm_get_u8())
+ | DW_FORM_block1 -> (adv_block1(); DATA_other)
+ | DW_FORM_block4 -> (adv_block4(); DATA_other)
+ | _ ->
+ bug () "unknown DWARF form %d"
+ (dw_form_to_int form)
+ in
+ (attr, (form, data))
+ end
+ attrs;
+ in
+ let children =
+ match children with
+ DW_CHILDREN_yes -> read_dies (ref [])
+ | DW_CHILDREN_no -> [| |]
+ in
+ let die = { die_off = die_off;
+ die_tag = tag;
+ die_attrs = attrs;
+ die_children = children }
+ in
+ prepend dies die;
+ htab_put all_dies die_off die;
+ read_dies dies
+ end
+ in
+ ignore (read_dies (ref []));
+ iflog sess
+ begin
+ fun _ ->
+ log sess "read DIEs:";
+ log sess "%s" (Ast.fmt_to_str fmt_dies (root, all_dies));
+ end;
+ (root, all_dies)
+;;
+
+let rec extract_meta
+ ((i:int),(dies:(int,die) Hashtbl.t))
+ : (Ast.ident * string) array =
+ let meta = Queue.create () in
+
+ let get_attr die attr =
+ atab_find die.die_attrs attr
+ in
+
+ let get_str die attr =
+ match get_attr die attr with
+ (_, DATA_str s) -> s
+ | _ -> bug () "unexpected num form for %s" (dw_at_to_string attr)
+ in
+
+ let die = Hashtbl.find dies i in
+ begin
+ match die.die_tag with
+ DW_TAG_rust_meta ->
+ let n = get_str die DW_AT_name in
+ let v = get_str die DW_AT_const_value in
+ Queue.add (n,v) meta
+
+ | DW_TAG_compile_unit ->
+ Array.iter
+ (fun child ->
+ Array.iter (fun m -> Queue.add m meta)
+ (extract_meta (child.die_off,dies)))
+ die.die_children
+
+ | _ -> ()
+ end;
+ queue_to_arr meta
+;;
+
+
+let rec extract_mod_items
+ (nref:node_id ref)
+ (oref:opaque_id ref)
+ (abi:Abi.abi)
+ (mis:Ast.mod_items)
+ ((i:int),(dies:(int,die) Hashtbl.t))
+ : unit =
+
+ let next_node_id _ : node_id =
+ let id = !nref in
+ nref:= Node ((int_of_node id)+1);
+ id
+ in
+
+ let next_opaque_id _ : opaque_id =
+ let id = !oref in
+ oref:= Opaque ((int_of_opaque id)+1);
+ id
+ in
+
+ let external_opaques = Hashtbl.create 0 in
+ let get_opaque_of o =
+ htab_search_or_add external_opaques o
+ (fun _ -> next_opaque_id())
+ in
+
+
+ let (word_sz:int64) = abi.Abi.abi_word_sz in
+ let (word_sz_int:int) = Int64.to_int word_sz in
+
+ let get_die i =
+ Hashtbl.find dies i
+ in
+
+ let get_attr die attr =
+ atab_find die.die_attrs attr
+ in
+
+ let get_str die attr =
+ match get_attr die attr with
+ (_, DATA_str s) -> s
+ | _ -> bug () "unexpected num form for %s" (dw_at_to_string attr)
+ in
+
+ let get_num die attr =
+ match get_attr die attr with
+ (_, DATA_num n) -> n
+ | _ -> bug () "unexpected str form for %s" (dw_at_to_string attr)
+ in
+
+ let get_flag die attr =
+ match get_attr die attr with
+ (_, DATA_num 0) -> false
+ | (_, DATA_num 1) -> true
+ | _ -> bug () "unexpected non-flag form for %s" (dw_at_to_string attr)
+ in
+
+ let get_effect die =
+ match (get_flag die DW_AT_mutable, get_flag die DW_AT_pure) with
+ (* Note: weird encoding: mutable+pure = unsafe. *)
+ (true, true) -> Ast.UNSAFE
+ | (true, false) -> Ast.STATE
+ | (false, false) -> Ast.IO
+ | (false, true) -> Ast.PURE
+ in
+
+ let get_name die = get_str die DW_AT_name in
+
+ let get_type_param die =
+ let idx = get_num die DW_AT_rust_type_param_index in
+ let e = get_effect die in
+ (idx, e)
+ in
+
+ let get_native_id die =
+ get_num die DW_AT_rust_native_type_id
+ in
+
+ let get_type_param_decl die =
+ ((get_str die DW_AT_name), (get_type_param die))
+ in
+
+ let is_rust_type die t =
+ match atab_search die.die_attrs DW_AT_rust_type_code with
+ Some (_, DATA_num n) -> (dw_rust_type_of_int n) = t
+ | _ -> false
+ in
+
+ let rec get_ty die : Ast.ty =
+ match die.die_tag with
+
+ DW_TAG_structure_type
+ when is_rust_type die DW_RUST_nil ->
+ Ast.TY_nil
+
+ | DW_TAG_pointer_type
+ when is_rust_type die DW_RUST_task ->
+ Ast.TY_task
+
+ | DW_TAG_pointer_type
+ when is_rust_type die DW_RUST_type ->
+ Ast.TY_type
+
+ | DW_TAG_pointer_type
+ when is_rust_type die DW_RUST_port ->
+ Ast.TY_port (get_referenced_ty die)
+
+ | DW_TAG_pointer_type
+ when is_rust_type die DW_RUST_chan ->
+ Ast.TY_chan (get_referenced_ty die)
+
+ | DW_TAG_pointer_type
+ when is_rust_type die DW_RUST_vec ->
+ Ast.TY_vec (get_referenced_slot die)
+
+ | DW_TAG_pointer_type
+ when is_rust_type die DW_RUST_type_param ->
+ Ast.TY_param (get_type_param die)
+
+ | DW_TAG_pointer_type
+ when is_rust_type die DW_RUST_native ->
+ Ast.TY_native (get_opaque_of (get_native_id die))
+
+ | DW_TAG_string_type -> Ast.TY_str
+
+ | DW_TAG_base_type ->
+ begin
+ match ((get_name die),
+ (dw_ate_of_int (get_num die DW_AT_encoding)),
+ (get_num die DW_AT_byte_size)) with
+ ("bool", DW_ATE_boolean, 1) -> Ast.TY_bool
+ | ("u8", DW_ATE_unsigned, 1) -> Ast.TY_mach TY_u8
+ | ("u16", DW_ATE_unsigned, 2) -> Ast.TY_mach TY_u16
+ | ("u32", DW_ATE_unsigned, 4) -> Ast.TY_mach TY_u32
+ | ("u64", DW_ATE_unsigned, 8) -> Ast.TY_mach TY_u64
+ | ("i8", DW_ATE_signed, 1) -> Ast.TY_mach TY_i8
+ | ("i16", DW_ATE_signed, 2) -> Ast.TY_mach TY_i16
+ | ("i32", DW_ATE_signed, 4) -> Ast.TY_mach TY_i32
+ | ("i64", DW_ATE_signed, 8) -> Ast.TY_mach TY_i64
+ | ("char", DW_ATE_unsigned_char, 4) -> Ast.TY_char
+ | ("int", DW_ATE_signed, sz)
+ when sz = word_sz_int -> Ast.TY_int
+ | ("uint", DW_ATE_unsigned, sz)
+ when sz = word_sz_int -> Ast.TY_uint
+ | _ -> bug () "unexpected type of DW_TAG_base_type"
+ end
+
+ | DW_TAG_structure_type ->
+ begin
+ let is_num_idx s =
+ let len = String.length s in
+ if len >= 2 && s.[0] = '_'
+ then
+ let ok = ref true in
+ String.iter
+ (fun c -> ok := (!ok) && '0' <= c && c <= '9')
+ (String.sub s 1 (len-1));
+ !ok
+ else
+ false
+ in
+ let members = arr_map_partial
+ die.die_children
+ begin
+ fun child ->
+ if child.die_tag = DW_TAG_member
+ then Some child
+ else None
+ end
+ in
+ assert ((Array.length members) > 0);
+ if is_num_idx (get_name members.(0))
+ then
+ let slots = Array.map get_referenced_slot members in
+ Ast.TY_tup slots
+ else
+ let entries =
+ Array.map
+ (fun member_die -> ((get_name member_die),
+ (get_referenced_slot member_die)))
+ members
+ in
+ Ast.TY_rec entries
+ end
+
+ | DW_TAG_interface_type ->
+ let eff = get_effect die in
+ let fns = Hashtbl.create 0 in
+ Array.iter
+ begin
+ fun child ->
+ if child.die_tag = DW_TAG_subroutine_type
+ then
+ Hashtbl.add fns (get_name child) (get_ty_fn child)
+ end
+ die.die_children;
+ Ast.TY_obj (eff,fns)
+
+ | DW_TAG_subroutine_type ->
+ Ast.TY_fn (get_ty_fn die)
+
+ | _ ->
+ bug () "unexpected tag in get_ty: %s"
+ (dw_tag_to_string die.die_tag)
+
+ and get_slot die : Ast.slot =
+ match die.die_tag with
+ DW_TAG_reference_type ->
+ let ty = get_referenced_ty die in
+ let mut = get_flag die DW_AT_mutable in
+ let mode =
+ (* Exterior slots have a 'data_location' attr. *)
+ match atab_search die.die_attrs DW_AT_data_location with
+ Some _ -> Ast.MODE_exterior
+ | None -> Ast.MODE_alias
+ in
+ { Ast.slot_mode = mode;
+ Ast.slot_mutable = mut;
+ Ast.slot_ty = Some ty }
+ | _ ->
+ let ty = get_ty die in
+ (* FIXME: encode mutability of interior slots properly. *)
+ { Ast.slot_mode = Ast.MODE_interior;
+ Ast.slot_mutable = false;
+ Ast.slot_ty = Some ty }
+
+ and get_referenced_ty die =
+ match get_attr die DW_AT_type with
+ (DW_FORM_ref_addr, DATA_num n) -> get_ty (get_die n)
+ | _ -> bug () "unexpected form of DW_AT_type in get_referenced_ty"
+
+ and get_referenced_slot die =
+ match get_attr die DW_AT_type with
+ (DW_FORM_ref_addr, DATA_num n) -> get_slot (get_die n)
+ | _ -> bug () "unexpected form of DW_AT_type in get_referenced_slot"
+
+ and get_ty_fn die =
+ let out = get_referenced_slot die in
+ let ins =
+ arr_map_partial
+ die.die_children
+ begin
+ fun child ->
+ if child.die_tag = DW_TAG_formal_parameter
+ then Some (get_referenced_slot child)
+ else None
+ end
+ in
+ let effect = get_effect die in
+ let iter = get_flag die DW_AT_rust_iterator in
+ let tsig =
+ { Ast.sig_input_slots = ins;
+ Ast.sig_input_constrs = [| |];
+ Ast.sig_output_slot = out; }
+ in
+ let taux =
+ { Ast.fn_is_iter = iter;
+ Ast.fn_effect = effect }
+ in
+ (tsig, taux)
+ in
+
+ let wrap n =
+ { id = next_node_id ();
+ node = n }
+ in
+
+ let decl p i =
+ wrap { Ast.decl_params = p;
+ Ast.decl_item = i; }
+ in
+
+ let get_formals die =
+ let islots = Queue.create () in
+ let params = Queue.create () in
+ Array.iter
+ begin
+ fun child ->
+ match child.die_tag with
+ DW_TAG_formal_parameter ->
+ if (is_rust_type child DW_RUST_type_param)
+ then Queue.push (wrap (get_type_param_decl child)) params
+ else Queue.push (get_referenced_slot child) islots
+ | _ -> ()
+ end
+ die.die_children;
+ (queue_to_arr params, queue_to_arr islots)
+ in
+
+ let extract_children mis die =
+ Array.iter
+ (fun child ->
+ extract_mod_items nref oref abi mis (child.die_off,dies))
+ die.die_children
+ in
+
+ let get_mod_items die =
+ let len = Array.length die.die_children in
+ let mis = Hashtbl.create len in
+ extract_children mis die;
+ mis
+ in
+
+ let form_header_slots slots =
+ Array.mapi
+ (fun i slot -> (wrap slot, "_" ^ (string_of_int i)))
+ slots
+ in
+
+ let die = Hashtbl.find dies i in
+ match die.die_tag with
+ DW_TAG_typedef ->
+ let ident = get_name die in
+ let ty = get_referenced_ty die in
+ let tyi = Ast.MOD_ITEM_type ty in
+ let (params, islots) = get_formals die in
+ assert ((Array.length islots) = 0);
+ htab_put mis ident (decl params tyi)
+
+ | DW_TAG_compile_unit ->
+ extract_children mis die
+
+ | DW_TAG_module ->
+ let ident = get_name die in
+ let sub_mis = get_mod_items die in
+ let exports = Hashtbl.create 0 in
+ let _ = Hashtbl.add exports Ast.EXPORT_all_decls () in
+ let view = { Ast.view_imports = Hashtbl.create 0;
+ Ast.view_exports = exports }
+ in
+ let mi = Ast.MOD_ITEM_mod (view, sub_mis) in
+ htab_put mis ident (decl [||] mi)
+
+ | DW_TAG_subprogram ->
+ (* FIXME: finish this. *)
+ let ident = get_name die in
+ let oslot = get_referenced_slot die in
+ let effect = get_effect die in
+ let (params, islots) = get_formals die in
+ let taux = { Ast.fn_effect = effect;
+ Ast.fn_is_iter = false }
+ in
+ let tfn = { Ast.fn_input_slots = form_header_slots islots;
+ Ast.fn_input_constrs = [| |];
+ Ast.fn_output_slot = wrap oslot;
+ Ast.fn_aux = taux;
+ Ast.fn_body = (wrap [||]); }
+ in
+ let fn = Ast.MOD_ITEM_fn tfn in
+ htab_put mis ident (decl params fn)
+
+ | _ -> ()
+;;
+
+(*
+ * Local Variables:
+ * fill-column: 78;
+ * indent-tabs-mode: nil
+ * buffer-file-coding-system: utf-8-unix
+ * compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
+ * End:
+ *)
+