diff options
Diffstat (limited to 'lib/ocaml_rts/linksem/dwarf.ml')
| -rw-r--r-- | lib/ocaml_rts/linksem/dwarf.ml | 4619 |
1 files changed, 4619 insertions, 0 deletions
diff --git a/lib/ocaml_rts/linksem/dwarf.ml b/lib/ocaml_rts/linksem/dwarf.ml new file mode 100644 index 00000000..9e5a31aa --- /dev/null +++ b/lib/ocaml_rts/linksem/dwarf.ml @@ -0,0 +1,4619 @@ +(*Generated by Lem from dwarf.lem.*) +open Lem_basic_classes +open Lem_bool +open Lem_function +open Lem_maybe +open Lem_num +open Lem_string + +open Lem_list (* TODO: check why this is not imported in ELF *) + +open Byte_sequence +open Error +open Hex_printing +open Missing_pervasives +open Show + +open Default_printing + +open Endianness +open String_table + +open Elf_dynamic +open Elf_file +open Elf_header +open Elf_program_header_table +open Elf_relocation +open Elf_section_header_table +open Elf_symbol_table +open Elf_types_native_uint + + +(** ***************** experimental DWARF reading *********** *) + +(* + +This defines a representation of some of the DWARF debug information, +with parsing functions to extract it from the byte sequences of the +relevant ELF sections, and pretty-printing function to dump it in a +human-readable form, similar to that of readelf. The main functions +for this are: + + val extract_dwarf : elf64_file -> maybe dwarf + val pp_dwarf : dwarf -> string + +It also defines evaluation of DWARF expressions and analysis functions +to convert the variable location information to a form suitable for +looking up variable names from machine addresses that arise during +execution, including the call frame address calculation. The main +types and functions for this are: + + type analysed_location_data + val analyse_locations : dwarf -> analysed_location_data + + type evaluated_frame_info + val evaluate_frame_info : dwarf -> evaluated_frame_info + + type dwarf_static + val extract_dwarf_static : elf64_file -> maybe dwarf_static + +The last collects all the above - information that can be computed statically. + +Then to do lookup from addresses to source-code names, we have: + + type analysed_location_data_at_pc + val analysed_locations_at_pc : evaluation_context -> dwarf_static -> natural -> analysed_location_data_at_pc + val names_of_address : dwarf -> analysed_location_data_at_pc -> natural -> list string + +The definitions are deliberately simple-minded, to be quick to write, +easy to see the correspondence to the DWARF text specification, and +potentially support generation of theorem-prover definitions in +future. They are in a pure functional style, making the information +dependencies explicit. They are not written for performance, though +they may be efficient enough for small examples as-is. They are +written in Lem, and compiled from that to executable OCaml. + +The development follows the DWARF 4 pdf specification at http://www.dwarfstd.org/ +though tweaked in places where our examples use earlier versions. It doesn't +systematically cover all the DWARF versions. +It doesn't cover the GNU extensions +(at https://fedorahosted.org/elfutils/wiki/DwarfExtensions). +The representation, parsing, and pretty printing are mostly complete for the +data in these DWARF ELF sections: + +.debug_abbrev +.debug_info +.debug_types +.debug_loc +.debug_str +.debug_ranges +.debug_frame (without augmentations) +.debug_line + +The following DWARF ELF sections are not covered: + +.debug_aranges +.debug_macinfo +.debug_pubnames +.debug_pubtypes + +The evaluation of DWARF expressions covers only some of the operations +- probably enough for common cases. + +The analysis of DWARF location data should be enough to look up names +from the addresses of variables and formal parameters. It does not +currently handle the DWARF type data, so will not be useful for accesses +strictly within the extent of a variable or parameter. + +The 'dwarf' type gives a lightly parsed representation of some of the +dwarf information, with the byte sequences of the above .debug_* +sections parsed into a structured representation. That makes the list +and tree structures explicit, and converts the various numeric types +into just natural, integer, and byte sequences. The lem natural and +integer could be replaced by unsigned and signed 64-bit types; that'd +probably be better for execution but not for theorem-prover use. + +*) + +(* some spec ambiguities (more in comments in-line below): *) +(* can a location list be referenced from multiple compilation units, with different base addresses? *) + + +(** debug *) + +(* workaround debug.lem linking *) +(*val print_endline : string -> unit*) + +let my_debug s:unit= () (*print_endline s*) +let my_debug2 s:unit= () (*print_endline s*) +let my_debug3 s:unit= () (*print_endline s*) +let my_debug4 s:unit= () (*print_endline s*) +let my_debug5 s:unit= (print_endline s) + + +(** ************************************************************ *) +(** ** dwarf representation types **************************** *) +(** ************************************************************ *) + + +type dwarf_attribute_classes = + | DWA_7_5_3 + | DWA_address + | DWA_block + | DWA_constant + | DWA_dash + | DWA_exprloc + | DWA_flag + | DWA_lineptr + | DWA_loclistptr + | DWA_macptr + | DWA_rangelistptr + | DWA_reference + | DWA_string + +(* operations and expression evalution *) + +type operation_argument_type = + | OAT_addr + | OAT_dwarf_format_t + | OAT_uint8 + | OAT_uint16 + | OAT_uint32 + | OAT_uint64 + | OAT_sint8 + | OAT_sint16 + | OAT_sint32 + | OAT_sint64 + | OAT_ULEB128 + | OAT_SLEB128 + | OAT_block + +type operation_argument_value = + | OAV_natural of Nat_big_num.num + | OAV_integer of Nat_big_num.num + | OAV_block of Nat_big_num.num * char list + +type operation_stack = Nat_big_num.num list + +type arithmetic_context = + { + ac_bitwidth: Nat_big_num.num; + ac_half: Nat_big_num.num; (* 2 ^ (ac_bitwidth -1) *) + ac_all: Nat_big_num.num; (* 2 ^ ac_bitwidth *) + ac_max: Nat_big_num.num; (* (2 ^ ac_bitwidth) -1 *) (* also the representation of -1 *) +} + +type operation_semantics = + | OpSem_lit + | OpSem_deref + | OpSem_stack of (arithmetic_context -> operation_stack -> operation_argument_value list -> operation_stack option) + | OpSem_not_supported + | OpSem_binary of (arithmetic_context -> Nat_big_num.num -> Nat_big_num.num -> Nat_big_num.num option) + | OpSem_unary of (arithmetic_context -> Nat_big_num.num -> Nat_big_num.num option) + | OpSem_opcode_lit of Nat_big_num.num + | OpSem_reg + | OpSem_breg + | OpSem_bregx + | OpSem_fbreg + | OpSem_deref_size + | OpSem_nop + | OpSem_piece + | OpSem_bit_piece + | OpSem_implicit_value + | OpSem_stack_value + | OpSem_call_frame_cfa + +type operation = + { + op_code: Nat_big_num.num; + op_string: string; + op_argument_values: operation_argument_value list; + op_semantics: operation_semantics; + } + + +(* the result of a location expression evaluation is a single_location (or failure) *) + +type simple_location = + | SL_memory_address of Nat_big_num.num + | SL_register of Nat_big_num.num + | SL_implicit of char list (* used for implicit and stack values *) + | SL_empty + +type composite_location_piece = + | CLP_piece of Nat_big_num.num * simple_location + | CLP_bit_piece of Nat_big_num.num * Nat_big_num.num * simple_location + +type single_location = + | SL_simple of simple_location + | SL_composite of composite_location_piece list + +(* location expression evaluation is a stack machine operating over the following state *) + +type state = + { + s_stack: operation_stack; + s_value: simple_location; + s_location_pieces: composite_location_piece list; + } + +(* location expression evaluation can involve register and memory reads, via the following interface *) + +type 'a register_read_result = + | RRR_result of Nat_big_num.num + | RRR_not_currently_available + | RRR_bad_register_number + +type 'a memory_read_result = + | MRR_result of Nat_big_num.num + | MRR_not_currently_available + | MRR_bad_address + +type evaluation_context = + { + read_register: Nat_big_num.num -> Nat_big_num.num register_read_result; + read_memory: Nat_big_num.num -> Nat_big_num.num -> Nat_big_num.num memory_read_result; + } + + +(* dwarf sections *) + +type dwarf_format = + | Dwarf32 + | Dwarf64 + +(* .debug_abbrev section *) + +type abbreviation_declaration = + { + ad_abbreviation_code: Nat_big_num.num; + ad_tag: Nat_big_num.num; + ad_has_children: bool; + ad_attribute_specifications: (Nat_big_num.num * Nat_big_num.num) list; + } + +type abbreviations_table = abbreviation_declaration list + +(* .debug_info section *) + +type attribute_value = + | AV_addr of Nat_big_num.num + | AV_block of Nat_big_num.num * char list + | AV_constantN of Nat_big_num.num * char list + | AV_constant_SLEB128 of Nat_big_num.num + | AV_constant_ULEB128 of Nat_big_num.num + | AV_exprloc of Nat_big_num.num * char list + | AV_flag of bool + | AV_ref of Nat_big_num.num + | AV_ref_addr of Nat_big_num.num (* dwarf_format dependent *) + | AV_ref_sig8 of Nat_big_num.num + | AV_sec_offset of Nat_big_num.num + | AV_string of char list (* not including terminating null *) + | AV_strp of Nat_big_num.num (* dwarf_format dependent *) + +type die = + { + die_offset: Nat_big_num.num; + die_abbreviation_code: Nat_big_num.num; + die_abbreviation_declaration: abbreviation_declaration; + die_attribute_values: (Nat_big_num.num (*pos*) * attribute_value) list; + die_children: die list; + } + +type compilation_unit_header = + { + cuh_offset: Nat_big_num.num; + cuh_dwarf_format: dwarf_format; + cuh_unit_length: Nat_big_num.num; + cuh_version: Nat_big_num.num; + cuh_debug_abbrev_offset: Nat_big_num.num; + cuh_address_size: Nat_big_num.num; + } + +type compilation_unit = + { + cu_header: compilation_unit_header; + cu_abbreviations_table: abbreviations_table; + cu_die: die; + } + +type compilation_units = compilation_unit list + +(* .debug_type section *) + +type type_unit_header = + { + tuh_cuh: compilation_unit_header; + tuh_type_signature: Nat_big_num.num; + tuh_type_offset: Nat_big_num.num; + } + +type type_unit = + { + tu_header: type_unit_header; + tu_abbreviations_table: abbreviations_table; + tu_die: die; + } + +type type_units = type_unit list + +(* .debug_loc section *) + +type single_location_description = char list + +type location_list_entry = + { + lle_beginning_address_offset: Nat_big_num.num; + lle_ending_address_offset: Nat_big_num.num; + lle_single_location_description: single_location_description; + } + +type base_address_selection_entry = + { + base_address: Nat_big_num.num; + } + +type location_list_item = + | LLI_lle of location_list_entry + | LLI_base of base_address_selection_entry + +type location_list = Nat_big_num.num (*offset*) * location_list_item list + +type location_list_list = location_list list + +(* .debug_ranges section *) + +type range_list_entry = + { + rle_beginning_address_offset: Nat_big_num.num; + rle_ending_address_offset: Nat_big_num.num; + } + +type range_list_item = + | RLI_rle of range_list_entry + | RLI_base of base_address_selection_entry + +type range_list = Nat_big_num.num (*offset*) * range_list_item list + +type range_list_list = range_list list + +(* .debug_frame section: call frame instructions *) + +type cfa_address = Nat_big_num.num +type cfa_block = char list +type cfa_delta = Nat_big_num.num +type cfa_offset = Nat_big_num.num +type cfa_register = Nat_big_num.num +type cfa_sfoffset = Nat_big_num.num + +type call_frame_argument_type = + | CFAT_address + | CFAT_delta1 + | CFAT_delta2 + | CFAT_delta4 + | CFAT_delta_ULEB128 + | CFAT_offset (*ULEB128*) + | CFAT_sfoffset (*SLEB128*) + | CFAT_register (*ULEB128*) + | CFAT_block + +type call_frame_argument_value = + | CFAV_address of cfa_address + | CFAV_block of cfa_block + | CFAV_delta of cfa_delta + | CFAV_offset of cfa_offset + | CFAV_register of cfa_register + | CFAV_sfoffset of cfa_sfoffset + +type call_frame_instruction = + | DW_CFA_advance_loc of cfa_delta + | DW_CFA_offset of cfa_register * cfa_offset + | DW_CFA_restore of cfa_register + | DW_CFA_nop + | DW_CFA_set_loc of cfa_address + | DW_CFA_advance_loc1 of cfa_delta + | DW_CFA_advance_loc2 of cfa_delta + | DW_CFA_advance_loc4 of cfa_delta + | DW_CFA_offset_extended of cfa_register * cfa_offset + | DW_CFA_restore_extended of cfa_register + | DW_CFA_undefined of cfa_register + | DW_CFA_same_value of cfa_register + | DW_CFA_register of cfa_register * cfa_register + | DW_CFA_remember_state + | DW_CFA_restore_state + | DW_CFA_def_cfa of cfa_register * cfa_offset + | DW_CFA_def_cfa_register of cfa_register + | DW_CFA_def_cfa_offset of cfa_offset + | DW_CFA_def_cfa_expression of cfa_block + | DW_CFA_expression of cfa_register * cfa_block + | DW_CFA_offset_extended_sf of cfa_register * cfa_sfoffset + | DW_CFA_def_cfa_sf of cfa_register * cfa_sfoffset + | DW_CFA_def_cfa_offset_sf of cfa_sfoffset + | DW_CFA_val_offset of cfa_register * cfa_offset + | DW_CFA_val_offset_sf of cfa_register * cfa_sfoffset + | DW_CFA_val_expression of cfa_register * cfa_block + | DW_CFA_unknown of char + +(* .debug_frame section: top-level *) + +type cie = + { + cie_offset: Nat_big_num.num; + cie_length: Nat_big_num.num; + cie_id: Nat_big_num.num; + cie_version: Nat_big_num.num; + cie_augmentation: char list; (* not including terminating null *) + cie_address_size: Nat_big_num.num option; + cie_segment_size: Nat_big_num.num option; + cie_code_alignment_factor: Nat_big_num.num; + cie_data_alignment_factor: Nat_big_num.num; + cie_return_address_register: cfa_register; + cie_initial_instructions_bytes: char list; + cie_initial_instructions: call_frame_instruction list; + } + +type fde = + { + fde_offset: Nat_big_num.num; + fde_length: Nat_big_num.num; + fde_cie_pointer: Nat_big_num.num; + fde_initial_location_segment_selector: Nat_big_num.num option; + fde_initial_location_address: Nat_big_num.num; + fde_address_range: Nat_big_num.num; + fde_instructions_bytes: char list; + fde_instructions: call_frame_instruction list; + } + +type frame_info_element = + | FIE_cie of cie + | FIE_fde of fde + +type frame_info = frame_info_element list + + +(* evaluated cfa data *) + +type cfa_rule = + | CR_undefined + | CR_register of cfa_register * Nat_big_num.num + | CR_expression of single_location_description + +type register_rule = + | RR_undefined (*A register that has this rule has no recoverable value in the previous frame. + (By convention, it is not preserved by a callee.)*) + | RR_same_value (*This register has not been modified from the previous frame. (By convention, + it is preserved by the callee, but the callee has not modified it.)*) + | RR_offset of Nat_big_num.num (* The previous value of this register is saved at the address CFA+N where CFA + is the current CFA value and N is a signed offset.*) + | RR_val_offset of Nat_big_num.num (* The previous value of this register is the value CFA+N where CFA is the + current CFA value and N is a signed offset.*) + | RR_register of Nat_big_num.num (* The previous value of this register is stored in another register numbered R.*) + | RR_expression of single_location_description (* The previous value of this register is located at the address produced by + executing the DWARF expression E.*) + | RR_val_expression of single_location_description (* The previous value of this register is the value produced by executing the +DWARF expression E.*) + | RR_architectural (*The rule is defined externally to this specification by the augmenter*) + +type register_rule_map = (cfa_register * register_rule) list + +type cfa_table_row = + { + ctr_loc: Nat_big_num.num; + ctr_cfa: cfa_rule; + ctr_regs: register_rule_map; + } + +type cfa_state = + { + cs_current_row: cfa_table_row; + cs_previous_rows: cfa_table_row list; + cs_initial_instructions_row: cfa_table_row; + cs_row_stack: cfa_table_row list; + } + + +type evaluated_frame_info = (fde * cfa_table_row list) + list + + +(* line number *) + +type line_number_argument_type = + | LNAT_address + | LNAT_ULEB128 + | LNAT_SLEB128 + | LNAT_uint16 + | LNAT_string + +type line_number_argument_value = + | LNAV_address of Nat_big_num.num + | LNAV_ULEB128 of Nat_big_num.num + | LNAV_SLEB128 of Nat_big_num.num + | LNAV_uint16 of Nat_big_num.num + | LNAV_string of char list (* not including terminating null *) + +type line_number_operation = + (* standard *) + | DW_LNS_copy + | DW_LNS_advance_pc of Nat_big_num.num + | DW_LNS_advance_line of Nat_big_num.num + | DW_LNS_set_file of Nat_big_num.num + | DW_LNS_set_column of Nat_big_num.num + | DW_LNS_negate_stmt + | DW_LNS_set_basic_block + | DW_LNS_const_add_pc + | DW_LNS_fixed_advance_pc of Nat_big_num.num + | DW_LNS_set_prologue_end + | DW_LNS_set_epilogue_begin + | DW_LNS_set_isa of Nat_big_num.num + (* extended *) + | DW_LNE_end_sequence + | DW_LNE_set_address of Nat_big_num.num + | DW_LNE_define_file of ( char list) * Nat_big_num.num * Nat_big_num.num * Nat_big_num.num + | DW_LNE_set_discriminator of Nat_big_num.num + (* special *) + | DW_LN_special of Nat_big_num.num (* the adjusted opcode *) + +type line_number_file_entry = + { + lnfe_path: char list; + lnfe_directory_index: Nat_big_num.num; + lnfe_last_modification: Nat_big_num.num; + lnfe_length: Nat_big_num.num; + } + +type line_number_header = + { + lnh_offset: Nat_big_num.num; + lnh_dwarf_format: dwarf_format; + lnh_unit_length: Nat_big_num.num; + lnh_version: Nat_big_num.num; + lnh_header_length: Nat_big_num.num; + lnh_minimum_instruction_length: Nat_big_num.num; + lnh_maximum_operations_per_instruction: Nat_big_num.num; + lnh_default_is_stmt: bool; + lnh_line_base: Nat_big_num.num; + lnh_line_range: Nat_big_num.num; + lnh_opcode_base: Nat_big_num.num; + lnh_standard_opcode_lengths: Nat_big_num.num list; + lnh_include_directories: ( char list) list; + lnh_file_names: line_number_file_entry list; + } + +type line_number_program = + { + lnp_header: line_number_header; + lnp_operations: line_number_operation list; + } + +(* line number evaluation *) + +type line_number_registers = + { + lnr_address: Nat_big_num.num; + lnr_op_index: Nat_big_num.num; + lnr_file: Nat_big_num.num; + lnr_line: Nat_big_num.num; + lnr_column: Nat_big_num.num; + lnr_is_stmt: bool; + lnr_basic_block: bool; + lnr_end_sequence: bool; + lnr_prologue_end: bool; + lnr_epilogue_begin: bool; + lnr_isa: Nat_big_num.num; + lnr_discriminator: Nat_big_num.num; + } + + + + +(* top-level collection of dwarf data *) + +type dwarf = + { + d_endianness: Endianness.endianness; (* from the ELF *) + d_str: char list; + d_compilation_units: compilation_units; + d_type_units: type_units; + d_loc: location_list_list; + d_ranges: range_list_list; + d_frame_info: frame_info; + d_line_info: line_number_program list; + } + +(* analysed location data *) + +type analysed_location_data = ((compilation_unit * ( die list) * die) * ( (Nat_big_num.num * Nat_big_num.num * single_location_description)list)option) list + +type analysed_location_data_at_pc = ((compilation_unit * ( die list) * die) * (Nat_big_num.num * Nat_big_num.num * single_location_description * single_location error)) list + +(* evaluated line data *) + +type evaluated_line_info = (line_number_header * line_number_registers list) list + +type dwarf_static = + { + ds_dwarf: dwarf; + ds_analysed_location_data: analysed_location_data; + ds_evaluated_frame_info: evaluated_frame_info; + ds_evaluated_line_info: evaluated_line_info; + } + +type dwarf_dynamic_at_pc = analysed_location_data_at_pc + +(** context for parsing and pp functions *) + +type p_context = + { + endianness: Endianness.endianness; + } + + + +(** ************************************************************ *) +(** ** missing pervasives ************************************ *) +(** ************************************************************ *) + +(** hex parsing *) + +(* this should be in lem, either built-in or in pervasives *) + +(*val natural_of_char : char -> natural*) +let natural_of_char c:Nat_big_num.num= + (let naturalOrd c'= (Nat_big_num.of_int (Char.code c')) in + let n = (naturalOrd c) in + if Nat_big_num.greater_equal n (naturalOrd '0') && Nat_big_num.less_equal n (naturalOrd '9') then Nat_big_num.sub_nat n (naturalOrd '0') + else if Nat_big_num.greater_equal n (naturalOrd 'A') && Nat_big_num.less_equal n (naturalOrd 'F') then Nat_big_num.add (Nat_big_num.sub_nat n (naturalOrd 'A'))(Nat_big_num.of_int 10) + else if Nat_big_num.greater_equal n (naturalOrd 'a') && Nat_big_num.less_equal n (naturalOrd 'f') then Nat_big_num.add (Nat_big_num.sub_nat n (naturalOrd 'a'))(Nat_big_num.of_int 10) + else failwith ("natural_of_char argument #'" ^ (Xstring.implode [c] ^ "' not in 0-9,A-F,a-f"))) + +(*val natural_of_hex' : list char -> natural*) +let rec natural_of_hex' cs:Nat_big_num.num= + ((match cs with + | c :: cs' -> Nat_big_num.add (natural_of_char c) (Nat_big_num.mul(Nat_big_num.of_int 16) (natural_of_hex' cs')) + | [] ->Nat_big_num.of_int 0 + )) + +(*val natural_of_hex : string -> natural*) +let natural_of_hex s:Nat_big_num.num= + (let cs = (Xstring.explode s) in + (match cs with + | '0'::'x'::cs' -> + (match cs' with + | c :: _ -> natural_of_hex' (List.rev cs') + | [] -> failwith ("natural_of_hex argument \"" ^ (s ^ "\" has no digits")) + ) + | _ -> failwith ("natural_of_hex argument \"" ^ (s ^ "\" does not begin 0x")) + )) + + +(* natural version of List.index *) +(*val index_natural : forall 'a. list 'a -> natural -> maybe 'a*) +let rec index_natural l n:'a option= ((match l with + | [] -> None + | x :: xs -> if Nat_big_num.equal n(Nat_big_num.of_int 0) then Some x else index_natural xs (Nat_big_num.sub_nat n(Nat_big_num.of_int 1)) +)) + +let partialNaturalFromInteger (i:Nat_big_num.num) : Nat_big_num.num= + (if Nat_big_num.less i(Nat_big_num.of_int 0) then failwith "partialNaturalFromInteger" else Nat_big_num.abs i) + +(*val natural_nat_shift_left : natural -> nat -> natural*) + +(*val natural_nat_shift_right : natural -> nat -> natural*) + + + +(** ************************************************************ *) +(** ** dwarf encodings *************************************** *) +(** ************************************************************ *) + +(* these encoding tables are pasted from the DWARF 4 specification *) + +(* tag encoding *) +let tag_encodings:(string*Nat_big_num.num)list= ([ + ("DW_TAG_array_type" , natural_of_hex "0x01" ); + ("DW_TAG_class_type" , natural_of_hex "0x02" ); + ("DW_TAG_entry_point" , natural_of_hex "0x03" ); + ("DW_TAG_enumeration_type" , natural_of_hex "0x04" ); + ("DW_TAG_formal_parameter" , natural_of_hex "0x05" ); + ("DW_TAG_imported_declaration" , natural_of_hex "0x08" ); + ("DW_TAG_label" , natural_of_hex "0x0a" ); + ("DW_TAG_lexical_block" , natural_of_hex "0x0b" ); + ("DW_TAG_member" , natural_of_hex "0x0d" ); + ("DW_TAG_pointer_type" , natural_of_hex "0x0f" ); + ("DW_TAG_reference_type" , natural_of_hex "0x10" ); + ("DW_TAG_compile_unit" , natural_of_hex "0x11" ); + ("DW_TAG_string_type" , natural_of_hex "0x12" ); + ("DW_TAG_structure_type" , natural_of_hex "0x13" ); + ("DW_TAG_subroutine_type" , natural_of_hex "0x15" ); + ("DW_TAG_typedef" , natural_of_hex "0x16" ); + ("DW_TAG_union_type" , natural_of_hex "0x17" ); + ("DW_TAG_unspecified_parameters" , natural_of_hex "0x18" ); + ("DW_TAG_variant" , natural_of_hex "0x19" ); + ("DW_TAG_common_block" , natural_of_hex "0x1a" ); + ("DW_TAG_common_inclusion" , natural_of_hex "0x1b" ); + ("DW_TAG_inheritance" , natural_of_hex "0x1c" ); + ("DW_TAG_inlined_subroutine" , natural_of_hex "0x1d" ); + ("DW_TAG_module" , natural_of_hex "0x1e" ); + ("DW_TAG_ptr_to_member_type" , natural_of_hex "0x1f" ); + ("DW_TAG_set_type" , natural_of_hex "0x20" ); + ("DW_TAG_subrange_type" , natural_of_hex "0x21" ); + ("DW_TAG_with_stmt" , natural_of_hex "0x22" ); + ("DW_TAG_access_declaration" , natural_of_hex "0x23" ); + ("DW_TAG_base_type" , natural_of_hex "0x24" ); + ("DW_TAG_catch_block" , natural_of_hex "0x25" ); + ("DW_TAG_const_type" , natural_of_hex "0x26" ); + ("DW_TAG_constant" , natural_of_hex "0x27" ); + ("DW_TAG_enumerator" , natural_of_hex "0x28" ); + ("DW_TAG_file_type" , natural_of_hex "0x29" ); + ("DW_TAG_friend" , natural_of_hex "0x2a" ); + ("DW_TAG_namelist" , natural_of_hex "0x2b" ); + ("DW_TAG_namelist_item" , natural_of_hex "0x2c" ); + ("DW_TAG_packed_type" , natural_of_hex "0x2d" ); + ("DW_TAG_subprogram" , natural_of_hex "0x2e" ); + ("DW_TAG_template_type_parameter" , natural_of_hex "0x2f" ); + ("DW_TAG_template_value_parameter" , natural_of_hex "0x30" ); + ("DW_TAG_thrown_type" , natural_of_hex "0x31" ); + ("DW_TAG_try_block" , natural_of_hex "0x32" ); + ("DW_TAG_variant_part" , natural_of_hex "0x33" ); + ("DW_TAG_variable" , natural_of_hex "0x34" ); + ("DW_TAG_volatile_type" , natural_of_hex "0x35" ); + ("DW_TAG_dwarf_procedure" , natural_of_hex "0x36" ); + ("DW_TAG_restrict_type" , natural_of_hex "0x37" ); + ("DW_TAG_interface_type" , natural_of_hex "0x38" ); + ("DW_TAG_namespace" , natural_of_hex "0x39" ); + ("DW_TAG_imported_module" , natural_of_hex "0x3a" ); + ("DW_TAG_unspecified_type" , natural_of_hex "0x3b" ); + ("DW_TAG_partial_unit" , natural_of_hex "0x3c" ); + ("DW_TAG_imported_unit" , natural_of_hex "0x3d" ); + ("DW_TAG_condition" , natural_of_hex "0x3f" ); + ("DW_TAG_shared_type" , natural_of_hex "0x40" ); + ("DW_TAG_type_unit" , natural_of_hex "0x41" ); + ("DW_TAG_rvalue_reference_type" , natural_of_hex "0x42" ); + ("DW_TAG_template_alias" , natural_of_hex "0x43" ); + ("DW_TAG_lo_user" , natural_of_hex "0x4080"); + ("DW_TAG_hi_user" , natural_of_hex "0xffff") +]) + + +(* child determination encoding *) + +let vDW_CHILDREN_no:Nat_big_num.num= (natural_of_hex "0x00") +let vDW_CHILDREN_yes:Nat_big_num.num= (natural_of_hex "0x01") + + +(* attribute encoding *) + +let attribute_encodings:(string*Nat_big_num.num*(dwarf_attribute_classes)list)list= ([ + ("DW_AT_sibling" , natural_of_hex "0x01", [DWA_reference]) ; + ("DW_AT_location" , natural_of_hex "0x02", [DWA_exprloc; DWA_loclistptr]) ; + ("DW_AT_name" , natural_of_hex "0x03", [DWA_string]) ; + ("DW_AT_ordering" , natural_of_hex "0x09", [DWA_constant]) ; + ("DW_AT_byte_size" , natural_of_hex "0x0b", [DWA_constant; DWA_exprloc; DWA_reference]) ; + ("DW_AT_bit_offset" , natural_of_hex "0x0c", [DWA_constant; DWA_exprloc; DWA_reference]) ; + ("DW_AT_bit_size" , natural_of_hex "0x0d", [DWA_constant; DWA_exprloc; DWA_reference]) ; + ("DW_AT_stmt_list" , natural_of_hex "0x10", [DWA_lineptr]) ; + ("DW_AT_low_pc" , natural_of_hex "0x11", [DWA_address]) ; + ("DW_AT_high_pc" , natural_of_hex "0x12", [DWA_address; DWA_constant]) ; + ("DW_AT_language" , natural_of_hex "0x13", [DWA_constant]) ; + ("DW_AT_discr" , natural_of_hex "0x15", [DWA_reference]) ; + ("DW_AT_discr_value" , natural_of_hex "0x16", [DWA_constant]) ; + ("DW_AT_visibility" , natural_of_hex "0x17", [DWA_constant]) ; + ("DW_AT_import" , natural_of_hex "0x18", [DWA_reference]) ; + ("DW_AT_string_length" , natural_of_hex "0x19", [DWA_exprloc; DWA_loclistptr]) ; + ("DW_AT_common_reference" , natural_of_hex "0x1a", [DWA_reference]) ; + ("DW_AT_comp_dir" , natural_of_hex "0x1b", [DWA_string]) ; + ("DW_AT_const_value" , natural_of_hex "0x1c", [DWA_block; DWA_constant; DWA_string]) ; + ("DW_AT_containing_type" , natural_of_hex "0x1d", [DWA_reference]) ; + ("DW_AT_default_value" , natural_of_hex "0x1e", [DWA_reference]) ; + ("DW_AT_inline" , natural_of_hex "0x20", [DWA_constant]) ; + ("DW_AT_is_optional" , natural_of_hex "0x21", [DWA_flag]) ; + ("DW_AT_lower_bound" , natural_of_hex "0x22", [DWA_constant; DWA_exprloc; DWA_reference]) ; + ("DW_AT_producer" , natural_of_hex "0x25", [DWA_string]) ; + ("DW_AT_prototyped" , natural_of_hex "0x27", [DWA_flag]) ; + ("DW_AT_return_addr" , natural_of_hex "0x2a", [DWA_exprloc; DWA_loclistptr]) ; + ("DW_AT_start_scope" , natural_of_hex "0x2c", [DWA_constant; DWA_rangelistptr]) ; + ("DW_AT_bit_stride" , natural_of_hex "0x2e", [DWA_constant; DWA_exprloc; DWA_reference]) ; + ("DW_AT_upper_bound" , natural_of_hex "0x2f", [DWA_constant; DWA_exprloc; DWA_reference]) ; + ("DW_AT_abstract_origin" , natural_of_hex "0x31", [DWA_reference]) ; + ("DW_AT_accessibility" , natural_of_hex "0x32", [DWA_constant]) ; + ("DW_AT_address_class" , natural_of_hex "0x33", [DWA_constant]) ; + ("DW_AT_artificial" , natural_of_hex "0x34", [DWA_flag]) ; + ("DW_AT_base_types" , natural_of_hex "0x35", [DWA_reference]) ; + ("DW_AT_calling_convention" , natural_of_hex "0x36", [DWA_constant]) ; + ("DW_AT_count" , natural_of_hex "0x37", [DWA_constant; DWA_exprloc; DWA_reference]) ; + ("DW_AT_data_member_location" , natural_of_hex "0x38", [DWA_constant; DWA_exprloc; DWA_loclistptr]) ; + ("DW_AT_decl_column" , natural_of_hex "0x39", [DWA_constant]) ; + ("DW_AT_decl_file" , natural_of_hex "0x3a", [DWA_constant]) ; + ("DW_AT_decl_line" , natural_of_hex "0x3b", [DWA_constant]) ; + ("DW_AT_declaration" , natural_of_hex "0x3c", [DWA_flag]) ; + ("DW_AT_discr_list" , natural_of_hex "0x3d", [DWA_block]) ; + ("DW_AT_encoding" , natural_of_hex "0x3e", [DWA_constant]) ; + ("DW_AT_external" , natural_of_hex "0x3f", [DWA_flag]) ; + ("DW_AT_frame_base" , natural_of_hex "0x40", [DWA_exprloc; DWA_loclistptr]) ; + ("DW_AT_friend" , natural_of_hex "0x41", [DWA_reference]) ; + ("DW_AT_identifier_case" , natural_of_hex "0x42", [DWA_constant]) ; + ("DW_AT_macro_info" , natural_of_hex "0x43", [DWA_macptr]) ; + ("DW_AT_namelist_item" , natural_of_hex "0x44", [DWA_reference]) ; + ("DW_AT_priority" , natural_of_hex "0x45", [DWA_reference]) ; + ("DW_AT_segment" , natural_of_hex "0x46", [DWA_exprloc; DWA_loclistptr]) ; + ("DW_AT_specification" , natural_of_hex "0x47", [DWA_reference]) ; + ("DW_AT_static_link" , natural_of_hex "0x48", [DWA_exprloc; DWA_loclistptr]) ; + ("DW_AT_type" , natural_of_hex "0x49", [DWA_reference]) ; + ("DW_AT_use_location" , natural_of_hex "0x4a", [DWA_exprloc; DWA_loclistptr]) ; + ("DW_AT_variable_parameter" , natural_of_hex "0x4b", [DWA_flag]) ; + ("DW_AT_virtuality" , natural_of_hex "0x4c", [DWA_constant]) ; + ("DW_AT_vtable_elem_location" , natural_of_hex "0x4d", [DWA_exprloc; DWA_loclistptr]) ; + ("DW_AT_allocated" , natural_of_hex "0x4e", [DWA_constant; DWA_exprloc; DWA_reference]) ; + ("DW_AT_associated" , natural_of_hex "0x4f", [DWA_constant; DWA_exprloc; DWA_reference]) ; + ("DW_AT_data_location" , natural_of_hex "0x50", [DWA_exprloc]) ; + ("DW_AT_byte_stride" , natural_of_hex "0x51", [DWA_constant; DWA_exprloc; DWA_reference]) ; + ("DW_AT_entry_pc" , natural_of_hex "0x52", [DWA_address]) ; + ("DW_AT_use_UTF8" , natural_of_hex "0x53", [DWA_flag]) ; + ("DW_AT_extension" , natural_of_hex "0x54", [DWA_reference]) ; + ("DW_AT_ranges" , natural_of_hex "0x55", [DWA_rangelistptr]) ; + ("DW_AT_trampoline" , natural_of_hex "0x56", [DWA_address; DWA_flag; DWA_reference; DWA_string]); + ("DW_AT_call_column" , natural_of_hex "0x57", [DWA_constant]) ; + ("DW_AT_call_file" , natural_of_hex "0x58", [DWA_constant]) ; + ("DW_AT_call_line" , natural_of_hex "0x59", [DWA_constant]) ; + ("DW_AT_description" , natural_of_hex "0x5a", [DWA_string]) ; + ("DW_AT_binary_scale" , natural_of_hex "0x5b", [DWA_constant]) ; + ("DW_AT_decimal_scale" , natural_of_hex "0x5c", [DWA_constant]) ; + ("DW_AT_small" , natural_of_hex "0x5d", [DWA_reference]) ; + ("DW_AT_decimal_sign" , natural_of_hex "0x5e", [DWA_constant]) ; + ("DW_AT_digit_count" , natural_of_hex "0x5f", [DWA_constant]) ; + ("DW_AT_picture_string" , natural_of_hex "0x60", [DWA_string]) ; + ("DW_AT_mutable" , natural_of_hex "0x61", [DWA_flag]) ; + ("DW_AT_threads_scaled" , natural_of_hex "0x62", [DWA_flag]) ; + ("DW_AT_explicit" , natural_of_hex "0x63", [DWA_flag]) ; + ("DW_AT_object_pointer" , natural_of_hex "0x64", [DWA_reference]) ; + ("DW_AT_endianity" , natural_of_hex "0x65", [DWA_constant]) ; + ("DW_AT_elemental" , natural_of_hex "0x66", [DWA_flag]) ; + ("DW_AT_pure" , natural_of_hex "0x67", [DWA_flag]) ; + ("DW_AT_recursive" , natural_of_hex "0x68", [DWA_flag]) ; + ("DW_AT_signature" , natural_of_hex "0x69", [DWA_reference]) ; + ("DW_AT_main_subprogram" , natural_of_hex "0x6a", [DWA_flag]) ; + ("DW_AT_data_bit_offset" , natural_of_hex "0x6b", [DWA_constant]) ; + ("DW_AT_const_expr" , natural_of_hex "0x6c", [DWA_flag]) ; + ("DW_AT_enum_class" , natural_of_hex "0x6d", [DWA_flag]) ; + ("DW_AT_linkage_name" , natural_of_hex "0x6e", [DWA_string]) ; + ("DW_AT_lo_user" , natural_of_hex "0x2000", [DWA_dash]) ; + ("DW_AT_hi_user" , natural_of_hex "0x3fff", [DWA_dash]) +]) + + +(* attribute form encoding *) + +let attribute_form_encodings:(string*Nat_big_num.num*(dwarf_attribute_classes)list)list= ([ + ("DW_FORM_addr" , natural_of_hex "0x01", [DWA_address]) ; + ("DW_FORM_block2" , natural_of_hex "0x03", [DWA_block]) ; + ("DW_FORM_block4" , natural_of_hex "0x04", [DWA_block]) ; + ("DW_FORM_data2" , natural_of_hex "0x05", [DWA_constant]) ; + ("DW_FORM_data4" , natural_of_hex "0x06", [DWA_constant]) ; + ("DW_FORM_data8" , natural_of_hex "0x07", [DWA_constant]) ; + ("DW_FORM_string" , natural_of_hex "0x08", [DWA_string]) ; + ("DW_FORM_block" , natural_of_hex "0x09", [DWA_block]) ; + ("DW_FORM_block1" , natural_of_hex "0x0a", [DWA_block]) ; + ("DW_FORM_data1" , natural_of_hex "0x0b", [DWA_constant]) ; + ("DW_FORM_flag" , natural_of_hex "0x0c", [DWA_flag]) ; + ("DW_FORM_sdata" , natural_of_hex "0x0d", [DWA_constant]) ; + ("DW_FORM_strp" , natural_of_hex "0x0e", [DWA_string]) ; + ("DW_FORM_udata" , natural_of_hex "0x0f", [DWA_constant]) ; + ("DW_FORM_ref_addr" , natural_of_hex "0x10", [DWA_reference]); + ("DW_FORM_ref1" , natural_of_hex "0x11", [DWA_reference]); + ("DW_FORM_ref2" , natural_of_hex "0x12", [DWA_reference]); + ("DW_FORM_ref4" , natural_of_hex "0x13", [DWA_reference]); + ("DW_FORM_ref8" , natural_of_hex "0x14", [DWA_reference]); + ("DW_FORM_ref_udata" , natural_of_hex "0x15", [DWA_reference]); + ("DW_FORM_indirect" , natural_of_hex "0x16", [DWA_7_5_3]) ; + ("DW_FORM_sec_offset" , natural_of_hex "0x17", [DWA_lineptr; DWA_loclistptr; DWA_macptr; DWA_rangelistptr]) ; + ("DW_FORM_exprloc" , natural_of_hex "0x18", [DWA_exprloc]) ; + ("DW_FORM_flag_present", natural_of_hex "0x19", [DWA_flag]) ; + ("DW_FORM_ref_sig8" , natural_of_hex "0x20", [DWA_reference]) +]) + + +(* operation encoding *) + +let operation_encodings:(string*Nat_big_num.num*(operation_argument_type)list*operation_semantics)list= ([ +("DW_OP_addr", natural_of_hex "0x03", [OAT_addr] , OpSem_lit); (*1*) (*constant address (size target specific)*) +("DW_OP_deref", natural_of_hex "0x06", [] , OpSem_deref); (*0*) +("DW_OP_const1u", natural_of_hex "0x08", [OAT_uint8] , OpSem_lit); (*1*) (* 1-byte constant *) +("DW_OP_const1s", natural_of_hex "0x09", [OAT_sint8] , OpSem_lit); (*1*) (* 1-byte constant *) +("DW_OP_const2u", natural_of_hex "0x0a", [OAT_uint16] , OpSem_lit); (*1*) (* 2-byte constant *) +("DW_OP_const2s", natural_of_hex "0x0b", [OAT_sint16] , OpSem_lit); (*1*) (* 2-byte constant *) +("DW_OP_const4u", natural_of_hex "0x0c", [OAT_uint32] , OpSem_lit); (*1*) (* 4-byte constant *) +("DW_OP_const4s", natural_of_hex "0x0d", [OAT_sint32] , OpSem_lit); (*1*) (* 4-byte constant *) +("DW_OP_const8u", natural_of_hex "0x0e", [OAT_uint64] , OpSem_lit); (*1*) (* 8-byte constant *) +("DW_OP_const8s", natural_of_hex "0x0f", [OAT_sint64] , OpSem_lit); (*1*) (* 8-byte constant *) +("DW_OP_constu", natural_of_hex "0x10", [OAT_ULEB128] , OpSem_lit); (*1*) (* ULEB128 constant *) +("DW_OP_consts", natural_of_hex "0x11", [OAT_SLEB128] , OpSem_lit); (*1*) (* SLEB128 constant *) +("DW_OP_dup", natural_of_hex "0x12", [] , OpSem_stack (fun ac vs args -> (match vs with v::vs -> Some (v::(v::vs)) | _ -> None ))); (*0*) +("DW_OP_drop", natural_of_hex "0x13", [] , OpSem_stack (fun ac vs args -> (match vs with v::vs -> Some vs | _ -> None ))); (*0*) +("DW_OP_over", natural_of_hex "0x14", [] , OpSem_stack (fun ac vs args -> (match vs with v::v'::vs -> Some (v'::(v::(v'::vs))) | _ -> None ))); (*0*) +("DW_OP_pick", natural_of_hex "0x15", [OAT_uint8] , OpSem_stack (fun ac vs args -> (match args with [OAV_natural n] -> (match index_natural vs n with Some v -> Some (v::vs) | None -> None ) | _ -> None ))); (*1*) (* 1-byte stack index *) +("DW_OP_swap", natural_of_hex "0x16", [] , OpSem_stack (fun ac vs args -> (match vs with v::v'::vs -> Some (v'::(v::vs)) | _ -> None ))); (*0*) +("DW_OP_rot", natural_of_hex "0x17", [] , OpSem_stack (fun ac vs args -> (match vs with v::v'::v''::vs -> Some (v'::(v''::(v::vs))) | _ -> None ))); (*0*) +("DW_OP_xderef", natural_of_hex "0x18", [] , OpSem_not_supported); (*0*) +("DW_OP_abs", natural_of_hex "0x19", [] , OpSem_unary (fun ac v -> if Nat_big_num.less v ac.ac_half then Some v else if Nat_big_num.equal v ac.ac_max then None else Some (Nat_big_num.sub_nat ac.ac_all v))); (*0*) +("DW_OP_and", natural_of_hex "0x1a", [] , OpSem_binary (fun ac v1 v2 -> Some (Nat_big_num.bitwise_and v1 v2))); (*0*) +("DW_OP_div", natural_of_hex "0x1b", [] , OpSem_not_supported) (*TODO*); (*0*) +("DW_OP_minus", natural_of_hex "0x1c", [] , OpSem_binary (fun ac v1 v2 -> Some (partialNaturalFromInteger ( Nat_big_num.modulus( Nat_big_num.sub( v1) ( v2)) ( ac.ac_all))))); (*0*) +("DW_OP_mod", natural_of_hex "0x1d", [] , OpSem_binary (fun ac v1 v2 -> Some ( Nat_big_num.modulus v1 v2))); (*0*) +("DW_OP_mul", natural_of_hex "0x1e", [] , OpSem_binary (fun ac v1 v2 -> Some (partialNaturalFromInteger ( Nat_big_num.modulus( Nat_big_num.mul( v1) ( v2)) ( ac.ac_all))))); (*0*) +("DW_OP_neg", natural_of_hex "0x1f", [] , OpSem_unary (fun ac v -> if Nat_big_num.less v ac.ac_half then Some ( Nat_big_num.sub_nat ac.ac_max v) else if Nat_big_num.equal v ac.ac_half then None else Some ( Nat_big_num.sub_nat ac.ac_all v))); (*0*) +("DW_OP_not", natural_of_hex "0x20", [] , OpSem_unary (fun ac v -> Some (Nat_big_num.bitwise_xor v ac.ac_max))); (*0*) +("DW_OP_or", natural_of_hex "0x21", [] , OpSem_binary (fun ac v1 v2 -> Some (Nat_big_num.bitwise_or v1 v2))); (*0*) +("DW_OP_plus", natural_of_hex "0x22", [] , OpSem_binary (fun ac v1 v2 -> Some ( Nat_big_num.modulus( Nat_big_num.add v1 v2) ac.ac_all))); (*0*) +("DW_OP_plus_uconst", natural_of_hex "0x23", [OAT_ULEB128] , OpSem_stack (fun ac vs args -> (match args with [OAV_natural n] -> (match vs with v::vs' -> let v' = (Nat_big_num.modulus (Nat_big_num.add v n) ac.ac_all) in Some (v'::vs) | [] -> None ) | _ -> None ))); (*1*) (* ULEB128 addend *) +("DW_OP_shl", natural_of_hex "0x24", [] , OpSem_binary (fun ac v1 v2 -> if Nat_big_num.greater_equal v2 ac.ac_bitwidth then Some(Nat_big_num.of_int 0) else Some (Nat_big_num.shift_left v1 (Nat_big_num.to_int v2)))); (*0*) +("DW_OP_shr", natural_of_hex "0x25", [] , OpSem_binary (fun ac v1 v2 -> if Nat_big_num.greater_equal v2 ac.ac_bitwidth then Some(Nat_big_num.of_int 0) else Some (Nat_big_num.shift_right v1 (Nat_big_num.to_int v2)))); (*0*) +("DW_OP_shra", natural_of_hex "0x26", [] , OpSem_binary (fun ac v1 v2 -> if Nat_big_num.less v1 ac.ac_half then (if Nat_big_num.greater_equal v2 ac.ac_bitwidth then Some(Nat_big_num.of_int 0) else Some (Nat_big_num.shift_right v1 (Nat_big_num.to_int v2))) else (if Nat_big_num.greater_equal v2 ac.ac_bitwidth then Some ac.ac_max else Some ( Nat_big_num.sub_nat ac.ac_max (Nat_big_num.shift_right ( Nat_big_num.sub_nat ac.ac_max v1) (Nat_big_num.to_int v2)))))); (*0*) +("DW_OP_xor", natural_of_hex "0x27", [] , OpSem_binary (fun ac v1 v2 -> Some (Nat_big_num.bitwise_xor v1 v2))); (*0*) +("DW_OP_skip", natural_of_hex "0x2f", [OAT_sint16] , OpSem_not_supported); (*1*) (* signed 2-byte constant *) +("DW_OP_bra", natural_of_hex "0x28", [OAT_sint16] , OpSem_not_supported); (*1*) (* signed 2-byte constant *) +("DW_OP_eq", natural_of_hex "0x29", [] , OpSem_not_supported); (*0*) +("DW_OP_ge", natural_of_hex "0x2a", [] , OpSem_not_supported); (*0*) +("DW_OP_gt", natural_of_hex "0x2b", [] , OpSem_not_supported); (*0*) +("DW_OP_le", natural_of_hex "0x2c", [] , OpSem_not_supported); (*0*) +("DW_OP_lt", natural_of_hex "0x2d", [] , OpSem_not_supported); (*0*) +("DW_OP_ne", natural_of_hex "0x2e", [] , OpSem_not_supported); (*0*) +("DW_OP_lit0", natural_of_hex "0x30", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) (* literals 0..31 =(DW_OP_lit0 + literal) *) +("DW_OP_lit1", natural_of_hex "0x31", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit2", natural_of_hex "0x32", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit3", natural_of_hex "0x33", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit4", natural_of_hex "0x34", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit5", natural_of_hex "0x35", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit6", natural_of_hex "0x36", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit7", natural_of_hex "0x37", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit8", natural_of_hex "0x38", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit9", natural_of_hex "0x39", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit10", natural_of_hex "0x3a", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit11", natural_of_hex "0x3b", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit12", natural_of_hex "0x3c", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit13", natural_of_hex "0x3d", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit14", natural_of_hex "0x3e", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit15", natural_of_hex "0x3f", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit16", natural_of_hex "0x40", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit17", natural_of_hex "0x41", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit18", natural_of_hex "0x42", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit19", natural_of_hex "0x43", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit20", natural_of_hex "0x44", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit21", natural_of_hex "0x45", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit22", natural_of_hex "0x46", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit23", natural_of_hex "0x47", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit24", natural_of_hex "0x48", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit25", natural_of_hex "0x49", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit26", natural_of_hex "0x4a", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit27", natural_of_hex "0x4b", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit28", natural_of_hex "0x4c", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit29", natural_of_hex "0x4d", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit30", natural_of_hex "0x4e", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_lit31", natural_of_hex "0x4f", [] , OpSem_opcode_lit (natural_of_hex "0x30")); (*0*) +("DW_OP_reg0", natural_of_hex "0x50", [] , OpSem_reg); (*1*) (* reg 0..31 = (DW_OP_reg0 + regnum) *) +("DW_OP_reg1", natural_of_hex "0x51", [] , OpSem_reg); (*1*) +("DW_OP_reg2", natural_of_hex "0x52", [] , OpSem_reg); (*1*) +("DW_OP_reg3", natural_of_hex "0x53", [] , OpSem_reg); (*1*) +("DW_OP_reg4", natural_of_hex "0x54", [] , OpSem_reg); (*1*) +("DW_OP_reg5", natural_of_hex "0x55", [] , OpSem_reg); (*1*) +("DW_OP_reg6", natural_of_hex "0x56", [] , OpSem_reg); (*1*) +("DW_OP_reg7", natural_of_hex "0x57", [] , OpSem_reg); (*1*) +("DW_OP_reg8", natural_of_hex "0x58", [] , OpSem_reg); (*1*) +("DW_OP_reg9", natural_of_hex "0x59", [] , OpSem_reg); (*1*) +("DW_OP_reg10", natural_of_hex "0x5a", [] , OpSem_reg); (*1*) +("DW_OP_reg11", natural_of_hex "0x5b", [] , OpSem_reg); (*1*) +("DW_OP_reg12", natural_of_hex "0x5c", [] , OpSem_reg); (*1*) +("DW_OP_reg13", natural_of_hex "0x5d", [] , OpSem_reg); (*1*) +("DW_OP_reg14", natural_of_hex "0x5e", [] , OpSem_reg); (*1*) +("DW_OP_reg15", natural_of_hex "0x5f", [] , OpSem_reg); (*1*) +("DW_OP_reg16", natural_of_hex "0x60", [] , OpSem_reg); (*1*) +("DW_OP_reg17", natural_of_hex "0x61", [] , OpSem_reg); (*1*) +("DW_OP_reg18", natural_of_hex "0x62", [] , OpSem_reg); (*1*) +("DW_OP_reg19", natural_of_hex "0x63", [] , OpSem_reg); (*1*) +("DW_OP_reg20", natural_of_hex "0x64", [] , OpSem_reg); (*1*) +("DW_OP_reg21", natural_of_hex "0x65", [] , OpSem_reg); (*1*) +("DW_OP_reg22", natural_of_hex "0x66", [] , OpSem_reg); (*1*) +("DW_OP_reg23", natural_of_hex "0x67", [] , OpSem_reg); (*1*) +("DW_OP_reg24", natural_of_hex "0x68", [] , OpSem_reg); (*1*) +("DW_OP_reg25", natural_of_hex "0x69", [] , OpSem_reg); (*1*) +("DW_OP_reg26", natural_of_hex "0x6a", [] , OpSem_reg); (*1*) +("DW_OP_reg27", natural_of_hex "0x6b", [] , OpSem_reg); (*1*) +("DW_OP_reg28", natural_of_hex "0x6c", [] , OpSem_reg); (*1*) +("DW_OP_reg29", natural_of_hex "0x6d", [] , OpSem_reg); (*1*) +("DW_OP_reg30", natural_of_hex "0x6e", [] , OpSem_reg); (*1*) +("DW_OP_reg31", natural_of_hex "0x6f", [] , OpSem_reg); (*1*) +("DW_OP_breg0", natural_of_hex "0x70", [OAT_SLEB128] , OpSem_breg); (*1*) (* base register 0..31 = (DW_OP_breg0 + regnum) *) +("DW_OP_breg1", natural_of_hex "0x71", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg2", natural_of_hex "0x72", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg3", natural_of_hex "0x73", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg4", natural_of_hex "0x74", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg5", natural_of_hex "0x75", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg6", natural_of_hex "0x76", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg7", natural_of_hex "0x77", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg8", natural_of_hex "0x78", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg9", natural_of_hex "0x79", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg10", natural_of_hex "0x7a", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg11", natural_of_hex "0x7b", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg12", natural_of_hex "0x7c", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg13", natural_of_hex "0x7d", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg14", natural_of_hex "0x7e", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg15", natural_of_hex "0x7f", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg16", natural_of_hex "0x80", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg17", natural_of_hex "0x81", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg18", natural_of_hex "0x82", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg19", natural_of_hex "0x83", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg20", natural_of_hex "0x84", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg21", natural_of_hex "0x85", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg22", natural_of_hex "0x86", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg23", natural_of_hex "0x87", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg24", natural_of_hex "0x88", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg25", natural_of_hex "0x89", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg26", natural_of_hex "0x8a", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg27", natural_of_hex "0x8b", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg28", natural_of_hex "0x8c", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg29", natural_of_hex "0x8d", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg30", natural_of_hex "0x8e", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_breg31", natural_of_hex "0x8f", [OAT_SLEB128] , OpSem_breg); (*1*) +("DW_OP_regx", natural_of_hex "0x90", [OAT_ULEB128] , OpSem_lit); (*1*) (* ULEB128 register *) +("DW_OP_fbreg", natural_of_hex "0x91", [OAT_SLEB128] , OpSem_fbreg); (*1*) (* SLEB128 offset *) +("DW_OP_bregx", natural_of_hex "0x92", [OAT_ULEB128; OAT_SLEB128] , OpSem_bregx); (*2*) (* ULEB128 register followed by SLEB128 offset *) +("DW_OP_piece", natural_of_hex "0x93", [OAT_ULEB128] , OpSem_piece); (*1*) (* ULEB128 size of piece addressed *) +("DW_OP_deref_size", natural_of_hex "0x94", [OAT_uint8] , OpSem_deref_size); (*1*) (* 1-byte size of data retrieved *) +("DW_OP_xderef_size", natural_of_hex "0x95", [OAT_uint8] , OpSem_not_supported); (*1*) (* 1-byte size of data retrieved *) +("DW_OP_nop", natural_of_hex "0x96", [] , OpSem_nop); (*0*) +("DW_OP_push_object_address", natural_of_hex "0x97", [] , OpSem_not_supported); (*0*) +("DW_OP_call2", natural_of_hex "0x98", [OAT_uint16] , OpSem_not_supported); (*1*) (* 2-byte offset of DIE *) +("DW_OP_call4", natural_of_hex "0x99", [OAT_uint32] , OpSem_not_supported); (*1*) (* 4-byte offset of DIE *) +("DW_OP_call_ref", natural_of_hex "0x9a", [OAT_dwarf_format_t] , OpSem_not_supported); (*1*) (* 4- or 8-byte offset of DIE *) +("DW_OP_form_tls_address", natural_of_hex "0x9b", [] , OpSem_not_supported); (*0*) +("DW_OP_call_frame_cfa", natural_of_hex "0x9c", [] , OpSem_call_frame_cfa); (*0*) +("DW_OP_bit_piece", natural_of_hex "0x9d", [OAT_ULEB128; OAT_ULEB128] , OpSem_bit_piece); (*2*) (* ULEB128 size followed by ULEB128 offset *) +("DW_OP_implicit_value", natural_of_hex "0x9e", [OAT_block] , OpSem_implicit_value); (*2*) (* ULEB128 size followed by block of that size *) +("DW_OP_stack_value", natural_of_hex "0x9f", [] , OpSem_stack_value); (*0*) +(* these aren't real operations +("DW_OP_lo_user", natural_of_hex "0xe0", [] , ); +("DW_OP_hi_user", natural_of_hex "0xff", [] , ); +*) + +(* GCC also produces these for our example: +https://fedorahosted.org/elfutils/wiki/DwarfExtensions +http://dwarfstd.org/ShowIssue.php?issue=100909.1 *) +("DW_GNU_OP_entry_value", natural_of_hex "0xf3", [OAT_block], OpSem_not_supported); (*2*) (* ULEB128 size followed by DWARF expression block of that size*) +("DW_OP_GNU_implicit_pointer", natural_of_hex "0xf2", [OAT_dwarf_format_t;OAT_SLEB128], OpSem_not_supported) + +]) + + +let vDW_OP_reg0:Nat_big_num.num= (natural_of_hex "0x50") +let vDW_OP_breg0:Nat_big_num.num= (natural_of_hex "0x70") + + +(* call frame instruction encoding *) + +let call_frame_instruction_encoding : (string * Nat_big_num.num * Nat_big_num.num * call_frame_argument_type list * (( call_frame_argument_value list) -> call_frame_instruction option)) list= ([ +(* high-order 2 bits low-order 6 bits uniformly parsed arguments *) + +(* instructions using low-order 6 bits for first argument *) +(* +("DW_CFA_advance_loc", 1, 0,(*delta *) []); +("DW_CFA_offset", 2, 0,(*register*) [CFAT_offset]); +("DW_CFA_restore", 3, 0,(*register*) []); +*) +(* instructions using low-order 6 bits as part of opcode *) +("DW_CFA_nop",Nat_big_num.of_int 0, natural_of_hex "0x00", [], +( (* *)fun avs -> (match avs with [] -> Some (DW_CFA_nop) | _ -> None ))); +("DW_CFA_set_loc",Nat_big_num.of_int 0, natural_of_hex "0x01", [CFAT_address], +( (* address *)fun avs -> (match avs with [CFAV_address a] -> Some (DW_CFA_set_loc a) | _ -> None ))); +("DW_CFA_advance_loc1",Nat_big_num.of_int 0, natural_of_hex "0x02", [CFAT_delta1], +( (* 1-byte delta *)fun avs -> (match avs with [CFAV_delta d] -> Some (DW_CFA_advance_loc1 d) | _ -> None ))); +("DW_CFA_advance_loc2",Nat_big_num.of_int 0, natural_of_hex "0x03", [CFAT_delta2], +( (* 2-byte delta *)fun avs -> (match avs with [CFAV_delta d] -> Some (DW_CFA_advance_loc2 d) | _ -> None ))); +("DW_CFA_advance_loc4",Nat_big_num.of_int 0, natural_of_hex "0x04", [CFAT_delta4], +( (* 4-byte delta *)fun avs -> (match avs with [CFAV_delta d] -> Some (DW_CFA_advance_loc4 d) | _ -> None ))); +("DW_CFA_offset_extended",Nat_big_num.of_int 0, natural_of_hex "0x05", [CFAT_register; CFAT_offset], +( (* ULEB128 register ULEB128 offset *)fun avs -> (match avs with [CFAV_register r; CFAV_offset n] -> Some (DW_CFA_offset_extended( r, n)) | _ -> None ))); +("DW_CFA_restore_extended",Nat_big_num.of_int 0, natural_of_hex "0x06", [CFAT_register], +( (* ULEB128 register *)fun avs -> (match avs with [CFAV_register r] -> Some (DW_CFA_restore_extended r) | _ -> None ))); +("DW_CFA_undefined",Nat_big_num.of_int 0, natural_of_hex "0x07", [CFAT_register], +( (* ULEB128 register *)fun avs -> (match avs with [CFAV_register r] -> Some (DW_CFA_undefined r) | _ -> None ))); +("DW_CFA_same_value",Nat_big_num.of_int 0, natural_of_hex "0x08", [CFAT_register], +( (* ULEB128 register *)fun avs -> (match avs with [CFAV_register r] -> Some (DW_CFA_same_value r) | _ -> None ))); +("DW_CFA_register",Nat_big_num.of_int 0, natural_of_hex "0x09", [CFAT_register; CFAT_register], +( (* ULEB128 register ULEB128 register *)fun avs -> (match avs with [CFAV_register r1; CFAV_register r2] -> Some (DW_CFA_register( r1, r2)) | _ -> None ))); +("DW_CFA_remember_state",Nat_big_num.of_int 0, natural_of_hex "0x0a", [], +( (* *)fun avs -> (match avs with [] -> Some (DW_CFA_remember_state) | _ -> None ))); +("DW_CFA_restore_state",Nat_big_num.of_int 0, natural_of_hex "0x0b", [], +( (* *)fun avs -> (match avs with [] -> Some (DW_CFA_restore_state) | _ -> None ))); +("DW_CFA_def_cfa",Nat_big_num.of_int 0, natural_of_hex "0x0c", [CFAT_register; CFAT_offset], +( (* ULEB128 register ULEB128 offset *)fun avs -> (match avs with [CFAV_register r; CFAV_offset n] -> Some (DW_CFA_def_cfa( r, n)) | _ -> None ))); +("DW_CFA_def_cfa_register",Nat_big_num.of_int 0, natural_of_hex "0x0d", [CFAT_register], +( (* ULEB128 register *)fun avs -> (match avs with [CFAV_register r] -> Some (DW_CFA_def_cfa_register r) | _ -> None ))); +("DW_CFA_def_cfa_offset",Nat_big_num.of_int 0, natural_of_hex "0x0e", [CFAT_offset], +( (* ULEB128 offset *)fun avs -> (match avs with [CFAV_offset n] -> Some (DW_CFA_def_cfa_offset n) | _ -> None ))); +("DW_CFA_def_cfa_expression",Nat_big_num.of_int 0, natural_of_hex "0x0f", [CFAT_block], +( (* BLOCK *)fun avs -> (match avs with [CFAV_block b] -> Some (DW_CFA_def_cfa_expression b) | _ -> None ))); +("DW_CFA_expression",Nat_big_num.of_int 0, natural_of_hex "0x10", [CFAT_register; CFAT_block], +( (* ULEB128 register BLOCK *)fun avs -> (match avs with [CFAV_register r; CFAV_block b] -> Some (DW_CFA_expression( r, b)) | _ -> None ))); +("DW_CFA_offset_extended_sf",Nat_big_num.of_int 0, natural_of_hex "0x11", [CFAT_register; CFAT_sfoffset], +( (* ULEB128 register SLEB128 offset *)fun avs -> (match avs with [CFAV_register r; CFAV_sfoffset i] -> Some (DW_CFA_offset_extended_sf( r, i)) | _ -> None ))); +("DW_CFA_def_cfa_sf",Nat_big_num.of_int 0, natural_of_hex "0x12", [CFAT_register; CFAT_sfoffset], +( (* ULEB128 register SLEB128 offset *)fun avs -> (match avs with [CFAV_register r; CFAV_sfoffset i] -> Some (DW_CFA_def_cfa_sf( r, i)) | _ -> None ))); +("DW_CFA_def_cfa_offset_sf",Nat_big_num.of_int 0, natural_of_hex "0x13", [CFAT_sfoffset], +( (* SLEB128 offset *)fun avs -> (match avs with [CFAV_sfoffset i] -> Some (DW_CFA_def_cfa_offset_sf i) | _ -> None ))); +("DW_CFA_val_offset",Nat_big_num.of_int 0, natural_of_hex "0x14", [CFAT_register; CFAT_offset], +( (* ULEB128 ULEB128 *)fun avs -> (match avs with [CFAV_register r; CFAV_offset n] -> Some (DW_CFA_val_offset( r, n)) | _ -> None ))); +("DW_CFA_val_offset_sf",Nat_big_num.of_int 0, natural_of_hex "0x15", [CFAT_register; CFAT_sfoffset], +( (* ULEB128 SLEB128 *)fun avs -> (match avs with [CFAV_register r; CFAV_sfoffset i] -> Some (DW_CFA_val_offset_sf( r, i)) | _ -> None ))); +("DW_CFA_val_expression",Nat_big_num.of_int 0, natural_of_hex "0x16", [CFAT_register; CFAT_block], +( (* ULEB128 BLOCK *)fun avs -> (match avs with [CFAV_register r; CFAV_block b] -> Some (DW_CFA_val_expression( r, b)) | _ -> None ))) +]) + +(* +("DW_CFA_lo_user", 0, natural_of_hex "0x1c", []); (* *) +("DW_CFA_hi_user", 0, natural_of_hex "0x3f", []); (* *) +*) + + +(* line number encodings *) + +let line_number_standard_encodings:(string*Nat_big_num.num*(line_number_argument_type)list*((line_number_argument_value)list ->(line_number_operation)option))list= ([ + ("DW_LNS_copy" , natural_of_hex "0x01", [ ], + (fun lnvs -> (match lnvs with [] -> Some DW_LNS_copy | _ -> None ))); + ("DW_LNS_advance_pc" , natural_of_hex "0x02", [LNAT_ULEB128 ], + (fun lnvs -> (match lnvs with [LNAV_ULEB128 n] -> Some (DW_LNS_advance_pc n) | _ -> None ))); + ("DW_LNS_advance_line" , natural_of_hex "0x03", [LNAT_SLEB128 ], + (fun lnvs -> (match lnvs with [LNAV_SLEB128 i] -> Some (DW_LNS_advance_line i) | _ -> None ))); + ("DW_LNS_set_file" , natural_of_hex "0x04", [LNAT_ULEB128 ], + (fun lnvs -> (match lnvs with [LNAV_ULEB128 n] -> Some (DW_LNS_set_file n) | _ -> None ))); + ("DW_LNS_set_column" , natural_of_hex "0x05", [LNAT_ULEB128 ], + (fun lnvs -> (match lnvs with [LNAV_ULEB128 n] -> Some (DW_LNS_set_column n) | _ -> None ))); + ("DW_LNS_negate_stmt" , natural_of_hex "0x06", [ ], + (fun lnvs -> (match lnvs with [] -> Some (DW_LNS_negate_stmt) | _ -> None ))); + ("DW_LNS_set_basic_block" , natural_of_hex "0x07", [ ], + (fun lnvs -> (match lnvs with [] -> Some (DW_LNS_set_basic_block) | _ -> None ))); + ("DW_LNS_const_add_pc" , natural_of_hex "0x08", [ ], + (fun lnvs -> (match lnvs with [] -> Some (DW_LNS_const_add_pc) | _ -> None ))); + ("DW_LNS_fixed_advance_pc" , natural_of_hex "0x09", [LNAT_uint16 ], + (fun lnvs -> (match lnvs with [LNAV_uint16 n] -> Some (DW_LNS_fixed_advance_pc n) | _ -> None ))); + ("DW_LNS_set_prologue_end" , natural_of_hex "0x0a", [ ], +(fun lnvs -> (match lnvs with [] -> Some (DW_LNS_set_prologue_end) | _ -> None ))); + ("DW_LNS_set_epilogue_begin" , natural_of_hex "0x0b", [ ], +(fun lnvs -> (match lnvs with [] -> Some (DW_LNS_set_epilogue_begin) | _ -> None ))); + ("DW_LNS_set_isa" , natural_of_hex "0x0c", [LNAT_ULEB128 ], + (fun lnvs -> (match lnvs with [LNAV_ULEB128 n] -> Some (DW_LNS_set_isa n) | _ -> None ))) +]) + +let line_number_extended_encodings:(string*Nat_big_num.num*(line_number_argument_type)list*((line_number_argument_value)list ->(line_number_operation)option))list= ([ + ("DW_LNE_end_sequence" , natural_of_hex "0x01", [], + (fun lnvs -> (match lnvs with [] -> Some (DW_LNE_end_sequence) | _ -> None ))); + ("DW_LNE_set_address" , natural_of_hex "0x02", [LNAT_address], + (fun lnvs -> (match lnvs with [LNAV_address n] -> Some (DW_LNE_set_address n) | _ -> None ))); + ("DW_LNE_define_file" , natural_of_hex "0x03", [LNAT_string; LNAT_ULEB128; LNAT_ULEB128; LNAT_ULEB128], + (fun lnvs -> (match lnvs with [LNAV_string s; LNAV_ULEB128 n1; LNAV_ULEB128 n2; LNAV_ULEB128 n3] -> Some (DW_LNE_define_file( s, n1, n2, n3)) | _ -> None ))); + ("DW_LNE_set_discriminator" , natural_of_hex "0x04", [LNAT_ULEB128], + (fun lnvs -> (match lnvs with [LNAV_ULEB128 n] -> Some (DW_LNE_set_discriminator n) | _ -> None ))) (* new in Dwarf 4*) +]) + + +(* +(DW_LNE_lo_user , natural_of_hex "0x80", "DW_LNE_lo_user"); +(DW_LNE_hi_user , natural_of_hex "0xff", "DW_LNE_hi_user"); +*) + + + +(* booleans encoded as a single byte containing the value 0 for âfalse,â and a non-zero value for âtrue.â *) + + +(** ************************************************************ *) +(** ** more missing pervasives and bits *********************** *) +(** ************************************************************ *) + + +(* quick hacky workaround: this is in String.lem, in src_lem_library, but the linker doesn't find it *) +(*val myconcat : string -> list string -> string*) +let rec myconcat sep ss:string= + ((match ss with + | [] -> "" + | s :: ss' -> + (match ss' with + | [] -> s + | _ -> s ^ (sep ^ myconcat sep ss') + ) + )) + +(*val myhead : forall 'a. list 'a -> 'a*) +let myhead l:'a= ((match l with | x::xs -> x | [] -> failwith "myhead of empty list" )) + + +(*val myfindNonPure : forall 'a. ('a -> bool) -> list 'a -> 'a*) +let myfindNonPure p0 l:'a= ((match (Lem_list.list_find_opt p0 l) with + | Some e -> e + | None -> failwith "myfindNonPure" +)) + +(*val myfindmaybe : forall 'a 'b. ('a -> maybe 'b) -> list 'a -> maybe 'b*) +let rec myfindmaybe f xs:'b option= + ((match xs with + | [] -> None + | x::xs' -> (match f x with Some y -> Some y | None -> myfindmaybe f xs' ) + )) + +(*val myfind : forall 'a. ('a -> bool) -> list 'a -> maybe 'a*) +let rec myfind f xs:'a option= + ((match xs with + | [] -> None + | x::xs' -> (match f x with true -> Some x | false -> myfind f xs' ) + )) + +(*val myfiltermaybe : forall 'a 'b. ('a -> maybe 'b) -> list 'a -> list 'b*) +let rec myfiltermaybe f xs:'b list= + ((match xs with + | [] -> [] + | x::xs' -> (match f x with Some y -> y::myfiltermaybe f xs'| None -> myfiltermaybe f xs' ) + )) + + + +(*val bytes_of_natural: endianness -> natural (*size*) -> natural (*value*) -> list byte*) +let bytes_of_natural en size2 n:(char)list= + (if Nat_big_num.equal size2(Nat_big_num.of_int 8) then + bytes_of_elf64_xword en (Uint64.of_string (Nat_big_num.to_string n)) + else if Nat_big_num.equal size2(Nat_big_num.of_int 4) then + bytes_of_elf32_word en (Uint32.of_string (Nat_big_num.to_string n)) + else + failwith "bytes_of_natural given size that is not 4 or 8") + +(* TODO: generalise *) +(*val natural_of_bytes: endianness -> list byte -> natural*) +let natural_of_bytes en bs:Nat_big_num.num= + ((match bs with + | b0::b1::b2::b3::b4::b5::b6::b7::[] -> + let v = (if en=Little then + Nat_big_num.add (Nat_big_num.add (Nat_big_num.add (Nat_big_num.add + (natural_of_byte b0)(Nat_big_num.mul(Nat_big_num.of_int 256)(natural_of_byte b1)))(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(natural_of_byte b2)))(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(natural_of_byte b3))) (Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))( Nat_big_num.add (Nat_big_num.add (Nat_big_num.add(natural_of_byte b4)(Nat_big_num.mul(Nat_big_num.of_int 256)(natural_of_byte b5)))(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(natural_of_byte b6)))(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(natural_of_byte b7)))) + else + Nat_big_num.add (Nat_big_num.add (Nat_big_num.add (Nat_big_num.add +(natural_of_byte b7)(Nat_big_num.mul(Nat_big_num.of_int 256)(natural_of_byte b6)))(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(natural_of_byte b5)))(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(natural_of_byte b4))) (Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))( Nat_big_num.add (Nat_big_num.add (Nat_big_num.add(natural_of_byte b3)(Nat_big_num.mul(Nat_big_num.of_int 256)(natural_of_byte b2)))(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(natural_of_byte b1)))(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(natural_of_byte b0))))) + in + v + | b0::b1::b2::b3::[] -> + let v = (if en=Little then Nat_big_num.add (Nat_big_num.add (Nat_big_num.add + (natural_of_byte b0)(Nat_big_num.mul(Nat_big_num.of_int 256)(natural_of_byte b1)))(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(natural_of_byte b2)))(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(natural_of_byte b3)) + else Nat_big_num.add (Nat_big_num.add (Nat_big_num.add +(natural_of_byte b3)(Nat_big_num.mul(Nat_big_num.of_int 256)(natural_of_byte b2)))(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(natural_of_byte b1)))(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(natural_of_byte b0))) + + in + v + | b0::b1::[] -> + let v = (if en=Little then Nat_big_num.add + (natural_of_byte b0)(Nat_big_num.mul(Nat_big_num.of_int 256)(natural_of_byte b1)) + else Nat_big_num.add +(natural_of_byte b1)(Nat_big_num.mul(Nat_big_num.of_int 256)(natural_of_byte b0))) + + in + v + | b0::[] -> + natural_of_byte b0 + | _ -> failwith "natural_of_bytes given not-8/4/2/1 bytes" + )) + + +(*val bigunionListMap : forall 'a 'b. SetType 'b => ('a -> set 'b) -> list 'a -> set 'b*) +let rec bigunionListMap dict_Basic_classes_SetType_b f xs:'b Pset.set= + ((match xs with + | [] ->(Pset.from_list + dict_Basic_classes_SetType_b.setElemCompare_method []) + | x::xs' -> Pset.(union) (f x) (bigunionListMap + dict_Basic_classes_SetType_b f xs') + )) + +let rec mytake' (n:Nat_big_num.num) acc xs:('a list*'a list)option= + ( + if(Nat_big_num.equal n (Nat_big_num.of_int 0)) then + (Some (List.rev acc, xs)) else + ((match xs with + [] -> None + | x::xs' -> mytake' (Nat_big_num.sub_nat n (Nat_big_num.of_int 1)) + (x :: acc) xs' + ))) + +(*val mytake : forall 'a. natural -> (list 'a) -> maybe (list 'a * list 'a)*) +let mytake n xs:('a list*'a list)option= (mytake' n [] xs) + +(*val mynth : forall 'a. natural -> (list 'a) -> maybe 'a*) +let rec mynth (n:Nat_big_num.num) xs:'a option= + ( (*Assert_extra.failwith "mynth"*) + if(Nat_big_num.equal n (Nat_big_num.of_int 0)) then + ((match xs with x::xs' -> Some x | [] -> None )) else + ((match xs with + x::xs' -> mynth (Nat_big_num.sub_nat n (Nat_big_num.of_int 1)) xs' + ))) + + +(** basic pretty printing *) + +let pphex n:string= ("0x" ^ unsafe_hex_string_of_natural( 0) n) + +let ppbytes dict_Show_Show_a xs:string= (string_of_list + instance_Show_Show_string_dict (Lem_list.map (fun x -> + dict_Show_Show_a.show_method x) xs)) + +let rec ppbytes2 dict_Show_Show_a n xs:string= ((match xs with | [] -> "" | x::xs' -> "<"^(pphex n^("> "^( + dict_Show_Show_a.show_method x^("\n"^ppbytes2 dict_Show_Show_a (Nat_big_num.add n(Nat_big_num.of_int 1)) xs')))) )) + +(* workaround: from String *) +(*val mytoString : list char -> string*) + +let string_of_bytes bs:string= (Xstring.implode (Lem_list.map (fun x-> x) bs)) + + +let just_one s xs:'a= + ((match xs with + | [] -> failwith ("no " ^ s) + | x1::x2::_ -> failwith ("more than one " ^ s) + | [x] -> x + )) + + + + +let max_address (as': Nat_big_num.num) : Nat_big_num.num= + ( + if(Nat_big_num.equal as' (Nat_big_num.of_int 4)) then + (natural_of_hex "0xffffffff") else + ( + if(Nat_big_num.equal as' (Nat_big_num.of_int 8)) then + (natural_of_hex "0xffffffffffffffff") else + (failwith "max_address size not 4 or 8"))) + + +(** lookup of encodings *) + +(*val lookup_Ab_b : forall 'a 'b. Eq 'a => 'a -> list ('a * 'b) -> maybe 'b*) +let rec lookup_Ab_b dict_Basic_classes_Eq_a x0 xys:'b option= + ((match xys with + | [] -> None + | (x,y)::xys' -> if + dict_Basic_classes_Eq_a.isEqual_method x x0 then Some y else lookup_Ab_b + dict_Basic_classes_Eq_a x0 xys' + )) + +(*val lookup_aB_a : forall 'a 'b. Eq 'b => 'b -> list ('a * 'b) -> maybe 'a*) +let rec lookup_aB_a dict_Basic_classes_Eq_b y0 xys:'a option= + ((match xys with + | [] -> None + | (x,y)::xys' -> if + dict_Basic_classes_Eq_b.isEqual_method y y0 then Some x else lookup_aB_a + dict_Basic_classes_Eq_b y0 xys' + )) + + +(*val lookup_aBc_a : forall 'a 'b 'c. Eq 'b => 'b -> list ('a * 'b * 'c) -> maybe 'a*) +let rec lookup_aBc_a dict_Basic_classes_Eq_b y0 xyzs:'a option= + ((match xyzs with + | [] -> None + | (x,y,_)::xyzs' -> if + dict_Basic_classes_Eq_b.isEqual_method y y0 then Some x else lookup_aBc_a + dict_Basic_classes_Eq_b y0 xyzs' + )) + +(*val lookup_aBc_ac : forall 'a 'b 'c. Eq 'b => 'b -> list ('a * 'b * 'c) -> maybe ('a*'c)*) +let rec lookup_aBc_ac dict_Basic_classes_Eq_b y0 xyzs:('a*'c)option= + ((match xyzs with + | [] -> None + | (x,y,z)::xyzs' -> if + dict_Basic_classes_Eq_b.isEqual_method y y0 then Some (x,z) else lookup_aBc_ac + dict_Basic_classes_Eq_b y0 xyzs' + )) + +(*val lookup_Abc_b : forall 'a 'b 'c. Eq 'a => 'a -> list ('a * 'b * 'c) -> maybe 'b*) +let rec lookup_Abc_b dict_Basic_classes_Eq_a x0 xyzs:'b option= + ((match xyzs with + | [] -> None + | (x,y,_)::xyzs' -> if + dict_Basic_classes_Eq_a.isEqual_method x x0 then Some y else lookup_Abc_b + dict_Basic_classes_Eq_a x0 xyzs' + )) + + + +(*val lookup_aBcd_a : forall 'a 'b 'c 'd. Eq 'b => 'b -> list ('a * 'b * 'c * 'd) -> maybe 'a*) +let rec lookup_aBcd_a dict_Basic_classes_Eq_b y0 xyzws:'a option= + ((match xyzws with + | [] -> None + | (x,y,_,_)::xyzws' -> if + dict_Basic_classes_Eq_b.isEqual_method y y0 then Some x else lookup_aBcd_a + dict_Basic_classes_Eq_b y0 xyzws' + )) + +(*val lookup_aBcd_acd : forall 'a 'b 'c 'd. Eq 'b => 'b -> list ('a * 'b * 'c * 'd) -> maybe ('a * 'c * 'd)*) +let rec lookup_aBcd_acd dict_Basic_classes_Eq_b y0 xyzws:('a*'c*'d)option= + ((match xyzws with + | [] -> None + | (x,y,z,w)::xyzws' -> if + dict_Basic_classes_Eq_b.isEqual_method y y0 then Some (x,z,w) else lookup_aBcd_acd + dict_Basic_classes_Eq_b y0 xyzws' + )) + +(*val lookup_abCde_de : forall 'a 'b 'c 'd 'e. Eq 'c => 'c -> list ('a * 'b * 'c * 'd * 'e) -> maybe ('d * 'e)*) +let rec lookup_abCde_de dict_Basic_classes_Eq_c z0 xyzwus:('d*'e)option= + ((match xyzwus with + | [] -> None + | (x,y,z,w,u)::xyzwus' -> if + dict_Basic_classes_Eq_c.isEqual_method z z0 then Some (w,u) else lookup_abCde_de + dict_Basic_classes_Eq_c z0 xyzwus' + )) + + +let pp_maybe ppf n:string= ((match ppf n with Some s -> s | None -> "encoding not found: " ^ pphex n )) + +let pp_tag_encoding n:string= (pp_maybe (fun n -> lookup_aB_a + instance_Basic_classes_Eq_Num_natural_dict n tag_encodings) n) +let pp_attribute_encoding n:string= (pp_maybe (fun n -> lookup_aBc_a + instance_Basic_classes_Eq_Num_natural_dict n attribute_encodings) n) +let pp_attribute_form_encoding n:string= (pp_maybe (fun n -> lookup_aBc_a + instance_Basic_classes_Eq_Num_natural_dict n attribute_form_encodings) n) +let pp_operation_encoding n:string= (pp_maybe (fun n -> lookup_aBcd_a + instance_Basic_classes_Eq_Num_natural_dict n operation_encodings) n) + +let tag_encode (s: string) : Nat_big_num.num= + ((match lookup_Ab_b + instance_Basic_classes_Eq_string_dict s tag_encodings with + | Some n -> n + | None -> failwith "attribute_encode" + )) + + +let attribute_encode (s: string) : Nat_big_num.num= + ((match lookup_Abc_b + instance_Basic_classes_Eq_string_dict s attribute_encodings with + | Some n -> n + | None -> failwith "attribute_encode" + )) + +let attribute_form_encode (s: string) : Nat_big_num.num= + ((match lookup_Abc_b + instance_Basic_classes_Eq_string_dict s attribute_form_encodings with + | Some n -> n + | None -> failwith "attribute_form_encode" + )) + + + +(** ************************************************************ *) +(** ** parser combinators and primitives ********************* *) +(** ************************************************************ *) + +(* parsing combinators *) + +type parse_context = { pc_bytes: char list; pc_offset: Nat_big_num.num } + +type 'a parse_result = + | PR_success of 'a * parse_context + | PR_fail of string * parse_context + +type 'a parser = parse_context -> 'a parse_result + +let pp_parse_context pc:string= ("pc_offset = " ^ pphex pc.pc_offset) + +let pp_parse_fail s pc:string= + ("Parse fail\n" ^ (s ^ (" at " ^ (pp_parse_context pc ^ "\n")))) + +let pp_parse_result ppa pr:string= + ((match pr with + | PR_success( x, pc) -> "Parse success\n" ^ (ppa x ^ ("\n" ^ (pp_parse_context pc ^ "\n"))) + | PR_fail( s, pc) -> pp_parse_fail s pc + )) + +(* [(>>=)] should be the monadic binding function for [parse_result]. *) +(* but there's a type clash if we use >>=, and lem seems to output bad ocaml for >>>=. So we just use a non-infix version for now *) + +(*val pr_bind : forall 'a 'b. parse_result 'a -> ('a -> parser 'b) -> parse_result 'b*) +let pr_bind x f:'b parse_result= + ((match x with + | PR_success( v, pc) -> f v pc + | PR_fail( err, pc) -> PR_fail( err, pc) + )) + +(*val pr_return : forall 'a. 'a -> (parser 'a)*) +let pr_return x pc:'a parse_result= (PR_success( x, pc)) + +(*val pr_map : forall 'a 'b. ('a -> 'b) -> parse_result 'a -> parse_result 'b*) +let pr_map f x:'b parse_result= + ((match x with + | PR_success( v, pc) -> PR_success( (f v), pc) + | PR_fail( err, pc) -> PR_fail( err, pc) + )) + +(*val pr_map2 : forall 'a 'b. ('a -> 'b) -> (parser 'a) -> (parser 'b)*) +let pr_map2 f p:parse_context ->'b parse_result= (fun pc -> pr_map f (p pc)) + +(*val pr_post_map1 : forall 'a 'b. (parse_result 'a) -> ('a -> 'b) -> (parse_result 'b)*) +let pr_post_map1 x f:'b parse_result= (pr_map f x) + +(* +val pr_post_map : forall 'a 'b 'c. ('c -> parse_result 'a) -> ('a -> 'b) -> ('c -> parse_result 'b) +let pr_post_map g f = fun x -> pr_map f (g x) +*) +(*val pr_post_map : forall 'a 'b. (parser 'a) -> ('a -> 'b) -> (parser 'b)*) +let pr_post_map p f:parse_context ->'b parse_result= (fun (pc: parse_context) -> pr_map f (p pc)) + + +(*val pr_with_pos : forall 'a. (parser 'a) -> (parser (natural * 'a))*) +let pr_with_pos p:parse_context ->(Nat_big_num.num*'a)parse_result= (fun pc -> pr_map (fun x -> (pc.pc_offset,x)) (p pc)) + + +(*val parse_pair : forall 'a 'b. (parser 'a) -> (parser 'b) -> (parser ('a * 'b))*) +let parse_pair p1 p2:parse_context ->('a*'b)parse_result= + (fun pc -> + let _ = (my_debug "pair ") in + pr_bind (p1 pc) (fun x pc' -> (match p2 pc' with + | PR_success( y, pc'') -> PR_success( (x,y), pc'') + | PR_fail( s, pc'') -> PR_fail( s, pc'') + ))) + +(*val parse_triple : forall 'a 'b 'c. (parser 'a) -> (parser 'b) -> (parser 'c) -> parser ('a * ('b * 'c))*) +let parse_triple p1 p2 p3:parse_context ->('a*('b*'c))parse_result= + (parse_pair p1 (parse_pair p2 p3)) + +(*val parse_quadruple : forall 'a 'b 'c 'd. (parser 'a) -> (parser 'b) -> (parser 'c) -> (parser 'd) -> parser ('a * ('b * ('c * 'd)))*) +let parse_quadruple p1 p2 p3 p4:parse_context ->('a*('b*('c*'d)))parse_result= + (parse_pair p1 (parse_pair p2 (parse_pair p3 p4))) + +(*val parse_pentuple : forall 'a 'b 'c 'd 'e. (parser 'a) -> (parser 'b) -> (parser 'c) -> (parser 'd) -> (parser 'e) -> parser ('a * ('b * ('c * ('d * 'e))))*) +let parse_pentuple p1 p2 p3 p4 p5:parse_context ->('a*('b*('c*('d*'e))))parse_result= + (parse_pair p1 (parse_pair p2 (parse_pair p3 (parse_pair p4 p5)))) + +(*val parse_sextuple : forall 'a 'b 'c 'd 'e 'f. (parser 'a) -> (parser 'b) -> (parser 'c) -> (parser 'd) -> (parser 'e) -> (parser 'f) -> parser ('a * ('b * ('c * ('d * ('e * 'f)))))*) +let parse_sextuple p1 p2 p3 p4 p5 p6:parse_context ->('a*('b*('c*('d*('e*'f)))))parse_result= + (parse_pair p1 (parse_pair p2 (parse_pair p3 (parse_pair p4 (parse_pair p5 p6))))) + +(*val parse_dependent_pair : forall 'a 'b. (parser 'a) -> ('a -> parser 'b) -> (parser ('a * 'b))*) +let parse_dependent_pair p1 p2:parse_context ->('a*'b)parse_result= + (fun pc -> + pr_bind (p1 pc) (fun x pc' -> (match p2 x pc' with + | PR_success( y, pc'') -> PR_success( (x,y), pc'') + | PR_fail( s, pc'') -> PR_fail( s, pc'') + ))) + +(*val parse_dependent : forall 'a 'b. (parser 'a) -> ('a -> parser 'b) -> (parser 'b)*) +let parse_dependent p1 p2:parse_context ->'b parse_result= + (fun pc -> + pr_bind (p1 pc) (fun x pc' -> p2 x pc')) + + + +(*val parse_list' : forall 'a. (parser (maybe 'a)) -> (list 'a -> parser (list 'a))*) +let rec parse_list' p1:'a list ->parse_context ->('a list)parse_result= + (fun acc pc -> let _ = (my_debug "list' ") in pr_bind (p1 pc) (fun mx pc' -> + (match mx with + | None -> PR_success( acc, pc') + | Some x -> parse_list' p1 (x :: acc) pc' + ))) + +(*val parse_list : forall 'a. (parser (maybe 'a)) -> (parser (list 'a))*) +let parse_list p1:parse_context ->('a list)parse_result= + (pr_post_map + (parse_list' p1 []) + (List.rev)) + +(*val parse_parser_list : forall 'a. (list (parser 'a)) -> (parser (list 'a))*) +let rec parse_parser_list ps:parse_context ->('a list)parse_result= + ((match ps with + | [] -> pr_return [] + | p::ps' -> + (fun pc -> pr_bind (p pc) (fun x pc' -> + (match parse_parser_list ps' pc' with + | PR_success( xs, pc'') -> PR_success( (x::xs), pc'') + | PR_fail( s, pc'') -> PR_fail( s, pc'') + ))) + )) + +(*val parse_maybe : forall 'a. parser 'a -> parser (maybe 'a)*) +let parse_maybe p:parse_context ->('a option)parse_result= + (fun pc -> + (match pc.pc_bytes with + | [] -> pr_return None pc + | _ -> + (match p pc with + | PR_success( v, pc'') -> PR_success( (Some v), pc'') + | PR_fail( s, pc'') -> PR_fail( s, pc'') + ) + )) + +(*val parse_demaybe : forall 'a. string ->parser (maybe 'a) -> parser 'a*) +let parse_demaybe s p:parse_context ->'a parse_result= + (fun pc -> + (match p pc with + | PR_success( (Some v), pc'') -> PR_success( v, pc'') + | PR_success( (None), pc'') -> PR_fail( s, pc'') + | PR_fail( s, pc'') -> PR_fail( s, pc'') + + )) + + +(*val parse_restrict_length : forall 'a. natural -> parser 'a -> parser 'a*) +let parse_restrict_length n p:parse_context ->'a parse_result= + (fun pc -> + (match mytake n pc.pc_bytes with + | None -> failwith "parse_restrict_length not given enough bytes" + | Some (xs,ys) -> + let pc' = ({ pc_bytes = xs; pc_offset = (pc.pc_offset) }) in + p pc' + )) + + +(* parsing of basic types *) + + +let parse_n_bytes (n:Nat_big_num.num) : ( char list) parser= + (fun (pc:parse_context) -> + (match mytake n pc.pc_bytes with + | None -> PR_fail( ("parse_n_bytes n=" ^ pphex n), pc) + | Some (xs,bs) -> PR_success( xs, ({pc_bytes=bs; pc_offset= (Nat_big_num.add pc.pc_offset (Nat_big_num.of_int (List.length xs))) } )) + )) + +let rec mytakestring' acc xs:((char)list*(char)list)option= + ((match xs with + | [] -> None + | x::xs' -> if Nat_big_num.equal (natural_of_byte x)(Nat_big_num.of_int 0) then Some (List.rev acc, xs') else mytakestring' (x::acc) xs' + )) + +let parse_string : ( char list) parser= + (fun (pc:parse_context) -> + (match mytakestring' [] pc.pc_bytes with + | None -> PR_fail( "parse_string", pc) + | Some (xs,bs) -> PR_success( xs, ({pc_bytes=bs; pc_offset = (Nat_big_num.add (Nat_big_num.add pc.pc_offset (Nat_big_num.of_int (List.length xs))) (Nat_big_num.of_int( 1))) } )) + )) + +(* parse a null-terminated string; return Nothing if it is empty, Just s otherwise *) +let parse_non_empty_string : ( ( char list)option) parser= + (fun (pc:parse_context) -> + (match mytakestring' [] pc.pc_bytes with + | None -> PR_fail( "parse_string", pc) + | Some (xs,bs) -> + (*let _ = my_debug5 ("**" ^string_of_bytes xs ^ "**\n") in *) + let pc' = ({pc_bytes=bs; pc_offset = (Nat_big_num.add (Nat_big_num.add pc.pc_offset (Nat_big_num.of_int (List.length xs))) (Nat_big_num.of_int( 1))) } ) in + if (listEqualBy (=) xs []) then PR_success( (None), pc') + else PR_success( (Some xs), pc') + )) + + +let parse_uint8 : Nat_big_num.num parser= + (fun (pc:parse_context) -> + let _ = (my_debug "uint8 ") in + (match pc.pc_bytes with + | b0::bytes' -> + let v = (natural_of_byte b0) in + PR_success( v, ({ pc_bytes = bytes'; pc_offset = (Nat_big_num.add pc.pc_offset(Nat_big_num.of_int 1)) })) + | _ -> PR_fail( "parse_uint32 not given enough bytes", pc) + )) + +let parse_uint16 c : Nat_big_num.num parser= + (fun (pc:parse_context) -> + let _ = (my_debug "uint16 ") in + (match pc.pc_bytes with + | b0::b1::bytes' -> + let v = (if c.endianness=Little then Nat_big_num.add + (natural_of_byte b0)(Nat_big_num.mul(Nat_big_num.of_int 256)(natural_of_byte b1)) + else Nat_big_num.add + (natural_of_byte b1)(Nat_big_num.mul(Nat_big_num.of_int 256)(natural_of_byte b0))) in + PR_success( v, ({ pc_bytes = bytes'; pc_offset = (Nat_big_num.add pc.pc_offset(Nat_big_num.of_int 2)) })) + | _ -> PR_fail( "parse_uint32 not given enough bytes", pc) + )) + +let parse_uint32 c : Nat_big_num.num parser= + (fun (pc:parse_context) -> + let _ = (my_debug "uint32 ") in + (match pc.pc_bytes with + | b0::b1::b2::b3::bytes' -> + let v = (if c.endianness=Little then Nat_big_num.add (Nat_big_num.add (Nat_big_num.add + (natural_of_byte b0)(Nat_big_num.mul(Nat_big_num.of_int 256)(natural_of_byte b1)))(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(natural_of_byte b2)))(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(natural_of_byte b3)) + else Nat_big_num.add (Nat_big_num.add (Nat_big_num.add + (natural_of_byte b3)(Nat_big_num.mul(Nat_big_num.of_int 256)(natural_of_byte b2)))(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(natural_of_byte b1)))(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(natural_of_byte b0))) in + PR_success( v, ({ pc_bytes = bytes'; pc_offset = (Nat_big_num.add pc.pc_offset(Nat_big_num.of_int 4)) })) + | _ -> PR_fail( "parse_uint32 not given enough bytes", pc) + )) + +let parse_uint64 c : Nat_big_num.num parser= + (fun (pc:parse_context) -> + let _ = (my_debug "uint64 ") in + (match pc.pc_bytes with + | b0::b1::b2::b3::b4::b5::b6::b7::bytes' -> + let v = (if c.endianness=Little then + Nat_big_num.add (Nat_big_num.add (Nat_big_num.add (Nat_big_num.add + (natural_of_byte b0)(Nat_big_num.mul(Nat_big_num.of_int 256)(natural_of_byte b1)))(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(natural_of_byte b2)))(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(natural_of_byte b3))) (Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))( Nat_big_num.add (Nat_big_num.add (Nat_big_num.add(natural_of_byte b4)(Nat_big_num.mul(Nat_big_num.of_int 256)(natural_of_byte b5)))(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(natural_of_byte b6)))(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(natural_of_byte b7)))) + else + Nat_big_num.add (Nat_big_num.add (Nat_big_num.add (Nat_big_num.add +(natural_of_byte b7)(Nat_big_num.mul(Nat_big_num.of_int 256)(natural_of_byte b6)))(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(natural_of_byte b5)))(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(natural_of_byte b4))) (Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))( Nat_big_num.add (Nat_big_num.add (Nat_big_num.add(natural_of_byte b3)(Nat_big_num.mul(Nat_big_num.of_int 256)(natural_of_byte b2)))(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(natural_of_byte b1)))(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(natural_of_byte b0))))) + in + PR_success( v, ({ pc_bytes = bytes'; pc_offset = (Nat_big_num.add pc.pc_offset(Nat_big_num.of_int 8)) })) + | _ -> PR_fail( "parse_uint64 not given enough bytes", pc) + )) + +let integerFromTwosComplementNatural (n:Nat_big_num.num) (half: Nat_big_num.num) (all:Nat_big_num.num) : Nat_big_num.num= + (if Nat_big_num.less n half then n else Nat_big_num.sub ( n) all) + +let partialTwosComplementNaturalFromInteger (i:Nat_big_num.num) (half: Nat_big_num.num) (all:Nat_big_num.num) : Nat_big_num.num= + (if Nat_big_num.greater_equal i(Nat_big_num.of_int 0) && Nat_big_num.less i ( half) then partialNaturalFromInteger i + else if Nat_big_num.greater_equal i (Nat_big_num.sub(Nat_big_num.of_int 0)( half)) && Nat_big_num.less i(Nat_big_num.of_int 0) then partialNaturalFromInteger ( Nat_big_num.add all i) + else failwith "partialTwosComplementNaturalFromInteger") + + +let parse_sint8 : Nat_big_num.num parser= + (pr_post_map (parse_uint8) (fun n -> integerFromTwosComplementNatural n(Nat_big_num.of_int 128)(Nat_big_num.of_int 256))) + +let parse_sint16 c : Nat_big_num.num parser= + (pr_post_map (parse_uint16 c) (fun n -> integerFromTwosComplementNatural n (Nat_big_num.mul(Nat_big_num.of_int 128)(Nat_big_num.of_int 256)) (Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256)))) + +let parse_sint32 c : Nat_big_num.num parser= + (pr_post_map (parse_uint32 c) (fun n -> integerFromTwosComplementNatural n (Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 128)(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(Nat_big_num.of_int 256)) (Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(Nat_big_num.of_int 256)))) + +let parse_sint64 c : Nat_big_num.num parser= + (pr_post_map (parse_uint64 c) (fun n -> integerFromTwosComplementNatural n (Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 128)(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(Nat_big_num.of_int 256)) (Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.mul(Nat_big_num.of_int 256)(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(Nat_big_num.of_int 256))(Nat_big_num.of_int 256)))) + +let rec parse_ULEB128' (acc: Nat_big_num.num) (shift_factor: Nat_big_num.num) : Nat_big_num.num parser= + (fun (pc:parse_context) -> + let _ = (my_debug "ULEB128' ") in + (match pc.pc_bytes with + | b::bytes' -> + let n = (natural_of_byte b) in + let acc' = (Nat_big_num.add (Nat_big_num.mul (Nat_big_num.bitwise_and n(Nat_big_num.of_int 127)) shift_factor) acc) in + let finished = ( Nat_big_num.equal(Nat_big_num.bitwise_and n(Nat_big_num.of_int 128))(Nat_big_num.of_int 0)) in + let pc' = ({ pc_bytes = bytes'; pc_offset = (Nat_big_num.add pc.pc_offset(Nat_big_num.of_int 1)) }) in + if finished then + PR_success( acc', pc') + else + parse_ULEB128' acc' ( Nat_big_num.mul shift_factor(Nat_big_num.of_int 128)) pc' + | _ -> + PR_fail( "parse_ULEB128' not given enough bytes", pc) + )) + +let parse_ULEB128 : Nat_big_num.num parser= + (fun (pc:parse_context) -> + parse_ULEB128'(Nat_big_num.of_int 0)(Nat_big_num.of_int 1) pc) + +let rec parse_SLEB128' (acc: Nat_big_num.num) (shift_factor: Nat_big_num.num) : (bool * Nat_big_num.num * Nat_big_num.num) parser= + (fun (pc:parse_context) -> + let _ = (my_debug "SLEB128' ") in + (match pc.pc_bytes with + | b::bytes' -> + let n = (natural_of_byte b) in + let acc' = (Nat_big_num.add acc (Nat_big_num.mul (Nat_big_num.bitwise_and n(Nat_big_num.of_int 127)) shift_factor)) in + let shift_factor' = (Nat_big_num.mul shift_factor(Nat_big_num.of_int 128)) in + let finished = ( Nat_big_num.equal(Nat_big_num.bitwise_and n(Nat_big_num.of_int 128))(Nat_big_num.of_int 0)) in + let positive = ( Nat_big_num.equal(Nat_big_num.bitwise_and n(Nat_big_num.of_int 64))(Nat_big_num.of_int 0)) in + let pc' = ({ pc_bytes = bytes'; pc_offset = (Nat_big_num.add pc.pc_offset(Nat_big_num.of_int 1)) }) in + if finished then + PR_success( (positive, shift_factor', acc'), pc') + else + parse_SLEB128' acc' shift_factor' pc' + | _ -> + PR_fail( "parse_SLEB128' not given enough bytes", pc) + )) + +let parse_SLEB128 : Nat_big_num.num parser= + (pr_post_map (parse_SLEB128'(Nat_big_num.of_int 0)(Nat_big_num.of_int 1)) (fun (positive, shift_factor, acc) -> + if positive then acc else Nat_big_num.sub ( acc) ( shift_factor))) + +let parse_nonzero_ULEB128_pair : ( (Nat_big_num.num*Nat_big_num.num)option) parser= + (let _ = (my_debug "nonzero_ULEB128_pair ") in + pr_post_map + (parse_pair parse_ULEB128 parse_ULEB128) + (fun (n1,n2) -> if Nat_big_num.equal n1(Nat_big_num.of_int 0) &&Nat_big_num.equal n2(Nat_big_num.of_int 0) then None else Some (n1,n2))) + +let parse_zero_terminated_ULEB128_pair_list : ( (Nat_big_num.num*Nat_big_num.num)list) parser= + (let _ = (my_debug "zero_terminated_ULEB128_pair_list ") in + parse_list parse_nonzero_ULEB128_pair) + +let parse_uintDwarfN c (df: dwarf_format) : Nat_big_num.num parser= + ((match df with + | Dwarf32 -> (parse_uint32 c) + | Dwarf64 -> (parse_uint64 c) + )) + +let parse_uint_address_size c (as': Nat_big_num.num) : Nat_big_num.num parser= + ( + if(Nat_big_num.equal as' (Nat_big_num.of_int 4)) then (parse_uint32 c) else + ( + if(Nat_big_num.equal as' (Nat_big_num.of_int 8)) then (parse_uint64 c) + else + (failwith ("cuh_address_size not 4 or 8: " ^ Nat_big_num.to_string as')))) + +let parse_uint_segment_selector_size c (ss: Nat_big_num.num) : ( Nat_big_num.num option) parser= + ( + if(Nat_big_num.equal ss (Nat_big_num.of_int 0)) then (pr_return None) else + ( + if(Nat_big_num.equal ss (Nat_big_num.of_int 1)) then + (pr_post_map (parse_uint8) (fun n -> Some n)) else + ( + if(Nat_big_num.equal ss (Nat_big_num.of_int 2)) then + (pr_post_map (parse_uint16 c) (fun n -> Some n)) else + ( + if(Nat_big_num.equal ss (Nat_big_num.of_int 4)) then + (pr_post_map (parse_uint32 c) (fun n -> Some n)) else + ( + if(Nat_big_num.equal ss (Nat_big_num.of_int 8)) then + (pr_post_map (parse_uint64 c) (fun n -> Some n)) else + (failwith "cuh_address_size not 4 or 8")))))) + + + +(** ************************************************************ *) +(** ** parsing and pretty printing of .debug_* sections ****** *) +(** ************************************************************ *) + + +(** abbreviations table: pp and parsing *) + +let pp_abbreviation_declaration (x:abbreviation_declaration):string= + (" " + ^ (Nat_big_num.to_string x.ad_abbreviation_code ^ (" " + ^ (pp_tag_encoding x.ad_tag ^ (" " + ^ ((if x.ad_has_children then "[has children]" else "[no children]") + ^ ("\n" +(* ^ " "^show (List.length x.ad_attribute_specifications) ^ " attributes\n"*) + ^ myconcat "" + (Lem_list.map + (fun (n1,n2) -> + " " ^ (pp_attribute_encoding n1 ^ (" " ^ (pp_attribute_form_encoding n2 ^ "\n")))) + x.ad_attribute_specifications)))))))) + +let pp_abbreviations_table (x:abbreviations_table):string= + (myconcat "" (Lem_list.map (pp_abbreviation_declaration) x)) + +let parse_abbreviation_declaration c : ( abbreviation_declaration option) parser= + (fun (pc: parse_context) -> + pr_bind (parse_ULEB128 pc) (fun n1 pc' -> + if Nat_big_num.equal n1(Nat_big_num.of_int 0) then + PR_success( None, pc') + else + pr_bind (parse_ULEB128 pc') (fun n2 pc'' -> + pr_bind (parse_uint8 pc'') (fun c pc''' -> + pr_post_map1 + (parse_zero_terminated_ULEB128_pair_list pc''') + (fun l -> + Some ( let ad = + ({ + ad_abbreviation_code = n1; + ad_tag = n2; + ad_has_children = (not (Nat_big_num.equal c(Nat_big_num.of_int 0))); + ad_attribute_specifications = l; + }) in let _ = (my_debug2 (pp_abbreviation_declaration ad)) in ad) + ))))) + +let parse_abbreviations_table c:parse_context ->((abbreviation_declaration)list)parse_result= + (parse_list (parse_abbreviation_declaration c)) + + +(** debug_str entry *) + +(*val mydrop : forall 'a. natural -> list 'a -> maybe (list 'a)*) +let rec mydrop n xs:('a list)option= + (if Nat_big_num.equal n(Nat_big_num.of_int 0) then Some xs + else + (match xs with + | x::xs' -> mydrop (Nat_big_num.sub_nat n(Nat_big_num.of_int 1)) xs' + | [] -> None + )) + +let rec null_terminated_list (acc: char list) (xs: char list) : char list= + ((match xs with + | [] -> List.rev acc (* TODO: flag failure? *) + | x::xs' -> if Nat_big_num.equal (natural_of_byte x)(Nat_big_num.of_int 0) then List.rev acc else null_terminated_list (x::acc) xs' + )) + +let pp_debug_str_entry (str: char list) (n: Nat_big_num.num):string= + ((match mydrop n str with + | None -> "strp beyond .debug_str extent" + | Some xs -> string_of_bytes (null_terminated_list [] xs) + )) + +(** operations: pp and parsing *) + +let pp_operation_argument_value (oav:operation_argument_value) : string= + ((match oav with + | OAV_natural n -> pphex n + | OAV_integer n -> Nat_big_num.to_string n + | OAV_block( n, bs) -> pphex n ^ (" " ^ ppbytes + instance_Show_Show_Missing_pervasives_byte_dict bs) + )) + +let pp_operation_semantics (os: operation_semantics) : string= + ((match os with + | OpSem_lit -> "OpSem_lit" + | OpSem_deref -> "OpSem_deref" + | OpSem_stack _ -> "OpSem_stack ..." + | OpSem_not_supported -> "OpSem_not_supported" + | OpSem_binary _ -> "OpSem_binary ..." + | OpSem_unary _ -> "OpSem_unary ..." + | OpSem_opcode_lit _ -> "OpSem_opcode_lit ..." + | OpSem_reg -> "OpSem_reg" + | OpSem_breg -> "OpSem_breg" + | OpSem_bregx -> "OpSem_bregx" + | OpSem_fbreg -> "OpSem_fbreg" + | OpSem_deref_size -> "OpSem_deref_size" + | OpSem_nop -> "OpSem_nop" + | OpSem_piece -> "OpSem_piece" + | OpSem_bit_piece -> "OpSem_bitpiece" + | OpSem_implicit_value -> "OpSem_implicit_value" + | OpSem_stack_value -> "OpSem_stack_value" + | OpSem_call_frame_cfa -> "OpSem_call_frame_cfa" + )) + +let pp_operation (op: operation) : string= + (op.op_string ^ (" " ^ (myconcat " " (Lem_list.map pp_operation_argument_value op.op_argument_values) ^ (" (" ^ (pp_operation_semantics op.op_semantics ^ ")"))))) + +let pp_operations (ops: operation list) : string= + (myconcat "; " (Lem_list.map pp_operation ops)) + +(*val parser_of_operation_argument_type : p_context -> compilation_unit_header -> operation_argument_type -> (parser operation_argument_value)*) +let parser_of_operation_argument_type c cuh oat:parse_context ->(operation_argument_value)parse_result= + ((match oat with + | OAT_addr -> + pr_map2 (fun n -> OAV_natural n) (parse_uint_address_size c cuh.cuh_address_size) + | OAT_dwarf_format_t -> + pr_map2 (fun n -> OAV_natural n) (parse_uintDwarfN c cuh.cuh_dwarf_format) + | OAT_uint8 -> pr_map2 (fun n -> OAV_natural n) (parse_uint8) + | OAT_uint16 -> pr_map2 (fun n -> OAV_natural n) (parse_uint16 c) + | OAT_uint32 -> pr_map2 (fun n -> OAV_natural n) (parse_uint32 c) + | OAT_uint64 -> pr_map2 (fun n -> OAV_natural n) (parse_uint64 c) + | OAT_sint8 -> pr_map2 (fun n -> OAV_integer n) (parse_sint8) + | OAT_sint16 -> pr_map2 (fun n -> OAV_integer n) (parse_sint16 c) + | OAT_sint32 -> pr_map2 (fun n -> OAV_integer n) (parse_sint32 c) + | OAT_sint64 -> pr_map2 (fun n -> OAV_integer n) (parse_sint64 c) + | OAT_ULEB128 -> pr_map2 (fun n -> OAV_natural n) parse_ULEB128 + | OAT_SLEB128 -> pr_map2 (fun n -> OAV_integer n) parse_SLEB128 + | OAT_block -> + (fun pc -> pr_bind (parse_ULEB128 pc) (fun n pc' -> + pr_map (fun bs -> OAV_block( n, bs)) (parse_n_bytes n pc'))) + )) + +(*val parse_operation : p_context -> compilation_unit_header -> parser (maybe operation)*) +let parse_operation c cuh pc:((operation)option)parse_result= + ((match parse_uint8 pc with + | PR_fail( s, pc') -> PR_success( None, pc) + | PR_success( code, pc') -> + (match lookup_aBcd_acd + instance_Basic_classes_Eq_Num_natural_dict code operation_encodings with + | None -> PR_fail( ("encoding not found: " ^ pphex code), pc) + | Some (s,oats,opsem) -> + let ps = (Lem_list.map (parser_of_operation_argument_type c cuh) oats) in + (pr_post_map + (parse_parser_list ps) + (fun oavs -> Some { op_code = code; op_string = s; op_argument_values = oavs; op_semantics = opsem }) + ) + pc' + ) + )) + +(*val parse_operations : p_context -> compilation_unit_header -> parser (list operation)*) +let parse_operations c cuh:parse_context ->((operation)list)parse_result= + (parse_list (parse_operation c cuh)) + +(*val parse_and_pp_operations : p_context -> compilation_unit_header -> list byte -> string*) +let parse_and_pp_operations c cuh bs:string= + (let pc = ({pc_bytes = bs; pc_offset =(Nat_big_num.of_int 0) }) in + (match parse_operations c cuh pc with + | PR_fail( s, pc') -> "parse_operations fail: " ^ pp_parse_fail s pc' + | PR_success( ops, pc') -> + pp_operations ops + ^ (if not ((listEqualBy (=) pc'.pc_bytes [])) then " Warning: extra non-parsed bytes" else "") + )) + + +(** attribute values: pp and parsing *) + +(*val pp_attribute_value : p_context -> compilation_unit_header -> list byte -> natural (*attribute tag*) -> attribute_value -> string*) +let pp_attribute_value c cuh str at av:string= + ((match av with + | AV_addr x -> "AV_addr " ^ pphex x + | AV_block( n, bs) -> "AV_block " ^ (Nat_big_num.to_string n ^ (" " ^ (ppbytes + instance_Show_Show_Missing_pervasives_byte_dict bs + ^ (if Nat_big_num.equal at (attribute_encode "DW_AT_location") then " " ^ parse_and_pp_operations c cuh bs else "")))) + | AV_constantN( n, bs) -> "AV_constantN " ^ (Nat_big_num.to_string n ^ (" " ^ ppbytes + instance_Show_Show_Missing_pervasives_byte_dict bs)) + | AV_constant_SLEB128 i -> "AV_constant_SLEB128 " ^ Nat_big_num.to_string i + | AV_constant_ULEB128 n -> "AV_constant_ULEB128 " ^ Nat_big_num.to_string n + | AV_exprloc( n, bs) -> "AV_exprloc " ^ (Nat_big_num.to_string n ^ (" " ^ (ppbytes + instance_Show_Show_Missing_pervasives_byte_dict bs + ^ (" " ^ parse_and_pp_operations c cuh bs)))) + | AV_flag b -> "AV_flag " ^ string_of_bool b + | AV_ref n -> "AV_ref " ^ pphex n + | AV_ref_addr n -> "AV_ref_addr " ^ pphex n + | AV_ref_sig8 n -> "AV_ref_sig8 " ^ pphex n + | AV_sec_offset n -> "AV_sec_offset " ^ pphex n + | AV_string bs -> string_of_bytes bs + | AV_strp n -> "AV_sec_offset " ^ (pphex n ^ (" " + ^ pp_debug_str_entry str n)) + )) + + +(*val parser_of_attribute_form_non_indirect : p_context -> compilation_unit_header -> natural -> parser attribute_value*) +let parser_of_attribute_form_non_indirect c cuh n:parse_context ->(attribute_value)parse_result= +( +(* address*)if Nat_big_num.equal n (attribute_form_encode "DW_FORM_addr") then + pr_map2 (fun n -> AV_addr n) (parse_uint_address_size c cuh.cuh_address_size) +(* block *) + else if Nat_big_num.equal n (attribute_form_encode "DW_FORM_block1") then + (fun pc -> pr_bind (parse_uint8 pc) (fun n pc' -> + pr_map (fun bs -> AV_block( n, bs)) (parse_n_bytes n pc'))) + else if Nat_big_num.equal n (attribute_form_encode "DW_FORM_block2") then + (fun pc -> pr_bind (parse_uint16 c pc) (fun n pc' -> + pr_map (fun bs -> AV_block( n, bs)) (parse_n_bytes n pc'))) + else if Nat_big_num.equal n (attribute_form_encode "DW_FORM_block4") then + (fun pc -> pr_bind (parse_uint32 c pc) (fun n pc' -> + pr_map (fun bs -> AV_block( n, bs)) (parse_n_bytes n pc'))) + else if Nat_big_num.equal n (attribute_form_encode "DW_FORM_block") then + (fun pc -> pr_bind (parse_ULEB128 pc) (fun n pc' -> + pr_map (fun bs -> AV_block( n, bs)) (parse_n_bytes n pc'))) +(* constant *) + else if Nat_big_num.equal n (attribute_form_encode "DW_FORM_data1") then + pr_map2 (fun bs -> AV_block((Nat_big_num.of_int 1), bs)) (parse_n_bytes(Nat_big_num.of_int 1)) + else if Nat_big_num.equal n (attribute_form_encode "DW_FORM_data2") then + pr_map2 (fun bs -> AV_block((Nat_big_num.of_int 2), bs)) (parse_n_bytes(Nat_big_num.of_int 2)) + else if Nat_big_num.equal n (attribute_form_encode "DW_FORM_data4") then + pr_map2 (fun bs -> AV_block((Nat_big_num.of_int 4), bs)) (parse_n_bytes(Nat_big_num.of_int 4)) + else if Nat_big_num.equal n (attribute_form_encode "DW_FORM_data8") then + pr_map2 (fun bs -> AV_block((Nat_big_num.of_int 8), bs)) (parse_n_bytes(Nat_big_num.of_int 8)) + else if Nat_big_num.equal n (attribute_form_encode "DW_FORM_sdata") then + pr_map2 (fun i -> AV_constant_SLEB128 i) parse_SLEB128 + else if Nat_big_num.equal n (attribute_form_encode "DW_FORM_udata") then + pr_map2 (fun n -> AV_constant_ULEB128 n) parse_ULEB128 +(* exprloc *) + else if Nat_big_num.equal n (attribute_form_encode "DW_FORM_exprloc") then + (fun pc -> pr_bind (parse_ULEB128 pc) (fun n pc' -> + pr_map (fun bs -> AV_exprloc( n, bs)) (parse_n_bytes n pc'))) +(* flag *) + else if Nat_big_num.equal n (attribute_form_encode "DW_FORM_flag") then + pr_map2 (fun n -> AV_flag (not (Nat_big_num.equal n(Nat_big_num.of_int 0)))) (parse_uint8) + else if Nat_big_num.equal n (attribute_form_encode "DW_FORM_flag_present") then + pr_map2 (fun () -> AV_flag true) (pr_return ()) +(* lineptr, loclistptr, macptr, rangelistptr *) + else if Nat_big_num.equal n (attribute_form_encode "DW_FORM_sec_offset") then + pr_map2 (fun n -> AV_sec_offset n) (parse_uintDwarfN c cuh.cuh_dwarf_format) +(* reference - first type *) + else if Nat_big_num.equal n (attribute_form_encode "DW_FORM_ref1") then + pr_map2 (fun n -> AV_ref n) (parse_uint8) + else if Nat_big_num.equal n (attribute_form_encode "DW_FORM_ref2") then + pr_map2 (fun n -> AV_ref n) (parse_uint16 c) + else if Nat_big_num.equal n (attribute_form_encode "DW_FORM_ref4") then + pr_map2 (fun n -> AV_ref n) (parse_uint32 c) + else if Nat_big_num.equal n (attribute_form_encode "DW_FORM_ref8") then + pr_map2 (fun n -> AV_ref n) (parse_uint64 c) + else if Nat_big_num.equal n (attribute_form_encode "DW_FORM_ref_udata") then + pr_map2 (fun n -> AV_ref n) parse_ULEB128 +(* reference - second type *) + else if Nat_big_num.equal n (attribute_form_encode "DW_FORM_ref_addr") then + pr_map2 (fun n -> AV_ref_addr n) (parse_uintDwarfN c cuh.cuh_dwarf_format) +(* reference - third type *) + else if Nat_big_num.equal n (attribute_form_encode "DW_FORM_ref_sig8") then + pr_map2 (fun n -> AV_ref_sig8 n) (parse_uint64 c) +(* string *) + else if Nat_big_num.equal n (attribute_form_encode "DW_FORM_string") then + pr_map2 (fun bs -> AV_string bs) parse_string + else if Nat_big_num.equal n (attribute_form_encode "DW_FORM_strp") then + pr_map2 (fun n -> AV_strp n) (parse_uintDwarfN c cuh.cuh_dwarf_format) +(* indirect (cycle detection) *) + else if Nat_big_num.equal n (attribute_form_encode "DW_FORM_indirect") then + failwith "DW_FORM_INDIRECT cycle" +(* unknown *) + else + failwith "parser_of_attribute_form_non_indirect: unknown attribute form") + + +let parser_of_attribute_form c cuh n:parse_context ->(attribute_value)parse_result= + (if Nat_big_num.equal n (attribute_form_encode "DW_FORM_indirect") then + (fun pc -> pr_bind (parse_ULEB128 pc) (fun n -> + parser_of_attribute_form_non_indirect c cuh n) ) + else + parser_of_attribute_form_non_indirect c cuh n) + +(** attribute find *) + +let find_name str ats : string option= + (myfindmaybe + (fun (((at: Nat_big_num.num), (af: Nat_big_num.num)), ((pos: Nat_big_num.num),(av:attribute_value))) -> + if Nat_big_num.equal (attribute_encode "DW_AT_name") at then + let name1 = + ((match av with + | AV_string bs -> string_of_bytes bs + | AV_strp n -> pp_debug_str_entry str n + | _ -> "av_name AV not understood" + )) in + Some name1 + else + None) + ats) + +let find_name_of_die str die1 : string option= + (let ats = (Lem_list.list_combine + die1.die_abbreviation_declaration.ad_attribute_specifications + die1.die_attribute_values) in + find_name str ats) + +let find_attribute_value (an: string) (die1:die) : attribute_value option= + (let at = (attribute_encode an) in + let ats = (Lem_list.list_combine + die1.die_abbreviation_declaration.ad_attribute_specifications + die1.die_attribute_values) in + myfindmaybe + (fun (((at': Nat_big_num.num), (af: Nat_big_num.num)), ((pos: Nat_big_num.num),(av:attribute_value))) -> + if Nat_big_num.equal at' at then Some av else None) + ats) + +(** compilation unit header: pp and parsing *) + +let pp_dwarf_format df:string= ((match df with Dwarf32 -> "(32-bit)" | Dwarf64 -> "(64-bit)" )) + +let pp_unit_header (s:string) (x:compilation_unit_header) : string= + (" " ^ (s ^ (" Unit @ offset " ^ (pphex x.cuh_offset ^ (":\n" + ^ (" Length: " ^ (pphex x.cuh_unit_length ^ (" " ^ (pp_dwarf_format x.cuh_dwarf_format ^ ("\n" + ^ (" Version: " ^ (Nat_big_num.to_string x.cuh_version ^ ("\n" + ^ (" Abbrev Offset: " ^ (pphex x.cuh_debug_abbrev_offset ^ ("\n" + ^ (" Pointer Size: " ^ (Nat_big_num.to_string x.cuh_address_size ^ "\n")))))))))))))))))) + +let pp_compilation_unit_header (x:compilation_unit_header) : string= + (pp_unit_header "Compilation" x) + +let parse_unit_length c : (dwarf_format * Nat_big_num.num) parser= + (fun (pc: parse_context) -> + pr_bind (parse_uint32 c pc) (fun x pc' -> + if Nat_big_num.less x (natural_of_hex "0xfffffff0") then PR_success( (Dwarf32,x), pc') + else if not (Nat_big_num.equal x (natural_of_hex "0xffffffff")) then PR_fail( "bad unit_length", pc) + else + pr_bind (parse_uint64 c pc') (fun x' pc'' -> + PR_success( (Dwarf64, x'), pc')))) + + +let parse_compilation_unit_header c : compilation_unit_header parser= + (pr_post_map + (pr_with_pos + (parse_dependent_pair + (parse_unit_length c) + (fun (df,ul) -> + parse_triple + (parse_uint16 c) (* version *) + (parse_uintDwarfN c df) (* debug abbrev offset *) + (parse_uint8) (* address_size *)))) + (fun (offset,((df,ul), (v, (dao, as')))) -> + { + cuh_offset = offset; + cuh_dwarf_format = df; + cuh_unit_length = ul; + cuh_version = v; + cuh_debug_abbrev_offset = dao; + cuh_address_size = as'; + })) + + +(** type unit header: pp and parsing *) + +(* the test binaries don't have a .debug_types section, so this isn't tested *) + +let pp_type_unit_header (x:type_unit_header) : string= + (pp_unit_header "Type" x.tuh_cuh + ^ (" Type Signature: " ^ (pphex x.tuh_type_signature ^ ("\n" + ^ (" Type Offset: " ^ (pphex x.tuh_type_offset ^ "\n")))))) + + +let parse_type_unit_header c : type_unit_header parser= + (pr_post_map + (parse_dependent_pair + (parse_compilation_unit_header c) + (fun cuh -> + parse_pair + (parse_uint64 c) (* type signature *) + (parse_uintDwarfN c cuh.cuh_dwarf_format) (* type offset *) )) + (fun (cuh, (ts, to')) -> + { + tuh_cuh = cuh; + tuh_type_signature = ts; + tuh_type_offset = to'; + })) + + +(** debugging information entries: pp and parsing *) + +(* example pp from readelf + <2><51>: Abbrev Number: 3 (DW_TAG_variable) + <52> DW_AT_name : x + <54> DW_AT_decl_file : 1 + <55> DW_AT_decl_line : 2 + <56> DW_AT_type : <0x6a> + <5a> DW_AT_location : 2 byte block: 91 6c (DW_OP_fbreg: -20) +*) + +let pp_pos pos:string= ("<" ^ (pphex pos ^">")) + +let indent_level (level: Nat_big_num.num):string= (Xstring.implode (replicate0 ( Nat_big_num.mul(Nat_big_num.of_int 3) level) ' ')) + +let pp_die_attribute c (cuh:compilation_unit_header) (str : char list) (level: Nat_big_num.num) (((at: Nat_big_num.num), (af: Nat_big_num.num)), ((pos: Nat_big_num.num),(av:attribute_value))) : string= + (indent_level ( Nat_big_num.add level(Nat_big_num.of_int 1)) ^ (pp_pos pos ^ (" " + ^ (pp_attribute_encoding at ^ (" : " + ^ ("(" ^ (pp_attribute_form_encoding af ^ (") " + ^ (pp_attribute_value c cuh str at av + ^ "\n"))))))))) + +(*val pp_die : p_context -> compilation_unit_header -> list byte -> natural -> bool -> die -> string*) +let rec pp_die c cuh str level (pp_children:bool) die1:string= + (indent_level level ^ ("<" ^ (Nat_big_num.to_string level ^ (">" + ^ (pp_pos die1.die_offset + ^ (": Abbrev Number: " ^ (Nat_big_num.to_string die1.die_abbreviation_code + ^ (" (" ^ (pp_tag_encoding die1.die_abbreviation_declaration.ad_tag ^(")\n" + ^ +(let ats = (Lem_list.list_combine + die1.die_abbreviation_declaration.ad_attribute_specifications + die1.die_attribute_values) in + (myconcat "" (Lem_list.map (pp_die_attribute c cuh str level) ats)) + ^ +(if pp_children then myconcat "" (Lem_list.map (pp_die c cuh str ( Nat_big_num.add level(Nat_big_num.of_int 1)) pp_children) die1.die_children) else "")))))))))))) + +(*val pp_die_abbrev : p_context -> compilation_unit_header -> list byte -> natural -> bool -> (list die) -> die -> string*) +let rec pp_die_abbrev c cuh str level (pp_children:bool) parents die1:string= + (indent_level level + ^ (pp_tag_encoding die1.die_abbreviation_declaration.ad_tag + ^ (" (" ^ (pp_pos die1.die_offset ^ (") " +(* ^ ": Abbrev Number: " ^ show die.die_abbreviation_code *) + ^ +(let ats = (Lem_list.list_combine + die1.die_abbreviation_declaration.ad_attribute_specifications + die1.die_attribute_values) in + ((match find_name str ats with Some s -> s | None -> "-" )) + ^ (" : " ^ (myconcat " : " (Lem_list.map (fun die' -> pp_tag_encoding die'.die_abbreviation_declaration.ad_tag) parents) + ^ ("\n" + ^ + +( (*(myconcat "" (List.map (pp_die_abbrev_attribute c cuh str) ats))*)if pp_children then myconcat "" (Lem_list.map (pp_die_abbrev c cuh str ( Nat_big_num.add level(Nat_big_num.of_int 1)) pp_children (die1::parents)) die1.die_children) else "")))))))))) + + + +(*val parse_die : p_context -> list byte -> compilation_unit_header -> (natural->abbreviation_declaration) -> parser (maybe die)*) +let rec parse_die c str cuh find_abbreviation_declaration:parse_context ->((die)option)parse_result= + (fun (pc: parse_context) -> + let _ = (my_debug3 ("parse_die called at " ^ (pp_parse_context pc ^ "\n"))) in + pr_bind (parse_ULEB128 pc) (fun abbreviation_code pc' -> + if Nat_big_num.equal abbreviation_code(Nat_big_num.of_int 0) then PR_success( None, pc') + else + let _ = (my_debug3 ("parse_die abbreviation code "^(pphex abbreviation_code ^"\n"))) in + let ad = (find_abbreviation_declaration abbreviation_code) in + let attribute_value_parsers = (Lem_list.map (fun (at,af) -> pr_with_pos (parser_of_attribute_form c cuh af)) ad.ad_attribute_specifications) in + pr_bind (parse_parser_list attribute_value_parsers pc') (fun avs pc'' -> + +(* + let die_header = + <| + die_offset = pc.pc_offset; + die_abbreviation_code = abbreviation_code; + die_abbreviation_declaration = ad; + die_attribute_values = avs; + die_children = []; + |> in let _ = my_debug3 ("die_header " ^ pp_die cuh str 999 die_header) in + *) + pr_bind + (if ad.ad_has_children then parse_list (parse_die c str cuh find_abbreviation_declaration) pc'' else pr_return [] pc'') + (fun dies pc''' -> + PR_success( (Some ( let die1 = + ({ + die_offset = (pc.pc_offset); + die_abbreviation_code = abbreviation_code; + die_abbreviation_declaration = ad; + die_attribute_values = avs; + die_children = dies; + }) in (* let _ = my_debug3 ("die entire " ^ pp_die cuh str 999 die) in *)die1)), pc'''))))) + +let has_attribute (an: string) (die1: die) : bool= + (Lem_list.elem instance_Basic_classes_Eq_Num_natural_dict + (attribute_encode an) + (Lem_list.map fst die1.die_abbreviation_declaration.ad_attribute_specifications)) + + +(** compilation units: pp and parsing *) + +let pp_compilation_unit c (debug_str_section_body: char list) cu:string= + + ("*** compilation unit header ***\n" + ^ (pp_compilation_unit_header cu.cu_header + ^ ("\n*** compilation unit abbreviation table ***\n" + ^ (pp_abbreviations_table cu.cu_abbreviations_table + ^ ("\n*** compilation unit die tree ***\n" + ^ (pp_die c cu.cu_header debug_str_section_body(Nat_big_num.of_int 0) true cu.cu_die + ^ "\n")))))) + +let pp_compilation_units c debug_string_section_body (compilation_units1: compilation_unit list) : string= + (myconcat "" (Lem_list.map (pp_compilation_unit c debug_string_section_body) compilation_units1)) + + +let pp_compilation_unit_abbrev c (debug_str_section_body: char list) cu:string= + (pp_compilation_unit_header cu.cu_header +(* ^ pp_abbreviations_table cu.cu_abbreviations_table*) + ^ pp_die_abbrev c cu.cu_header debug_str_section_body(Nat_big_num.of_int 0) true [] cu.cu_die) + +let pp_compilation_units_abbrev c debug_string_section_body (compilation_units1: compilation_unit list) : string= + (myconcat "" (Lem_list.map (pp_compilation_unit_abbrev c debug_string_section_body) compilation_units1)) + + +let parse_compilation_unit c (debug_str_section_body: char list) (debug_abbrev_section_body: char list) : ( compilation_unit option) parser= + (fun (pc:parse_context) -> + + if (listEqualBy (=) pc.pc_bytes []) then PR_success( None, pc) else + + let (cuh, pc') = + + ((match parse_compilation_unit_header c pc with + | PR_fail( s, pc') -> failwith ("parse_cuh_header fail: " ^ pp_parse_fail s pc') + | PR_success( cuh, pc') -> (cuh,pc') + )) in + + let _ = (my_debug4 (pp_compilation_unit_header cuh)) in + + let pc_abbrev = ({pc_bytes = ((match mydrop cuh.cuh_debug_abbrev_offset debug_abbrev_section_body with Some bs -> bs | None -> failwith "mydrop of debug_abbrev" )); pc_offset = (cuh.cuh_debug_abbrev_offset) }) in + + let abbreviations_table1 = + ((match parse_abbreviations_table c pc_abbrev with + | PR_fail( s, pc_abbrev') -> failwith ("parse_abbrevations_table fail: " ^ pp_parse_fail s pc_abbrev') + | PR_success( at, pc_abbrev') -> at + )) in + + let _ = (my_debug4 (pp_abbreviations_table abbreviations_table1)) in + + let find_abbreviation_declaration (ac:Nat_big_num.num) : abbreviation_declaration= + (let _ = (my_debug4 ("find_abbreviation_declaration "^pphex ac)) in + myfindNonPure (fun ad -> Nat_big_num.equal ad.ad_abbreviation_code ac) abbreviations_table1) in + + let _ = (my_debug3 (pp_abbreviations_table abbreviations_table1)) in + + (match parse_die c debug_str_section_body cuh find_abbreviation_declaration pc' with + | PR_fail( s, pc'') -> failwith ("parse_die fail: " ^ pp_parse_fail s pc'') + | PR_success( (None), pc'') -> failwith ("parse_die returned Nothing: " ^ pp_parse_context pc'') + | PR_success( (Some die1), pc'') -> + let cu = + ({ + cu_header = cuh; + cu_abbreviations_table = abbreviations_table1; + cu_die = die1; + }) in + PR_success( (Some cu), pc'') + )) + +let parse_compilation_units c (debug_str_section_body: char list) (debug_abbrev_section_body: char list): ( compilation_unit list) parser= + + (parse_list (parse_compilation_unit c debug_str_section_body debug_abbrev_section_body)) + + +(** type units: pp and parsing *) + +let pp_type_unit c (debug_str_section_body: char list) tu:string= + (pp_type_unit_header tu.tu_header + ^ (pp_abbreviations_table tu.tu_abbreviations_table + ^ pp_die c tu.tu_header.tuh_cuh debug_str_section_body(Nat_big_num.of_int 0) true tu.tu_die)) + +let pp_type_units c debug_string_section_body (type_units1: type_unit list) : string= + (myconcat "" (Lem_list.map (pp_type_unit c debug_string_section_body) type_units1)) + + +let parse_type_unit c (debug_str_section_body: char list) (debug_abbrev_section_body: char list) : ( type_unit option) parser= + (fun (pc:parse_context) -> + + if (listEqualBy (=) pc.pc_bytes []) then PR_success( None, pc) else + + let (tuh, pc') = + ((match parse_type_unit_header c pc with + | PR_fail( s, pc') -> failwith ("parse_tuh_header fail: " ^ pp_parse_fail s pc') + | PR_success( tuh, pc') -> (tuh,pc') + )) in + + let _ = (my_debug4 (pp_type_unit_header tuh)) in + + let pc_abbrev = (let n = (tuh.tuh_cuh.cuh_debug_abbrev_offset) in {pc_bytes = ((match mydrop n debug_abbrev_section_body with Some bs -> bs | None -> failwith "mydrop of debug_abbrev" )); pc_offset = n }) in + + let abbreviations_table1 = + ((match parse_abbreviations_table c pc_abbrev with + | PR_fail( s, pc_abbrev') -> failwith ("parse_abbrevations_table fail: " ^ pp_parse_fail s pc_abbrev') + | PR_success( at, pc_abbrev') -> at + )) in + + let _ = (my_debug4 (pp_abbreviations_table abbreviations_table1)) in + + let find_abbreviation_declaration (ac:Nat_big_num.num) : abbreviation_declaration= + (let _ = (my_debug4 ("find_abbreviation_declaration "^pphex ac)) in + myfindNonPure (fun ad -> Nat_big_num.equal ad.ad_abbreviation_code ac) abbreviations_table1) in + + let _ = (my_debug3 (pp_abbreviations_table abbreviations_table1)) in + + (match parse_die c debug_str_section_body tuh.tuh_cuh find_abbreviation_declaration pc' with + | PR_fail( s, pc'') -> failwith ("parse_die fail: " ^ pp_parse_fail s pc'') + | PR_success( (None), pc'') -> failwith ("parse_die returned Nothing: " ^ pp_parse_context pc'') + | PR_success( (Some die1), pc'') -> + let tu = + ({ + tu_header = tuh; + tu_abbreviations_table = abbreviations_table1; + tu_die = die1; + }) in + PR_success( (Some tu), pc'') + )) + +let parse_type_units c (debug_str_section_body: char list) (debug_abbrev_section_body: char list): ( type_unit list) parser= + + (parse_list (parse_type_unit c debug_str_section_body debug_abbrev_section_body)) + +(** location lists, pp and parsing *) + +(* readelf example +Contents of the .debug_loc section: + + Offset Begin End Expression + 00000000 0000000000400168 0000000000400174 (DW_OP_reg0 (r0)) + 00000000 0000000000400174 0000000000400184 (DW_OP_GNU_entry_value: (DW_OP_reg0 (r0)); DW_OP_stack_value) + 00000000 <End of list> + 00000039 000000000040017c 0000000000400180 (DW_OP_lit1; DW_OP_stack_value) +*) + +let pp_location_list_entry c (cuh:compilation_unit_header) (offset:Nat_big_num.num) (x:location_list_entry) : string= + (" " ^ (pphex offset + ^ (" " ^ (pphex x.lle_beginning_address_offset + ^ (" " ^ (pphex x.lle_ending_address_offset + ^ (" (" ^ (parse_and_pp_operations c cuh x.lle_single_location_description ^(")" + ^ "\n"))))))))) + +let pp_base_address_selection_entry c (cuh:compilation_unit_header) (offset:Nat_big_num.num) (x:base_address_selection_entry) : string= + (" " ^ (pphex offset + ^ (" " ^ (pphex x.base_address + ^ "\n")))) + +let pp_location_list_item c (cuh: compilation_unit_header) (offset: Nat_big_num.num) (x:location_list_item):string= + ((match x with + | LLI_lle lle -> pp_location_list_entry c cuh offset lle + | LLI_base base -> pp_base_address_selection_entry c cuh offset base + )) + +let pp_location_list c (cuh: compilation_unit_header) ((offset:Nat_big_num.num), (llis: location_list_item list)):string= + (myconcat "" (Lem_list.map (pp_location_list_item c cuh offset) llis)) +(* ^ " " ^ pphex offset ^ " <End of list>\n"*) + +let pp_loc c (cuh: compilation_unit_header) (lls: location_list list):string= + (" Offset Begin End Expression\n" + ^ myconcat "" (Lem_list.map (pp_location_list c cuh) lls)) + +(* Note that this is just pp'ing the raw location list data - Sectoin +3.1.1 says: The applicable base address of a location list entry is +determined by the closest preceding base address selection entry in +the same location list. If there is no such selection entry, then the +applicable base address defaults to the base address of the +compilation unit. That is handled by the interpret_location_list below *) + + + +let parse_location_list_item c (cuh: compilation_unit_header) : ( location_list_item option) parser= + (fun (pc:parse_context) -> + pr_bind + (parse_pair + (parse_uint_address_size c cuh.cuh_address_size) + (parse_uint_address_size c cuh.cuh_address_size) + pc) + (fun ((a1: Nat_big_num.num),(a2:Nat_big_num.num)) pc' -> + let _ = (my_debug4 ("offset="^(pphex pc.pc_offset ^ (" begin=" ^ (pphex a1 ^ (" end=" ^ pphex a2)))))) in + if Nat_big_num.equal a1(Nat_big_num.of_int 0) &&Nat_big_num.equal a2(Nat_big_num.of_int 0) then + PR_success( None, pc') + else if Nat_big_num.equal a1 (max_address cuh.cuh_address_size) then + let x = (LLI_base { (*base_offset=pc.pc_offset;*) base_address=a1 }) in + PR_success( (Some x (*(pc.pc_offset, x)*)), pc') + else + pr_bind (parse_uint16 c pc') (fun n pc'' -> + pr_post_map1 + (parse_n_bytes n pc'') + (fun bs -> + let x = + (LLI_lle { + (*lle_offset = pc.pc_offset;*) + lle_beginning_address_offset = a1; + lle_ending_address_offset = a2; + lle_single_location_description = bs; + }) in + Some x (*(pc.pc_offset, x)*)) + ) + )) + +let parse_location_list c cuh : ( location_list option) parser= + (fun (pc: parse_context) -> + if (listEqualBy (=) pc.pc_bytes []) then + PR_success( None, pc) + else + pr_post_map1 + (parse_list (parse_location_list_item c cuh) pc) + (fun llis -> (Some (pc.pc_offset, llis)))) + +let parse_location_list_list c cuh : location_list_list parser= + (parse_list (parse_location_list c cuh)) + +let find_location_list dloc n : location_list= + (myfindNonPure (fun (n',_)->Nat_big_num.equal n' n) dloc) + (* fails if location list not found *) + +(* interpretation of a location list applies the base_address and LLI_base offsets to give a list indexed by concrete address ranges *) + +let rec interpret_location_list (base_address1: Nat_big_num.num) (llis: location_list_item list) : (Nat_big_num.num * Nat_big_num.num * single_location_description) list= + ((match llis with + | [] -> [] + | LLI_base base::llis' -> interpret_location_list base.base_address llis' + | LLI_lle lle :: llis' -> (Nat_big_num.add base_address1 lle.lle_beginning_address_offset,Nat_big_num.add base_address1 lle.lle_ending_address_offset, lle.lle_single_location_description) :: interpret_location_list base_address1 llis' + )) + + +(** range lists, pp and parsing *) + +(* readelf example +Contents of the .debug_aranges section: + + Length: 44 + Version: 2 + Offset into .debug_info: 0x0 + Pointer Size: 8 + Segment Size: 0 + + Address Length + 00000000100000e8 0000000000000090 + 0000000000000000 0000000000000000 + Length: 44 + Version: 2 + Offset into .debug_info: 0x1de + Pointer Size: 8 + Segment Size: 0 +*) + +let pp_range_list_entry c (cuh:compilation_unit_header) (offset:Nat_big_num.num) (x:range_list_entry) : string= + (" " ^ (pphex offset + ^ (" " ^ (pphex x.rle_beginning_address_offset + ^ (" " ^ (pphex x.rle_ending_address_offset + ^ "\n")))))) + +let pp_range_list_item c (cuh: compilation_unit_header) (offset: Nat_big_num.num) (x:range_list_item):string= + ((match x with + | RLI_rle rle -> pp_range_list_entry c cuh offset rle + | RLI_base base -> pp_base_address_selection_entry c cuh offset base + )) + +let pp_range_list c (cuh: compilation_unit_header) ((offset:Nat_big_num.num), (rlis: range_list_item list)):string= + (myconcat "" (Lem_list.map (pp_range_list_item c cuh offset) rlis)) +(* ^ " " ^ pphex offset ^ " <End of list>\n"*) + +let pp_ranges c (cuh: compilation_unit_header) (rls: range_list list):string= + (" Offset Begin End Expression\n" + ^ myconcat "" (Lem_list.map (pp_range_list c cuh) rls)) + +(* Note that this is just pp'ing the raw range list data - see also +the interpret_range_list below *) + + +let parse_range_list_item c (cuh: compilation_unit_header) : ( range_list_item option) parser= + (fun (pc:parse_context) -> + pr_bind + (parse_pair + (parse_uint_address_size c cuh.cuh_address_size) + (parse_uint_address_size c cuh.cuh_address_size) + pc) + (fun ((a1: Nat_big_num.num),(a2:Nat_big_num.num)) pc' -> + let _ = (my_debug4 ("offset="^(pphex pc.pc_offset ^ (" begin=" ^ (pphex a1 ^ (" end=" ^ pphex a2)))))) in + if Nat_big_num.equal a1(Nat_big_num.of_int 0) &&Nat_big_num.equal a2(Nat_big_num.of_int 0) then + PR_success( None, pc') + else if Nat_big_num.equal a1 (max_address cuh.cuh_address_size) then + let x = (RLI_base { base_address=a1 }) in + PR_success( (Some x), pc') + else + let x = + (RLI_rle { + rle_beginning_address_offset = a1; + rle_ending_address_offset = a2; + }) in + PR_success( (Some x (*(pc.pc_offset, x)*)), pc') + )) + +let parse_range_list c cuh : ( range_list option) parser= + (fun (pc: parse_context) -> + if (listEqualBy (=) pc.pc_bytes []) then + PR_success( None, pc) + else + pr_post_map1 + (parse_list (parse_range_list_item c cuh) pc) + (fun rlis -> (Some (pc.pc_offset, rlis)))) + +let parse_range_list_list c cuh : range_list_list parser= + (parse_list (parse_range_list c cuh)) + +let find_range_list dranges n : range_list= + (myfindNonPure (fun (n',_)->Nat_big_num.equal n' n) dranges) + (* fails if range list not found *) + +(* interpretation of a range list applies the base_address and RLI_base offsets to give a list of concrete address ranges *) + +let rec interpret_range_list (base_address1: Nat_big_num.num) (rlis: range_list_item list) : (Nat_big_num.num * Nat_big_num.num) list= + ((match rlis with + | [] -> [] + | RLI_base base::rlis' -> interpret_range_list base.base_address rlis' + | RLI_rle rle :: rlis' -> (Nat_big_num.add base_address1 rle.rle_beginning_address_offset,Nat_big_num.add base_address1 rle.rle_ending_address_offset) :: interpret_range_list base_address1 rlis' + )) + +(** frame information, pp and parsing *) + +(* readelf example + +Contents of the .debug_frame section: + +00000000 0000000c ffffffff CIE + Version: 1 + Augmentation: "" + Code alignment factor: 4 + Data alignment factor: -8 + Return address column: 65 + + DW_CFA_def_cfa: r1 ofs 0 + +00000010 00000024 00000000 FDE cie=00000000 pc=100000b0..10000120 + DW_CFA_advance_loc: 8 to 100000b8 + DW_CFA_def_cfa_offset: 80 + DW_CFA_offset: r31 at cfa-8 + DW_CFA_advance_loc: 4 to 100000bc + DW_CFA_def_cfa_register: r31 + DW_CFA_advance_loc: 80 to 1000010c + DW_CFA_def_cfa: r1 ofs 0 + DW_CFA_nop + DW_CFA_nop + DW_CFA_nop + DW_CFA_nop + +00000038 00000024 00000000 FDE cie=00000000 pc=10000120..100001a4 + DW_CFA_advance_loc: 16 to 10000130 + DW_CFA_def_cfa_offset: 144 + DW_CFA_offset_extended_sf: r65 at cfa+16 + DW_CFA_offset: r31 at cfa-8 + DW_CFA_advance_loc: 4 to 10000134 + DW_CFA_def_cfa_register: r31 + DW_CFA_advance_loc: 84 to 10000188 + DW_CFA_def_cfa: r1 ofs 0 +*) + + + +let pp_cfa_address a:string= (pphex a) +let pp_cfa_block dict_Show_Show_a b:string= (ppbytes + dict_Show_Show_a b) +let pp_cfa_delta d:string= (pphex d) +(*let pp_cfa_offset n = pphex n +let pp_cfa_register r = show r*) +let pp_cfa_sfoffset dict_Show_Show_a i:string= ( + dict_Show_Show_a.show_method i) + +let pp_cfa_register dict_Show_Show_a r:string= ("r"^ + dict_Show_Show_a.show_method r) (*TODO: arch-specific register names *) + +let pp_cfa_offset (i:Nat_big_num.num):string= (if Nat_big_num.equal i(Nat_big_num.of_int 0) then "" else if Nat_big_num.less i(Nat_big_num.of_int 0) then Nat_big_num.to_string i else "+" ^ Nat_big_num.to_string i) + +let pp_cfa_rule (cr:cfa_rule) : string= + ((match cr with + | CR_undefined -> "u" + | CR_register( r, i) -> pp_cfa_register + instance_Show_Show_Num_natural_dict r ^ pp_cfa_offset i + | CR_expression bs -> "exp" + )) + +let pp_register_rule (rr:register_rule) : string= +( (*TODO make this more readelf-like *)(match rr with + | RR_undefined -> "u" + | RR_same_value -> "s" + | RR_offset i -> "c" ^ pp_cfa_offset i + | RR_val_offset i -> "val(c" ^ (pp_cfa_offset i ^ ")") + | RR_register r -> pp_cfa_register + instance_Show_Show_Num_natural_dict r + | RR_expression bs -> "exp" + | RR_val_expression bs -> "val(exp)" + | RR_architectural -> "" + )) + + + +let pp_call_frame_instruction i:string= + ((match i with + | DW_CFA_advance_loc d -> "DW_CFA_advance_loc" ^ (" " ^ pp_cfa_delta d) + | DW_CFA_offset( r, n) -> "DW_CFA_offset" ^ (" " ^ (pp_cfa_register + instance_Show_Show_Num_natural_dict r ^ (" " ^ pp_cfa_offset ( n)))) + | DW_CFA_restore r -> "DW_CFA_restore" ^ (" " ^ pp_cfa_register + instance_Show_Show_Num_natural_dict r) + | DW_CFA_nop -> "DW_CFA_nop" + | DW_CFA_set_loc a -> "DW_CFA_set_loc" ^ (" " ^ pp_cfa_address a) + | DW_CFA_advance_loc1 d -> "DW_CFA_advance_loc1" ^ (" " ^ pp_cfa_delta d) + | DW_CFA_advance_loc2 d -> "DW_CFA_advance_loc2" ^ (" " ^ pp_cfa_delta d) + | DW_CFA_advance_loc4 d -> "DW_CFA_advance_loc4" ^ (" " ^ pp_cfa_delta d) + | DW_CFA_offset_extended( r, n) -> "DW_CFA_offset_extended" ^ (" " ^ (pp_cfa_register + instance_Show_Show_Num_natural_dict r ^ (" " ^ pp_cfa_offset ( n)))) + | DW_CFA_restore_extended r -> "DW_CFA_restore_extended" ^ (" " ^ pp_cfa_register + instance_Show_Show_Num_natural_dict r) + | DW_CFA_undefined r -> "DW_CFA_undefined" ^ (" " ^ pp_cfa_register + instance_Show_Show_Num_natural_dict r) + | DW_CFA_same_value r -> "DW_CFA_same_value" ^ (" " ^ pp_cfa_register + instance_Show_Show_Num_natural_dict r) + | DW_CFA_register( r1, r2) -> "DW_CFA_register" ^ (" " ^ (pp_cfa_register + instance_Show_Show_Num_natural_dict r1 ^ (" " ^ pp_cfa_register + instance_Show_Show_Num_natural_dict r2))) + | DW_CFA_remember_state -> "DW_CFA_remember_state" + | DW_CFA_restore_state -> "DW_CFA_restore_state" + | DW_CFA_def_cfa( r, n) -> "DW_CFA_def_cfa" ^ (" " ^ (pp_cfa_register + instance_Show_Show_Num_natural_dict r ^ (" " ^ pp_cfa_offset ( n)))) + | DW_CFA_def_cfa_register r -> "DW_CFA_def_cfa_register" ^ (" " ^ pp_cfa_register + instance_Show_Show_Num_natural_dict r) + | DW_CFA_def_cfa_offset n -> "DW_CFA_def_cfa_offset" ^ (" " ^ pp_cfa_offset ( n)) + | DW_CFA_def_cfa_expression b -> "DW_CFA_def_cfa_expression" ^ (" " ^ pp_cfa_block + instance_Show_Show_Missing_pervasives_byte_dict b) + | DW_CFA_expression( r, b) -> "DW_CFA_expression" ^ (" " ^ (pp_cfa_register + instance_Show_Show_Num_natural_dict r ^ (" " ^ pp_cfa_block + instance_Show_Show_Missing_pervasives_byte_dict b))) + | DW_CFA_offset_extended_sf( r, i) -> "DW_CFA_offset_extended_sf" ^ (" " ^ (pp_cfa_register + instance_Show_Show_Num_natural_dict r ^ (" " ^ pp_cfa_sfoffset + instance_Show_Show_Num_integer_dict i))) + | DW_CFA_def_cfa_sf( r, i) -> "DW_CFA_def_cfa_sf" ^ (" " ^ (pp_cfa_register + instance_Show_Show_Num_natural_dict r ^ (" " ^ pp_cfa_sfoffset + instance_Show_Show_Num_integer_dict i))) + | DW_CFA_def_cfa_offset_sf i -> "DW_CFA_def_cfa_offset_sf" ^ (" " ^ pp_cfa_sfoffset + instance_Show_Show_Num_integer_dict i) + | DW_CFA_val_offset( r, n) -> "DW_CFA_val_offset" ^ (" " ^ (pp_cfa_register + instance_Show_Show_Num_natural_dict r ^ (" " ^ pp_cfa_offset ( n)))) + | DW_CFA_val_offset_sf( r, i) -> "DW_CFA_val_offset_sf" ^ (pp_cfa_register + instance_Show_Show_Num_natural_dict r ^ (" " ^ pp_cfa_sfoffset + instance_Show_Show_Num_integer_dict i)) + | DW_CFA_val_expression( r, b) -> "DW_CFA_val_expression" ^ (" " ^ (pp_cfa_register + instance_Show_Show_Num_natural_dict r ^ (" " ^ pp_cfa_block + instance_Show_Show_Missing_pervasives_byte_dict b))) + | DW_CFA_unknown bt -> "DW_CFA_unknown" ^ (" " ^ hex_string_of_byte bt) + )) + +let pp_call_frame_instructions is:string= (myconcat "" (Lem_list.map (fun i -> " " ^ (pp_call_frame_instruction i ^ "\n")) is)) + + +let parser_of_call_frame_argument_type c cuh (cfat: call_frame_argument_type) : call_frame_argument_value parser= + ((match cfat with + | CFAT_address -> pr_map2 (fun n -> CFAV_address n) (parse_uint_address_size c cuh.cuh_address_size) + | CFAT_delta1 -> pr_map2 (fun n -> CFAV_delta n) (parse_uint8) + | CFAT_delta2 -> pr_map2 (fun n -> CFAV_delta n) (parse_uint16 c) + | CFAT_delta4 -> pr_map2 (fun n -> CFAV_delta n) (parse_uint32 c) + | CFAT_delta_ULEB128 -> pr_map2 (fun n -> CFAV_delta n) (parse_ULEB128) + | CFAT_offset -> pr_map2 (fun n -> CFAV_offset n) (parse_ULEB128) + | CFAT_sfoffset -> pr_map2 (fun n -> CFAV_sfoffset n) (parse_SLEB128) + | CFAT_register -> pr_map2 (fun n -> CFAV_register n) (parse_ULEB128) + | CFAT_block -> + (fun pc -> pr_bind (parse_ULEB128 pc) (fun n pc' -> + pr_map (fun bs -> CFAV_block bs) (parse_n_bytes n pc'))) + )) + +let parse_call_frame_instruction c cuh : ( call_frame_instruction option) parser= + (fun pc -> + (match pc.pc_bytes with + | [] -> PR_success( None, pc) + | b::bs' -> + let pc' = ({ pc_bytes = bs'; pc_offset = (Nat_big_num.add pc.pc_offset(Nat_big_num.of_int 1)) }) in + let ch = (Uint32.of_int (Char.code b)) in + let high_bits = (Uint32.logand ch (Uint32.of_string (Nat_big_num.to_string (Nat_big_num.of_int 192)))) in + let low_bits = (Nat_big_num.of_string (Uint32.to_string (Uint32.logand ch (Uint32.of_string (Nat_big_num.to_string (Nat_big_num.of_int 63)))))) in + if high_bits = Uint32.of_string (Nat_big_num.to_string (Nat_big_num.of_int 0)) then + (match lookup_abCde_de + instance_Basic_classes_Eq_Num_natural_dict low_bits call_frame_instruction_encoding with + | Some ((args: call_frame_argument_type list), result) -> + let ps = (Lem_list.map (parser_of_call_frame_argument_type c cuh) args) in + let p = + (pr_post_map + (parse_parser_list ps) + result) in + (match p pc' with + | PR_success( (Some cfi), pc'') -> PR_success( (Some cfi), pc'') + | PR_success( (None), pc'') -> failwith "bad call frame instruction argument 1" + | PR_fail( s, pc'') -> failwith "bad call frame instruction argument 2" + ) + | None -> + (*Assert_extra.failwith ("can't parse " ^ show b ^ " as call frame instruction")*) + PR_success( (Some (DW_CFA_unknown b)), pc') + ) + else + if high_bits = Uint32.of_string (Nat_big_num.to_string (Nat_big_num.of_int 64)) then + PR_success( (Some (DW_CFA_advance_loc low_bits)), pc') + else if high_bits = Uint32.of_string (Nat_big_num.to_string (Nat_big_num.of_int 192)) then + PR_success( (Some (DW_CFA_restore low_bits)), pc') + else + let p = (parser_of_call_frame_argument_type c cuh CFAT_offset) in + (match p pc' with + | PR_success( (CFAV_offset n), pc'') -> PR_success( (Some (DW_CFA_offset( low_bits, n))), pc'') + | PR_success( _, pc'') -> failwith "bad call frame instruction argument 3" + | PR_fail( s, pc'') -> failwith "bad call frame instruction argument 4" + ) + )) + +let parse_call_frame_instructions c cuh : ( call_frame_instruction list) parser= + (parse_list (parse_call_frame_instruction c cuh)) + +(*val parse_and_pp_call_frame_instructions : p_context -> compilation_unit_header -> list byte -> string*) +let parse_and_pp_call_frame_instructions c cuh bs:string= + (let pc = ({pc_bytes = bs; pc_offset =(Nat_big_num.of_int 0) }) in + (match parse_call_frame_instructions c cuh pc with + | PR_fail( s, pc') -> "parse_call_frame_instructions fail: " ^ pp_parse_fail s pc' + | PR_success( is, pc') -> + pp_call_frame_instructions is + ^ (if not ((listEqualBy (=) pc'.pc_bytes [])) then " Warning: extra non-parsed bytes" else "") + )) + + + +let pp_call_frame_instructions' c cuh bs:string= +( + (* ppbytes bs ^ "\n" *)parse_and_pp_call_frame_instructions c cuh bs) + + + +let pp_cie c cuh cie1:string= + (pphex cie1.cie_offset + ^ (" " ^ (pphex cie1.cie_length + ^ (" " ^ (pphex cie1.cie_id + ^ (" CIE\n" + ^ (" Version: " ^ (Nat_big_num.to_string cie1.cie_version ^ ("\n" + ^ (" Augmentation: \""^ (string_of_string (Xstring.implode (Lem_list.map (fun x-> x) cie1.cie_augmentation)) ^ ("\"\n" + ^ (" Code alignment factor: " ^ (Nat_big_num.to_string cie1.cie_code_alignment_factor ^ ("\n" + ^ (" Data alignment factor: " ^ (Nat_big_num.to_string cie1.cie_data_alignment_factor ^ ("\n" + ^ (" Return address column: " ^ (Nat_big_num.to_string cie1.cie_return_address_register ^ ("\n" + ^ ("\n" + ^ (ppbytes instance_Show_Show_Missing_pervasives_byte_dict cie1.cie_initial_instructions_bytes ^ ("\n" + ^ pp_call_frame_instructions cie1.cie_initial_instructions)))))))))))))))))))))))) + +(* cie_address_size: natural; (* not shown by readelf - must match compilation unit *)*) +(* cie_segment_size: natural; (* not shown by readelf *)*) +(* readelf says "Return address column", but the DWARF spec says "Return address register" *) + + +let pp_fde c cuh fde1:string= + (pphex fde1.fde_offset + ^ (" " ^ (pphex fde1.fde_length + ^ (" " ^ (pphex fde1.fde_cie_pointer (* not what this field of readelf output is *) + ^ (" FDE" + ^ (" cie=" ^ (pphex fde1.fde_cie_pointer (* duplicated?? *) + ^ (" pc=" ^ ((match fde1.fde_initial_location_segment_selector with None -> "" | Some segment_selector -> "("^(pphex segment_selector^")") ) ^ (pphex fde1.fde_initial_location_address ^ (".." ^ (pphex ( Nat_big_num.add fde1.fde_initial_location_address fde1.fde_address_range) ^ ("\n" + ^ (ppbytes instance_Show_Show_Missing_pervasives_byte_dict fde1.fde_instructions_bytes ^ ("\n" + ^ pp_call_frame_instructions fde1.fde_instructions)))))))))))))))) + +let pp_frame_info_element c cuh fie:string= + ((match fie with + | FIE_cie cie1 -> pp_cie c cuh cie1 + | FIE_fde fde1 -> pp_fde c cuh fde1 + )) + +let pp_frame_info c cuh fi:string= + ("Contents of the .debug_frame section:\n\n" + ^ (myconcat "\n" (Lem_list.map (pp_frame_info_element c cuh) fi) + ^ "\n")) + + + +let rec find_cie fi cie_id1:cie= + ((match fi with + | [] -> failwith "find_cie: cie_id not found" + | FIE_fde _ :: fi' -> find_cie fi' cie_id1 + | FIE_cie cie1 :: fi' -> if Nat_big_num.equal cie_id1 cie1.cie_offset then cie1 else find_cie fi' cie_id1 + )) + +let parse_initial_location c cuh mss mas' : (( Nat_big_num.num option) * Nat_big_num.num) parser= +( (*(segment selector and target address)*) + (* assume segment selector size is zero unless given explicitly. Probably we need to do something architecture-specific for earlier dwarf versions?*)parse_pair + (parse_uint_segment_selector_size c ((match mss with Some n -> n | None ->Nat_big_num.of_int 0 ))) + (parse_uint_address_size c ((match mas' with Some n -> n | None -> cuh.cuh_address_size )))) + + +let parse_call_frame_instruction_bytes offset' ul:parse_context ->((char)list)parse_result= + (fun (pc: parse_context) -> + parse_n_bytes ( Nat_big_num.sub_nat ul ( Nat_big_num.sub_nat pc.pc_offset offset')) pc) + +let parse_frame_info_element c cuh (fi: frame_info_element list) : frame_info_element parser= + (parse_dependent + (pr_with_pos + (parse_dependent_pair + (parse_unit_length c) + (fun (df,ul) -> + pr_with_pos + (parse_uintDwarfN c df) (* CIE_id (cie) or CIE_pointer (fde) *) + ))) + (fun (offset,((df,ul),(offset',cie_id1))) -> + if ( Nat_big_num.equal cie_id1 + (match df with + | Dwarf32 -> natural_of_hex "0xffffffff" + | Dwarf64 -> natural_of_hex "0xffffffffffffffff" + )) + then + (* parse cie *) + pr_post_map + (parse_pair + (parse_dependent_pair + parse_uint8 (* version *) + (fun v -> + parse_triple + parse_string (* augmentation *) + (if Nat_big_num.equal v(Nat_big_num.of_int 4) ||Nat_big_num.equal v(Nat_big_num.of_int 46) then pr_post_map parse_uint8 (fun i->Some i) else pr_return None) (* address_size *) + (if Nat_big_num.equal v(Nat_big_num.of_int 4) ||Nat_big_num.equal v(Nat_big_num.of_int 46) then pr_post_map parse_uint8 (fun i->Some i) else pr_return None))) (* segment_size *) + (parse_quadruple + parse_ULEB128 (* code_alignment_factor *) + parse_SLEB128 (* data_alignment_factor *) + parse_ULEB128 (* return address register *) + (parse_call_frame_instruction_bytes offset' ul))) + (fun ( (v,(aug,(mas',mss))), (caf,(daf,(rar,bs))) ) -> + let pc = ({pc_bytes = bs; pc_offset =(Nat_big_num.of_int 0) }) in + (match parse_call_frame_instructions c cuh pc with + | PR_success( is, _) -> + FIE_cie + ( + { + cie_offset = offset; + cie_length = ul; + cie_id = cie_id1; + cie_version = v; + cie_augmentation = aug; + cie_address_size = mas'; + cie_segment_size = mss; + cie_code_alignment_factor = caf; + cie_data_alignment_factor = daf; + cie_return_address_register = rar; + cie_initial_instructions_bytes = bs; + cie_initial_instructions = is; + }) + | PR_fail( s, _) -> failwith s + ) + ) + + else + (* parse fde *) + let cie1 = (find_cie fi cie_id1) in + let _ = (my_debug4 (pp_cie c cuh cie1)) in + pr_post_map + (parse_triple + (parse_initial_location c cuh cie1.cie_segment_size cie1.cie_address_size) (*(segment selector and target address)*) + (parse_uint_address_size c ((match cie1.cie_address_size with Some n -> n | None -> cuh.cuh_address_size ))) (* address_range (target address) *) + (parse_call_frame_instruction_bytes offset' ul) + ) + (fun ( (ss,adr), (ar, bs)) -> + let pc = ({pc_bytes = bs; pc_offset =(Nat_big_num.of_int 0) }) in + (match parse_call_frame_instructions c cuh pc with + | PR_success( is, _) -> + FIE_fde + ( + { + fde_offset = offset; + fde_length = ul; + fde_cie_pointer = cie_id1; + fde_initial_location_segment_selector = ss; + fde_initial_location_address = adr; + fde_address_range = ar; + fde_instructions_bytes = bs; + fde_instructions = is; + } ) + | PR_fail( s, _) -> failwith s + ) + ) + )) + +(* you can't even parse an fde without accessing the cie it refers to +(to determine the segment selector size). Gratuitous complexity or what? +Hence the following, which should be made more tail-recursive. *) + +(*val parse_dependent_list' : forall 'a. (list 'a -> parser 'a) -> list 'a -> parser (list 'a)*) +let rec parse_dependent_list' p1 acc:parse_context ->('a list)parse_result= + (fun pc -> + if (listEqualBy (=) pc.pc_bytes []) then + PR_success( (List.rev acc), pc) + else + pr_bind + (p1 acc pc) + (fun x pc' -> + parse_dependent_list' p1 (x::acc) pc')) + +(*val parse_dependent_list : forall 'a. (list 'a -> parser 'a) -> parser (list 'a)*) +let parse_dependent_list p1:parse_context ->('a list)parse_result= (parse_dependent_list' p1 []) + + +let parse_frame_info c cuh : frame_info parser= + +(parse_dependent_list (parse_frame_info_element c cuh)) + + +(** line numbers .debug_line, pp and parsing *) + +let pp_line_number_file_entry lnfe:string= + ("lnfe_path = " ^ (string_of_bytes lnfe.lnfe_path ^ ("\n" +^ ("lnfe_directory_index " ^ (Nat_big_num.to_string lnfe.lnfe_directory_index ^ ("\n" +^ ("lnfe_last_modification = " ^ (Nat_big_num.to_string lnfe.lnfe_last_modification ^ ("\n" +^ ("lnfe_length = " ^ (Nat_big_num.to_string lnfe.lnfe_length ^ "\n"))))))))))) + + +let pp_line_number_header lnh:string= + ("offset = " ^ (pphex lnh.lnh_offset ^ ("\n" +^ ("dwarf_format = " ^ (pp_dwarf_format lnh.lnh_dwarf_format ^ ("\n" +^ ("unit_length = " ^ (Nat_big_num.to_string lnh.lnh_unit_length ^ ("\n" +^ ("version = " ^ (Nat_big_num.to_string lnh.lnh_version ^ ("\n" +^ ("header_length = " ^ (Nat_big_num.to_string lnh.lnh_header_length ^ ("\n" +^ ("minimum_instruction_length = " ^ (Nat_big_num.to_string lnh.lnh_minimum_instruction_length ^ ("\n" +^ ("maximum_operations_per_instruction = " ^ (Nat_big_num.to_string lnh.lnh_maximum_operations_per_instruction ^ ("\n" +^ ("default_is_stmt = " ^ (string_of_bool lnh.lnh_default_is_stmt ^ ("\n" +^ ("line_base = " ^ (Nat_big_num.to_string lnh.lnh_line_base ^ ("\n" +^ ("line_range = " ^ (Nat_big_num.to_string lnh.lnh_line_range ^ ("\n" +^ ("opcode_base = " ^ (Nat_big_num.to_string lnh.lnh_opcode_base ^ ("\n" +^ ("standard_opcode_lengths = " ^ (string_of_list + instance_Show_Show_Num_natural_dict lnh.lnh_standard_opcode_lengths ^ ("\n" +^ ("include_directories = " ^ (myconcat ", " (Lem_list.map string_of_bytes lnh.lnh_include_directories) ^ ("\n" +^ ("file_names = \n\n" ^ (myconcat "\n" (Lem_list.map pp_line_number_file_entry lnh.lnh_file_names) ^ "\n"))))))))))))))))))))))))))))))))))))))))) + +let pp_line_number_operation lno:string= + ((match lno with + | DW_LNS_copy -> "DW_LNS_copy" + | DW_LNS_advance_pc n -> "DW_LNS_advance_pc" ^ (" " ^ Nat_big_num.to_string n) + | DW_LNS_advance_line i -> "DW_LNS_advance_line" ^ (" " ^ Nat_big_num.to_string i) + | DW_LNS_set_file n -> "DW_LNS_set_file" ^ (" " ^ Nat_big_num.to_string n) + | DW_LNS_set_column n -> "DW_LNS_set_column" ^ (" " ^ Nat_big_num.to_string n) + | DW_LNS_negate_stmt -> "DW_LNS_negate_stmt" + | DW_LNS_set_basic_block -> "DW_LNS_set_basic_block" + | DW_LNS_const_add_pc -> "DW_LNS_const_add_pc" + | DW_LNS_fixed_advance_pc n -> "DW_LNS_fixed_advance_pc" ^ (" " ^ Nat_big_num.to_string n) + | DW_LNS_set_prologue_end -> "DW_LNS_set_prologue_end" + | DW_LNS_set_epilogue_begin -> "DW_LNS_set_epilogue_begin" + | DW_LNS_set_isa n -> "DW_LNS_set_isa" ^ (" " ^ Nat_big_num.to_string n) + | DW_LNE_end_sequence -> "DW_LNE_end_sequence" + | DW_LNE_set_address n -> "DW_LNE_set_address" ^ (" " ^ pphex n) + | DW_LNE_define_file( s, n1, n2, n3) -> "DW_LNE_define_file" ^ (" " ^ (string_of_list + instance_Show_Show_Missing_pervasives_byte_dict s ^ (" " ^ (Nat_big_num.to_string n1 ^ (" " ^ (Nat_big_num.to_string n2 ^ (" " ^ Nat_big_num.to_string n3))))))) + | DW_LNE_set_discriminator n -> "DW_LNE_set_discriminator" ^ (" " ^ Nat_big_num.to_string n) + | DW_LN_special n -> "DW_LN_special" ^ (" " ^ Nat_big_num.to_string n) + )) + +let pp_line_number_program lnp:string= + (pp_line_number_header lnp.lnp_header + ^ ("[" ^ (myconcat ", " (Lem_list.map pp_line_number_operation lnp.lnp_operations) ^ "]\n"))) + + + +let parse_line_number_file_entry : ( line_number_file_entry option) parser= + +(parse_dependent + (parse_non_empty_string) + (fun ms -> + (match ms with + | None -> + pr_return None + | Some s -> + pr_post_map + (parse_triple + parse_ULEB128 + parse_ULEB128 + parse_ULEB128 + ) + (fun (n1,(n2,n3)) -> + (Some + { + lnfe_path = s; + lnfe_directory_index = n1; + lnfe_last_modification = n2; + lnfe_length = n3; + } ) + ) + ) + )) + +let parse_line_number_header c : line_number_header parser= + (parse_dependent + ((pr_with_pos + (parse_unit_length c) )) + (fun (pos,(df,ul)) -> + parse_dependent + (parse_pair + (parse_triple + (parse_uint16 c) (* version *) + (parse_uintDwarfN c df) (* header_length *) + (parse_uint8) (* minimum_instruction_length *) + (* (parse_uint8) (* maximum_operations_per_instruction *) NOT IN DWARF 2*) + ) + (parse_quadruple + (parse_uint8) (* default_is_stmt *) + (parse_sint8) (* line_base *) + (parse_uint8) (* line_range *) + (parse_uint8) (* opcode_base *) + )) + (fun ((v,(hl,(minil(*,maxopi*)))),(dis,(lb,(lr,ob)))) -> + pr_post_map + (parse_triple + (pr_post_map (parse_n_bytes (Nat_big_num.sub_nat ob(Nat_big_num.of_int 1))) (Lem_list.map natural_of_byte)) (* standard_opcode_lengths *) + ((*pr_return [[]]*) parse_list parse_non_empty_string) (* include_directories *) + (parse_list parse_line_number_file_entry) (* file names *) + ) + (fun (sols, (ids, fns)) -> + { + lnh_offset = pos; + lnh_dwarf_format = df; + lnh_unit_length = ul; + lnh_version = v; + lnh_header_length = hl; + lnh_minimum_instruction_length = minil; + lnh_maximum_operations_per_instruction =(Nat_big_num.of_int 1) (*maxopi*); + lnh_default_is_stmt = (not (Nat_big_num.equal dis(Nat_big_num.of_int 0))); + lnh_line_base = lb; + lnh_line_range = lr; + lnh_opcode_base = ob; + lnh_standard_opcode_lengths = sols; + lnh_include_directories = ids; + lnh_file_names = fns; + } + ) + ) + ) + ) + +let parser_of_line_number_argument_type c (cuh: compilation_unit_header) (lnat: line_number_argument_type) : line_number_argument_value parser= + ((match lnat with + | LNAT_address -> pr_map2 (fun n -> LNAV_address n) (parse_uint_address_size c cuh.cuh_address_size) + | LNAT_ULEB128 -> pr_map2 (fun n -> LNAV_ULEB128 n) (parse_ULEB128) + | LNAT_SLEB128 -> pr_map2 (fun i -> LNAV_SLEB128 i) (parse_SLEB128) + | LNAT_uint16 -> pr_map2 (fun n -> LNAV_uint16 n) (parse_uint16 c) + | LNAT_string -> pr_map2 (fun s -> LNAV_string s) (parse_string) + )) + +let parse_line_number_operation c (cuh: compilation_unit_header) (lnh: line_number_header) : line_number_operation parser= + (parse_dependent + parse_uint8 + (fun opcode -> + if Nat_big_num.equal opcode(Nat_big_num.of_int 0) then + (* parse extended opcode *) + parse_dependent + (parse_pair + parse_ULEB128 + parse_uint8) + (fun (size2,opcode') -> + (match lookup_aBcd_acd + instance_Basic_classes_Eq_Num_natural_dict opcode' line_number_extended_encodings with + | Some (_, arg_types, result) -> + let ps = (Lem_list.map (parser_of_line_number_argument_type c cuh) arg_types) in + parse_demaybe ("parse_line_number_operation fail") + (pr_post_map + (parse_parser_list ps) + result ) + | None -> + failwith ("parse_line_number_operation extended opcode not found: " ^ Nat_big_num.to_string opcode') + )) + (* it's not clear what the ULEB128 size field is for, as the extended opcides all seem to have well-defined sizes. perhaps there can be extra padding that needs to be absorbed? *) + else if Nat_big_num.greater_equal opcode lnh.lnh_opcode_base then + (* parse special opcode *) + let adjusted_opcode = (Nat_big_num.sub_nat opcode lnh.lnh_opcode_base) in + pr_return (DW_LN_special adjusted_opcode) + else + (* parse standard opcode *) + (match lookup_aBcd_acd + instance_Basic_classes_Eq_Num_natural_dict opcode line_number_standard_encodings with + | Some (_, arg_types, result) -> + let ps = (Lem_list.map (parser_of_line_number_argument_type c cuh) arg_types) in + parse_demaybe ("parse_line_number_operation fail") + (pr_post_map + (parse_parser_list ps) + result) + | None -> + failwith ("parse_line_number_operation standard opcode not found: " ^ Nat_big_num.to_string opcode) + (* the standard_opcode_lengths machinery is intended to allow vendor specific extension instructions to be parsed and ignored, but here we couldn't usefully process such instructions in any case, so we just fail *) + ))) + + +let parse_line_number_operations c (cuh:compilation_unit_header) (lnh:line_number_header) : ( line_number_operation list) parser= + (parse_list (parse_maybe (parse_line_number_operation c cuh lnh))) + + + (* assume operations start immediately after the header - not completely clear in DWARF whether the header_length is just an optimisation or whether it's intended to allow the operations to start later *) + (* line number operations have no no-op and no termination operation, so we have to cut down the available bytes to the right length *) + +let parse_line_number_program c (cuh:compilation_unit_header) : line_number_program parser= + (parse_dependent + (parse_line_number_header c) + (fun lnh -> + let byte_count_of_operations = (Nat_big_num.sub_nat + lnh.lnh_unit_length ( Nat_big_num.add (Nat_big_num.add lnh.lnh_header_length(Nat_big_num.of_int 2)) ((match lnh.lnh_dwarf_format with Dwarf32 ->Nat_big_num.of_int 4 | Dwarf64 ->Nat_big_num.of_int 8 )))) in + pr_post_map + (parse_restrict_length + byte_count_of_operations + (parse_line_number_operations c cuh lnh) + ) + (fun ops -> + { + lnp_header = lnh; + lnp_operations = ops; + }) + )) + +let parse_line_number_info c (d_line: char list) (cu: compilation_unit) : line_number_program= + (let f n= + (let d_line' = ((match mydrop n d_line with Some xs -> xs | None -> failwith "parse_line_number_info drop" )) in + let pc = ({ pc_bytes = d_line'; pc_offset = n}) in + (match parse_line_number_program c cu.cu_header pc with + | PR_success( lnp, pc') -> + (*let _ = print_endline (pp_line_number_program lnp) in*) + lnp + | PR_fail( s, pc') -> failwith ("parse_line_number_header failed: " ^ s) + )) in + (match find_attribute_value "DW_AT_stmt_list" cu.cu_die with + | Some (AV_sec_offset n) -> f n + | Some (AV_block( n, bs)) -> f (natural_of_bytes c.endianness bs) + (* a 32-bit MIPS example used a 4-byte AV_block not AV_sec_offset *) + | Some _ -> failwith "compilation unit DW_AT_stmt_list attribute was not an AV_sec_offset" + | _ -> failwith "compilation unit did not have a DW_AT_stmt_list attribute" + )) + + +let parse_line_number_infos c debug_line_section_body compilation_units1:(line_number_program)list= + + (Lem_list.map (parse_line_number_info c debug_line_section_body) compilation_units1) + +let pp_line_info li:string= + +(myconcat "\n" (Lem_list.map (pp_line_number_program) li)) + + +(** all dwarf info: pp and parsing *) + +let pp_dwarf d:string= + (let c : p_context = ({ endianness = (d.d_endianness) }) in + + "\n************** .debug_info section - abbreviated *****************\n" + ^ (pp_compilation_units_abbrev c d.d_str d.d_compilation_units + ^ ("\n************** .debug_info section - full ************************\n" + ^ (pp_compilation_units c d.d_str d.d_compilation_units + ^ ("\n************** .debug_loc section: location lists ****************\n" + ^ (let (cuh_default : compilation_unit_header) = (let cu = (myhead d.d_compilation_units) in cu.cu_header) in + pp_loc c cuh_default d.d_loc + ^ ("\n************** .debug_ranges section: range lists ****************\n" + ^ (pp_ranges c cuh_default d.d_ranges + ^ ("\n************** .debug_frame section: frame info ****************\n" + ^ (pp_frame_info c cuh_default d.d_frame_info + ^ ("\n************** .debug_line section: line number info ****************\n" + ^ pp_line_info d.d_line_info))))))))))) + + +let parse_dwarf c + (debug_info_section_body: char list) + (debug_abbrev_section_body: char list) + (debug_str_section_body: char list) + (debug_loc_section_body: char list) + (debug_ranges_section_body: char list) + (debug_frame_section_body: char list) + (debug_line_section_body: char list) + : dwarf= + + (let pc_info = ({pc_bytes = debug_info_section_body; pc_offset =(Nat_big_num.of_int 0) }) in + + let compilation_units1 = + ((match parse_compilation_units c debug_str_section_body debug_abbrev_section_body pc_info with + | PR_fail( s, pc_info') -> failwith ("parse_compilation_units: " ^ pp_parse_fail s pc_info') + | PR_success( cus, pc_info') -> cus + )) in + + (*let _ = my_debug5 (pp_compilation_units c debug_str_section_body compilation_units) in*) + + +(* the DWARF4 spec doesn't seem to specify the address size used in the .debug_loc section, so we (hackishly) take it from the first compilation unit *) + let (cuh_default : compilation_unit_header) = (let cu = (myhead compilation_units1) in cu.cu_header) in + + let pc_loc = ({pc_bytes = debug_loc_section_body; pc_offset =(Nat_big_num.of_int 0) }) in + + let loc = + ((match parse_location_list_list c cuh_default pc_loc with + | PR_fail( s, pc_info') -> failwith ("parse_location_list: " ^ pp_parse_fail s pc_info') + | PR_success( loc, pc_loc') -> loc + )) in + + let pc_ranges = ({pc_bytes = debug_ranges_section_body; pc_offset =(Nat_big_num.of_int 0) }) in + + let ranges = + ((match parse_range_list_list c cuh_default pc_ranges with + | PR_fail( s, pc_info') -> failwith ("parse_range_list: " ^ pp_parse_fail s pc_info') + | PR_success( r, pc_loc') -> r + )) in + + let pc_frame = ({pc_bytes = debug_frame_section_body; pc_offset =(Nat_big_num.of_int 0) }) in + + let fi = + (let _ = (my_debug5 ("debug_frame_section_body:\n" ^ ppbytes2 + instance_Show_Show_Missing_pervasives_byte_dict(Nat_big_num.of_int 0) debug_frame_section_body)) in + + (match parse_frame_info c cuh_default pc_frame with + | PR_fail( s, pc_info') -> failwith ("parse_frame_info: " ^ pp_parse_fail s pc_info') + | PR_success( fi, pc_loc') -> fi + )) in + + let li = (parse_line_number_infos c debug_line_section_body compilation_units1) in + + { + d_endianness = (c.endianness); + d_str = debug_str_section_body; + d_compilation_units = compilation_units1; + d_type_units = ([]); + d_loc = loc; + d_ranges = ranges; + d_frame_info = fi; + d_line_info = li; + }) + +(*val extract_dwarf : elf_file -> maybe dwarf*) +let extract_dwarf f:(dwarf)option= + + (let (en: Endianness.endianness) = + ((match f with + | ELF_File_32 f32 -> Elf_header.get_elf32_header_endianness f32.Elf_file.elf32_file_header + | ELF_File_64 f64 -> Elf_header.get_elf64_header_endianness f64.Elf_file.elf64_file_header + )) in + let (c: p_context) = ({ endianness = en }) in + let extract_section_body section_name (strict: bool)= + ((match f with + | ELF_File_32 f32 -> + let sections = + (List.filter + (fun x -> + x.Elf_interpreted_section.elf32_section_name_as_string = section_name + ) f32.elf32_file_interpreted_sections) in + (match sections with + | [section] -> + let section_body = ((match section.Elf_interpreted_section.elf32_section_body with Sequence bs -> bs )) in + let _ = (my_debug4 (section_name ^ (": \n" ^ (Elf_interpreted_section.string_of_elf32_interpreted_section section ^ ("\n" + ^ (" body = " ^ (ppbytes2 + instance_Show_Show_Missing_pervasives_byte_dict(Nat_big_num.of_int 0) section_body ^ "\n"))))))) in + section_body + | [] -> + if strict then + failwith ("" ^ (section_name ^ " section not present")) + else + [] + | _ -> failwith ("multiple " ^ (section_name ^ " sections present")) + ) + + + | ELF_File_64 f64 -> + let sections = + (List.filter + (fun x -> + x.Elf_interpreted_section.elf64_section_name_as_string = section_name + ) f64.elf64_file_interpreted_sections) in + (match sections with + | [section] -> + let section_body = ((match section.Elf_interpreted_section.elf64_section_body with Sequence bs -> bs )) in + section_body + | [] -> + if strict then + failwith ("" ^ (section_name ^ " section not present")) + else + [] + | _ -> failwith ("multiple " ^ (section_name ^ " sections present")) + ) + )) in + + let debug_info_section_body = (extract_section_body ".debug_info" true) in + let debug_abbrev_section_body = (extract_section_body ".debug_abbrev" false) in + let debug_str_section_body = (extract_section_body ".debug_str" false) in + let debug_loc_section_body = (extract_section_body ".debug_loc" false) in + let debug_ranges_section_body = (extract_section_body ".debug_ranges" false) in + let debug_frame_section_body = (extract_section_body ".debug_frame" false) in + let debug_line_section_body = (extract_section_body ".debug_line" false) in + + let d = (parse_dwarf c debug_info_section_body debug_abbrev_section_body debug_str_section_body debug_loc_section_body debug_ranges_section_body debug_frame_section_body debug_line_section_body) in + + Some d) + + +(** ************************************************************ *) +(** ****** location evaluation ******************************** *) +(** ************************************************************ *) + + +(** pp of locations *) + +(*val pp_simple_location : simple_location -> string*) +let pp_simple_location sl:string= + ((match sl with + | SL_memory_address n -> pphex n + | SL_register n -> "reg" ^ Nat_big_num.to_string n + | SL_implicit bs -> "value: " ^ ppbytes + instance_Show_Show_Missing_pervasives_byte_dict bs + | SL_empty -> "<empty>" + )) + +(*val pp_composite_location_piece : composite_location_piece -> string*) +let pp_composite_location_piece clp:string= + ((match clp with + | CLP_piece( n, sl) -> "piece (" ^ (Nat_big_num.to_string n ^ (") " ^ pp_simple_location sl)) + | CLP_bit_piece( n1, n2, sl) -> "bit_piece (" ^ (Nat_big_num.to_string n1 ^ ("," ^ (Nat_big_num.to_string n2 ^ (") " ^ pp_simple_location sl)))) + )) + +(*val pp_single_location: single_location -> string*) +let pp_single_location sl:string= + ((match sl with + | SL_simple sl -> pp_simple_location sl + | SL_composite clps -> "composite: " ^ myconcat ", " (Lem_list.map pp_composite_location_piece clps) + )) + + +(** evaluation of location expressions *) + +(* cf dwarflist, btw: https://fedorahosted.org/elfutils/wiki/DwarfLint?format=txt *) + +(* + +location description ::= +| single location description +| location list + +single location description ::= +| simple location description +| composite location description + +simple location description ::= +| memory location description : non-empty dwarf expr, value is address of all or part of object in memory +| register location description : single DW_OP_regN or DW_OP_regx, naming a register in which all the object is +| implicit location description : single DW_OP_implicit_value or a non-empty dwarf expr ending in DW_OP_stack_value, giving the value of all/part of object +| empty location description : an empty dwarf expr, indicating a part or all of an object that is not represented + +composite location description : a list of simple location descriptions, each followed by a DW_OP_piece or DW_OP_bitpiece + +(the simple location description can be a register location description: https://www.mail-archive.com/dwarf-discuss@lists.dwarfstd.org/msg00271.html) +(contradicting "A register location description must stand alone as the entire description of an object or a piece of an object.") + +location list entry : a list of address ranges (possibly overlapping), each with a single location description + +Dwarf expressions can include data-dependent control flow choices +(though we don't see that in the examples?), so we can't statically +determine which kind of single location description or simple location +description we have. We can distinguish: + +- empty -> simple.empty +- DW_OP_regN/DW_OP_regx -> simple.register +- DW_OP_implicit_value -> simple.implicit +- any of those followed by DW_OP_piece or DW_OP_bitpiece, perhaps followed by more composite parts -> composite part :: composite + +otherwise run to the end, or a DW_OP_stack_value at the end, or to +anything (except a DO_OP_regN/DW_OP_regx) followed by a +DW_OP_piece/DW_OP_bitpiece. Pfeh. + + +actually used in our examples (ignoring GNU extentions): + +DW_OP_addr literal +DW_OP_lit1 literal +DW_OP_const4u literal + +DW_OP_breg3 (r3) read register value and add offset + +DW_OP_and bitwise and +DW_OP_plus addition (mod whatever) + +DW_OP_deref_size +DW_OP_fbreg evaluate location description from DW_AT_frame_base attribute of the current function (which is DW_OP_call_frame_cfa in our examples) and add offset + +DW_OP_implicit_value the argument block is the actual value (not location) of the entity in question +DW_OP_stack_value use the value at top of stack as the actual value (not location) of the entity in question + +DW_OP_reg0 (r0)) read register value + +DW_OP_call_frame_cfa go off to 6.4 and pull info out of .debug_frame (possibly involving other location expressions) + +*) + + + +let initial_state:state= + ({ + s_stack = ([]); + s_value = SL_empty; + s_location_pieces = ([]); +}) + +(* the main location expression evaluation function *) + +(* location expression evaluation is basically a recursive function +down a list of operations, maintaining an operation_stack (a list of +naturals representing machine-address-size words), the current +simple_location, and a list of any composite_location_piece's +accumulated so far *) + + + +let arithmetic_context_of_cuh cuh:arithmetic_context= + ( + if(Nat_big_num.equal cuh.cuh_address_size (Nat_big_num.of_int 8)) then + ({ ac_bitwidth =(Nat_big_num.of_int 64); + ac_half = (Nat_big_num.pow_int (Nat_big_num.of_int 2) ( 32)); + ac_all = (Nat_big_num.pow_int (Nat_big_num.of_int 2) ( 64)); + ac_max = (Nat_big_num.sub_nat + (Nat_big_num.pow_int (Nat_big_num.of_int 2) ( 64)) + (Nat_big_num.of_int 1)); }) else + ( + if(Nat_big_num.equal cuh.cuh_address_size (Nat_big_num.of_int 4)) then + ({ ac_bitwidth =(Nat_big_num.of_int 32); + ac_half = (Nat_big_num.pow_int (Nat_big_num.of_int 2) ( 16)); + ac_all = (Nat_big_num.pow_int (Nat_big_num.of_int 2) ( 32)); + ac_max = (Nat_big_num.sub_nat + (Nat_big_num.pow_int (Nat_big_num.of_int 2) ( 32)) + (Nat_big_num.of_int 1)); }) else + (failwith "arithmetic_context_of_cuh given non-4/8 size"))) + +let find_cfa_table_row_for_pc (evaluated_frame_info1: evaluated_frame_info) (pc: Nat_big_num.num) : cfa_table_row= + ((match + myfind + (fun (fde1,rows) -> Nat_big_num.greater_equal pc fde1.fde_initial_location_address && Nat_big_num.less pc (Nat_big_num.add fde1.fde_initial_location_address fde1.fde_address_range)) + evaluated_frame_info1 + with + | Some (fde1,rows) -> + (match myfind (fun row -> Nat_big_num.greater_equal pc row.ctr_loc) rows with + | Some row -> row + | None -> failwith "evaluate_cfa: no matchine row" + ) + | None -> failwith "evaluate_cfa: no fde encloding pc" + )) + + +let rec evaluate_operation_list (c:p_context) (dloc: location_list_list) (evaluated_frame_info1: evaluated_frame_info) (cuh: compilation_unit_header) (ac: arithmetic_context) (ev: evaluation_context) (mfbloc: attribute_value option) (pc: Nat_big_num.num) (s: state) (ops: operation list) : single_location error= + + (let push_memory_address v vs'= (Success { s with s_stack = (v :: vs'); s_value = (SL_memory_address v) }) in + + let push_memory_address_maybe (mv: Nat_big_num.num option) vs' (err:string) op= + ((match mv with + | Some v -> push_memory_address v vs' + | None -> Fail (err ^ pp_operation op) + )) in + + let bregxi r i= + ((match ev.read_register r with + | RRR_result v -> push_memory_address (partialNaturalFromInteger ( Nat_big_num.modulus(Nat_big_num.add( v)i) ( ac.ac_all))) s.s_stack + | RRR_not_currently_available -> Fail "RRR_not_currently_available" + | RRR_bad_register_number -> Fail ("RRR_bad_register_number " ^ Nat_big_num.to_string r) + )) in + + let deref_size n= + ((match s.s_stack with + | v::vs' -> + (match ev.read_memory v n with + | MRR_result v' -> push_memory_address v' vs' + | MRR_not_currently_available -> Fail "MRR_not_currently_available" + | MRR_bad_address -> Fail "MRR_bad_address" + ) + | _ -> Fail "OpSem unary not given an element on stack" + )) in + + (match ops with + | [] -> + if (listEqualBy (=) s.s_location_pieces []) then + Success (SL_simple s.s_value) + else if s.s_value = SL_empty then + Success (SL_composite s.s_location_pieces) + else + (* unclear what's supposed to happen in this case *) + Fail "unfinished part of composite expression" + + | op::ops' -> + let es' = + ((match (op.op_semantics, op.op_argument_values) with + | (OpSem_nop, []) -> + Success s + | (OpSem_lit, [OAV_natural n]) -> + push_memory_address n s.s_stack + | (OpSem_lit, [OAV_integer i]) -> + push_memory_address (partialTwosComplementNaturalFromInteger i ac.ac_half ( ac.ac_all)) s.s_stack + | (OpSem_stack f, []) -> + (match f ac s.s_stack op.op_argument_values with + | Some stack' -> + let value' : simple_location = ((match stack' with [] -> SL_empty | v'::_ -> SL_memory_address v' )) in + Success { s with s_stack = stack'; s_value = value' } + | None -> Fail "OpSem_stack failed" + ) + | (OpSem_not_supported, []) -> + Fail ("OpSem_not_supported: " ^ pp_operation op) + | (OpSem_binary f, []) -> + (match s.s_stack with + | v1::v2::vs' -> push_memory_address_maybe (f ac v1 v2) vs' "OpSem_binary error: " op + | _ -> Fail "OpSem binary not given two elements on stack" + ) + | (OpSem_unary f, []) -> + (match s.s_stack with + | v1::vs' -> push_memory_address_maybe (f ac v1) vs' "OpSem_unary error: " op + | _ -> Fail "OpSem unary not given an element on stack" + ) + | (OpSem_opcode_lit base, []) -> + if Nat_big_num.greater_equal op.op_code base && Nat_big_num.less op.op_code (Nat_big_num.add base(Nat_big_num.of_int 32)) then + push_memory_address ( Nat_big_num.sub_nat op.op_code base) s.s_stack + else + Fail "OpSem_opcode_lit opcode not within [base,base+32)" + | (OpSem_reg, []) -> + (* TODO: unclear whether this should push the register id or not *) + let r = (Nat_big_num.sub_nat op.op_code vDW_OP_reg0) in + Success { s with s_stack = (r :: s.s_stack); s_value = (SL_register r) } + | (OpSem_breg, [OAV_integer i]) -> + let r = (Nat_big_num.sub_nat op.op_code vDW_OP_breg0) in + bregxi r i + | (OpSem_bregx, [OAV_natural r; OAV_integer i]) -> + bregxi r i + | (OpSem_deref, []) -> + deref_size cuh.cuh_address_size + | (OpSem_deref_size, [OAV_natural n]) -> + deref_size n + | (OpSem_fbreg, [OAV_integer i]) -> + (match mfbloc with + | Some fbloc -> + (*let _ = my_debug5 ("OpSem_fbreg (" ^ show i ^ ")\n") in*) + (match evaluate_location_description c dloc evaluated_frame_info1 cuh ac ev (*mfbloc*)None pc fbloc with + (* what to do if the recursive call also uses fbreg? for now assume that's not allowed *) + | Success l -> + (match l with + | SL_simple (SL_memory_address a) -> + (*let _ = my_debug5 ("OpSem_fbreg: a = "^ pphex a ^ "\n") in*) + let vi = (Nat_big_num.modulus ( Nat_big_num.add( a) i) ( ac.ac_all)) in + (*let _ = my_debug5 ("OpSem_fbreg: v = "^ show vi ^ "\n") in*) + let v = (partialNaturalFromInteger vi) (*ac.ac_half (integerFromNatural ac.ac_all)*) in + push_memory_address v s.s_stack + | _ -> + Fail "OpSem_fbreg got a non-SL_simple (SL_memory_address _) result" + (* "The DW_OP_fbreg operation provides a signed LEB128 + offset from the address specified by the location + description in the DW_AT_frame_base attribute of the + current function. " + - so what to do if the location description returns a non-memory-address location? *) + ) + | Fail e -> + Fail ("OpSem_fbreg failure: " ^ e) + ) + | None -> + Fail "OpSem_fbreg: no frame base location description given" + ) + + | (OpSem_piece, [OAV_natural size_bytes]) -> + let piece = (CLP_piece( size_bytes, s.s_value)) in + (* we allow a piece (or bit_piece) to be any simple_location, including implicit and stack values. Unclear if this is intended, esp. the latter *) + let stack' = ([]) in + let value' = SL_empty in + Success { s_stack = stack'; s_value = value'; s_location_pieces = (List.rev_append (List.rev s.s_location_pieces) [piece]) } + | (OpSem_bit_piece, [OAV_natural size_bits; OAV_natural offset_bits]) -> + let piece = (CLP_bit_piece( size_bits, offset_bits, s.s_value)) in + let stack' = ([]) in + let value' = SL_empty in + Success { s_stack = stack'; s_value = value'; s_location_pieces = (List.rev_append (List.rev s.s_location_pieces) [piece]) } + | (OpSem_implicit_value, [OAV_block( size2, bs)]) -> + let stack' = ([]) in + let value' = (SL_implicit bs) in + Success { s with s_stack = stack'; s_value = value' } + | (OpSem_stack_value, []) -> + (* "The DW_OP_stack_value operation terminates the expression." - does + this refer to just the subexpression, ie allowing a stack value to be + a piece of a composite location, or necessarily the whole expression? + Why does DW_OP_stack_value have this clause while DW_OP_implicit_value + does not? *) + (* why doesn't DW_OP_stack_value have a size argument? *) + (match s.s_stack with + | v::vs' -> + let stack' = ([]) in + let value' = (SL_implicit (bytes_of_natural c.endianness cuh.cuh_address_size v)) in + Success { s with s_stack = stack'; s_value = value' } + + | _ -> Fail "OpSem_stack_value not given an element on stack" + ) + | (OpSem_call_frame_cfa, []) -> + let row = (find_cfa_table_row_for_pc evaluated_frame_info1 pc) in + (match row.ctr_cfa with + | CR_undefined -> + failwith "evaluate_cfa of CR_undefined" + | CR_register( r, i) -> + bregxi r i (* same behaviour as an OpSem_bregx *) + | CR_expression bs -> + failwith "CR_expression" + (*TODO: fix result type - not this evaluate_location_description_bytes c dloc evaluated_frame_info cuh ac ev mfbloc pc bs*) + (* TODO: restrict allowed OpSem_* in that recursive call *) + ) + | (_, _) -> + Fail ("bad OpSem invocation: op=" ^ (pp_operation op ^ (" arguments=" ^ myconcat "" (Lem_list.map pp_operation_argument_value op.op_argument_values)))) + )) + in + (match es' with + | Success s' -> + evaluate_operation_list c dloc evaluated_frame_info1 cuh ac ev mfbloc pc s' ops' + | Fail e -> + Fail e + ) + )) + +and evaluate_location_description_bytes (c:p_context) (dloc: location_list_list) (evaluated_frame_info1: evaluated_frame_info) (cuh: compilation_unit_header) (ac: arithmetic_context) (ev: evaluation_context) (mfbloc: attribute_value option) (pc: Nat_big_num.num) (bs: char list) : single_location error= + (let parse_context1 = ({pc_bytes = bs; pc_offset =(Nat_big_num.of_int 0) }) in + (match parse_operations c cuh parse_context1 with + | PR_fail( s, pc') -> Fail ("evaluate_location_description_bytes: parse_operations fail: " ^ pp_parse_fail s pc') + | PR_success( ops, pc') -> + if not ((listEqualBy (=) pc'.pc_bytes [])) then + Fail "evaluate_location_description_bytes: extra non-parsed bytes" + else + evaluate_operation_list c dloc evaluated_frame_info1 cuh ac ev mfbloc pc initial_state ops + )) + +and evaluate_location_description (c:p_context) (dloc: location_list_list) (evaluated_frame_info1: evaluated_frame_info) (cuh: compilation_unit_header) (ac: arithmetic_context) (ev: evaluation_context) (mfbloc: attribute_value option) (pc: Nat_big_num.num) (loc:attribute_value) : single_location error= + ((match loc with + | AV_exprloc( n, bs) -> + evaluate_location_description_bytes c dloc evaluated_frame_info1 cuh ac ev mfbloc pc bs + | AV_block( n, bs) -> + evaluate_location_description_bytes c dloc evaluated_frame_info1 cuh ac ev mfbloc pc bs + | AV_sec_offset n -> + let location_list1 = (find_location_list dloc n) in + let (offset,(llis: location_list_item list)) = location_list1 in + let f (lli:location_list_item) : single_location_description option= + ((match lli with + | LLI_lle lle -> + if Nat_big_num.greater_equal pc lle.lle_beginning_address_offset && Nat_big_num.less pc lle.lle_ending_address_offset then Some lle.lle_single_location_description else None + | LLI_base _ -> + None (* TODO: either refactor to do offset during parsing or update base offsets here. Should refactor to use "interpreted". *) + )) in + (match myfindmaybe f llis with + | Some bs -> + evaluate_location_description_bytes c dloc evaluated_frame_info1 cuh ac ev mfbloc pc bs + | None -> + Fail "evaluate_location_description didn't find pc in location list ranges" + ) + | _ -> Fail "evaluate_location_description av_location not understood" + )) + + + + + +(** ************************************************************ *) +(** **** evaluation of frame information ********************** *) +(** ************************************************************ *) + +(** register maps *) + +(*val rrp_update : register_rule_map -> cfa_register -> register_rule -> register_rule_map*) +let rrp_update rrp r rr:(Nat_big_num.num*register_rule)list= ((r,rr)::rrp) + +(*val rrp_lookup : cfa_register -> register_rule_map -> register_rule*) +let rrp_lookup r rrp:register_rule= + ((match (lookupBy Nat_big_num.equal r rrp) with + | Some rr -> rr + | None -> RR_undefined + )) + +(*val rrp_empty : register_rule_map*) +let rrp_empty:(cfa_register*register_rule)list= ([]) + + + +(** pp of evaluated cfa information from .debug_frame *) +(* readelf --debug-dump=frames-interp test/a.out + +Contents of the .eh_frame section: + +00000000 00000014 00000000 CIE "zR" cf=1 df=-8 ra=16 + LOC CFA ra +0000000000000000 rsp+8 c-8 + +00000018 00000024 0000001c FDE cie=00000000 pc=004003b0..004003d0 + LOC CFA ra +00000000004003b0 rsp+16 c-8 +00000000004003b6 rsp+24 c-8 +00000000004003c0 exp c-8 + +00000040 0000001c 00000044 FDE cie=00000000 pc=004004b4..004004ba + LOC CFA rbp ra +00000000004004b4 rsp+8 u c-8 +00000000004004b5 rsp+16 c-16 c-8 +00000000004004b8 rbp+16 c-16 c-8 +00000000004004b9 rsp+8 c-16 c-8 + +00000060 00000024 00000064 FDE cie=00000000 pc=004004c0..00400549 + LOC CFA rbx rbp r12 r13 r14 r15 ra +00000000004004c0 rsp+8 u u u u u u c-8 +00000000004004d1 rsp+8 u c-48 c-40 u u u c-8 +00000000004004f0 rsp+64 c-56 c-48 c-40 c-32 c-24 c-16 c-8 +0000000000400548 rsp+8 c-56 c-48 c-40 c-32 c-24 c-16 c-8 + +00000088 00000014 0000008c FDE cie=00000000 pc=00400550..00400552 + LOC CFA ra +0000000000400550 rsp+8 c-8 + +000000a0 ZERO terminator +*) + + + +(*val mytoList : forall 'a. SetType 'a => set 'a -> list 'a*) + +let register_footprint_rrp (rrp: register_rule_map) : cfa_register Pset.set= + (Pset.from_list Nat_big_num.compare (Lem_list.map fst rrp)) + +let register_footprint (rows: cfa_table_row list) : cfa_register list= + (Pset.elements (bigunionListMap + instance_Basic_classes_SetType_Num_natural_dict (fun row -> register_footprint_rrp row.ctr_regs) rows)) + + +(*val max_lengths : list (list string) -> list natural*) +let rec max_lengths xss:(Nat_big_num.num)list= + ((match xss with + | [] -> failwith "max_lengths" + | xs::xss' -> + let lens = (Lem_list.map (fun x -> Nat_big_num.of_int (String.length x)) xs) in + if (listEqualBy (listEqualBy (=)) xss' []) then lens + else + let lens' = (max_lengths xss') in + let z = (Lem_list.list_combine lens lens') in + let lens'' = (Lem_list.map (fun (l1,l2)-> Nat_big_num.max l1 l2) z) in + lens'' + )) + +let rec pad_row xs lens:(string)list= + ((match (xs,lens) with + | ([],[]) -> [] + | (x::xs', len::lens') -> right_space_padded_to len x :: pad_row xs' lens' + )) + +let pad_rows (xss : ( string list) list) : string= + (let lens = (max_lengths xss) in + myconcat "" (Lem_list.map (fun xs -> myconcat " " (pad_row xs lens) ^ "\n") xss)) + +let pp_evaluated_fde (fde1, (rows: cfa_table_row list)) : string= + (let regs = (register_footprint rows) in + let header : string list = ("LOC" :: ("CFA" :: Lem_list.map + (pp_cfa_register instance_Show_Show_Num_natural_dict) regs)) in + let ppd_rows : ( string list) list = + (Lem_list.map (fun row -> pphex row.ctr_loc :: (pp_cfa_rule row.ctr_cfa :: Lem_list.map (fun r -> pp_register_rule (rrp_lookup r row.ctr_regs)) regs)) rows) in + pad_rows (header :: ppd_rows)) + + + +(** evaluation of cfa information from .debug_frame *) + +let evaluate_call_frame_instruction (fi: frame_info) (cie1: cie) (state1: cfa_state) (cfi: call_frame_instruction) : cfa_state= + + (let create_row (loc: Nat_big_num.num)= + (let row = ({ state1.cs_current_row with ctr_loc = loc }) in + { state1 with cs_current_row = row; cs_previous_rows = (state1.cs_current_row::state1.cs_previous_rows) }) in + + let update_cfa (cr:cfa_rule)= + (let row = ({ state1.cs_current_row with ctr_cfa = cr }) in + { state1 with cs_current_row = row }) in + + let update_reg r rr= + (let row = ({ state1.cs_current_row with ctr_regs = (rrp_update state1.cs_current_row.ctr_regs r rr) }) in + { state1 with cs_current_row = row }) in + + (match cfi with + (* Row Creation Instructions *) + | DW_CFA_set_loc a -> + create_row a + | DW_CFA_advance_loc d -> + create_row ( Nat_big_num.add state1.cs_current_row.ctr_loc (Nat_big_num.mul d cie1.cie_code_alignment_factor)) + | DW_CFA_advance_loc1 d -> + create_row ( Nat_big_num.add state1.cs_current_row.ctr_loc (Nat_big_num.mul d cie1.cie_code_alignment_factor)) + | DW_CFA_advance_loc2 d -> + create_row ( Nat_big_num.add state1.cs_current_row.ctr_loc (Nat_big_num.mul d cie1.cie_code_alignment_factor)) + | DW_CFA_advance_loc4 d -> + create_row ( Nat_big_num.add state1.cs_current_row.ctr_loc (Nat_big_num.mul d cie1.cie_code_alignment_factor)) + + (* CFA Definition Instructions *) + | DW_CFA_def_cfa( r, n) -> + update_cfa (CR_register( r, ( n))) + | DW_CFA_def_cfa_sf( r, i) -> + update_cfa (CR_register( r, ( Nat_big_num.mul i cie1.cie_data_alignment_factor))) + | DW_CFA_def_cfa_register r -> + (match state1.cs_current_row.ctr_cfa with + | CR_register( r', i) -> + update_cfa (CR_register( r, i)) + | _ -> failwith "DW_CFA_def_cfa_register: current rule is not CR_register" + ) + | DW_CFA_def_cfa_offset n -> + (match state1.cs_current_row.ctr_cfa with + | CR_register( r, i) -> + update_cfa (CR_register( r, ( n))) + | _ -> failwith "DW_CFA_def_cfa_offset: current rule is not CR_register" + ) + | DW_CFA_def_cfa_offset_sf i -> + (match state1.cs_current_row.ctr_cfa with + | CR_register( r, i') -> + update_cfa (CR_register( r, ( Nat_big_num.mul i' cie1.cie_data_alignment_factor))) + | _ -> failwith "DW_CFA_def_cfa_offset_sf: current rule is not CR_register" + ) + | DW_CFA_def_cfa_expression b -> + update_cfa (CR_expression b) + + (* Register Rule Instrutions *) + | DW_CFA_undefined r -> + update_reg r (RR_undefined) + | DW_CFA_same_value r -> + update_reg r (RR_same_value) + | DW_CFA_offset( r, n) -> + update_reg r (RR_offset ( Nat_big_num.mul( n) cie1.cie_data_alignment_factor)) + | DW_CFA_offset_extended( r, n) -> + update_reg r (RR_offset ( Nat_big_num.mul( n) cie1.cie_data_alignment_factor)) + | DW_CFA_offset_extended_sf( r, i) -> + update_reg r (RR_offset ( Nat_big_num.mul i cie1.cie_data_alignment_factor)) + | DW_CFA_val_offset( r, n) -> + update_reg r (RR_val_offset ( Nat_big_num.mul( n) cie1.cie_data_alignment_factor)) + | DW_CFA_val_offset_sf( r, i) -> + update_reg r (RR_val_offset ( Nat_big_num.mul i cie1.cie_data_alignment_factor)) + | DW_CFA_register( r1, r2) -> + update_reg r1 (RR_register r2) + | DW_CFA_expression( r, b) -> + update_reg r (RR_expression b) + | DW_CFA_val_expression( r, b) -> + update_reg r (RR_val_expression b) + | DW_CFA_restore r -> + update_reg r (rrp_lookup r state1.cs_initial_instructions_row.ctr_regs) +(* RR_undefined if the lookup fails? *) + | DW_CFA_restore_extended r -> + update_reg r (rrp_lookup r state1.cs_initial_instructions_row.ctr_regs) + +(* Row State Instructions *) +(* do these also push and restore the CFA rule? *) + | DW_CFA_remember_state -> + { state1 with cs_row_stack = (state1.cs_current_row :: state1.cs_row_stack) } + | DW_CFA_restore_state -> + (match state1.cs_row_stack with + | r::rs -> { state1 with cs_current_row = r; cs_row_stack = rs } + | [] -> failwith "DW_CFA_restore_state: empty row stack" + ) +(* Padding Instruction *) + | DW_CFA_nop -> + state1 + +(* Unknown *) + | DW_CFA_unknown b -> + failwith ("evaluate_call_frame_instruction: DW_CFA_unknown " ^ hex_string_of_byte b) + + )) + + + +let rec evaluate_call_frame_instructions (fi: frame_info) (cie1: cie) (state1: cfa_state) (cfis: call_frame_instruction list) : cfa_state= + ((match cfis with + | [] -> state1 + | cfi::cfis' -> + let state' = (evaluate_call_frame_instruction fi cie1 state1 cfi) in + evaluate_call_frame_instructions fi cie1 state' cfis' + )) + + +let evaluate_fde (fi: frame_info) (fde1:fde) : cfa_table_row list= + (let cie1 = (find_cie fi fde1.fde_cie_pointer) in + let final_location = (Nat_big_num.add fde1.fde_initial_location_address fde1.fde_address_range) in + let initial_cfa_state = + (let initial_row = + ({ + ctr_loc = (fde1.fde_initial_location_address); + ctr_cfa = CR_undefined; + ctr_regs = rrp_empty; + }) in + { + cs_current_row = initial_row; + cs_previous_rows = ([]); + cs_initial_instructions_row = initial_row; + cs_row_stack = ([]); + }) + in + let state' = + (evaluate_call_frame_instructions fi cie1 initial_cfa_state cie1.cie_initial_instructions) in + let initial_row' = (state'.cs_current_row) in + let state'' = ({ initial_cfa_state with cs_current_row = initial_row'; cs_initial_instructions_row = initial_row' }) in + let state''' = + (evaluate_call_frame_instructions fi cie1 (*final_location*) state'' fde1.fde_instructions) in + List.rev (state'''.cs_current_row:: state'''.cs_previous_rows)) + + + +(*val evaluate_frame_info : dwarf -> evaluated_frame_info*) +let evaluate_frame_info (d: dwarf) : evaluated_frame_info= + (Lem_list.mapMaybe (fun fie -> (match fie with FIE_fde fde1 -> Some (fde1, (evaluate_fde d.d_frame_info fde1)) | FIE_cie _ -> None )) d.d_frame_info) + +let pp_evaluated_frame_info (efi: evaluated_frame_info):string= + (myconcat "\n" (Lem_list.map pp_evaluated_fde efi)) + + + +(** ************************************************************ *) +(** ** analysis of location and frame data for reverse mapping *) +(** ************************************************************ *) + +(** analysis *) + +(*val find_dies_in_die : (die->bool) -> compilation_unit -> list die -> die -> list (compilation_unit * (list die) * die)*) +let rec find_dies_in_die (p:die->bool) (cu:compilation_unit) (parents: die list) (d: die):(compilation_unit*(die)list*die)list= + (let ds = (List.concat (map (find_dies_in_die p cu (d::parents)) d.die_children)) in + if p d then (cu,parents,d)::ds else ds) + +let find_dies (p:die->bool) (d: dwarf) : (compilation_unit * ( die list) * die) list= + (List.concat (map (fun cu -> find_dies_in_die p cu [] cu.cu_die) d.d_compilation_units)) + + +(** simple-minded analysis of location *) + +let analyse_locations_raw c (d: dwarf):string= + + (let (cuh_default : compilation_unit_header) = (let cu = (myhead d.d_compilation_units) in cu.cu_header) in + + (* find all DW_TAG_variable and DW_TAG_formal_parameter dies with a DW_AT_name attribute *) + let tags = (Lem_list.map tag_encode ["DW_TAG_variable"; "DW_TAG_formal_parameter"]) in + let dies : (compilation_unit * ( die list) * die) list = + (find_dies + (fun die1 -> + Lem_list.elem + instance_Basic_classes_Eq_Num_natural_dict die1.die_abbreviation_declaration.ad_tag tags + && has_attribute "DW_AT_name" die1) + d) in + + myconcat "" + (Lem_list.map + (fun (cu,parents,die1) -> + + let ats = (Lem_list.list_combine + die1.die_abbreviation_declaration.ad_attribute_specifications + die1.die_attribute_values) in + + let find_ats (s:string)= (myfindNonPure (fun (((at: Nat_big_num.num), (af: Nat_big_num.num)), ((pos: Nat_big_num.num),(av:attribute_value))) -> Nat_big_num.equal (attribute_encode s) at) ats) in + + let ((_,_),(_,av_name)) = (find_ats "DW_AT_name") in + + let name1 = + ((match av_name with + | AV_string bs -> string_of_bytes bs + | AV_strp n -> pp_debug_str_entry d.d_str n + | _ -> "av_name AV not understood" + )) in + + + let ((_,_),(_,av_location)) = (find_ats "DW_AT_location") in + + let ppd_location = + ((match av_location with + | AV_exprloc( n, bs) -> " "^(parse_and_pp_operations c cuh_default bs^"\n") + | AV_block( n, bs) -> " "^(parse_and_pp_operations c cuh_default bs^"\n") + | AV_sec_offset n -> + let location_list1 = (myfindNonPure (fun (n',_)->Nat_big_num.equal n' n) d.d_loc) in + pp_location_list c cuh_default location_list1 + | _ -> "av_location AV not understood" + )) in + + pp_tag_encoding die1.die_abbreviation_declaration.ad_tag ^ (" " ^ (name1 ^ (":\n" ^ (ppd_location ^ "\n")))) ) + + dies)) + + +(** more proper analysis of locations *) + +(* TODO: handle this: +In a variable entry representing the definition of a variable (that is, with no +DW_AT_declaration attribute) if no location attribute is present, or if the location attribute is +present but has an empty location description (as described in Section 2.6), the variable is +assumed to exist in the source code but not in the executable program (but see number 10, +below). +In a variable entry representing a non-defining declaration of a variable, the location +specified modifies the location specified by the defining declaration and only applies for the +scope of the variable entry; if no location is specified, then the location specified in the +defining declaration applies. +The location of a variable may be further specified with a DW_AT_segment attribute, if +appropriate. +*) + + +(* +if there's a DW_AT_location that's a location list (DW_FORM_sec_offset/AV_sec_offset) : use that for both the range(s) and location; interpret the range(s) wrt the applicable base address of the compilation unit + +if there's a DW_AT_location that's a location expression (DW_FORM_exprloc/AV_exprloc or DW_block/AV_block), look for the closest enclosing range: + - DW_AT_low_pc (AV_addr) and no DW_AT_high_pc or DW_AT_ranges: just the singleton address + - DW_AT_low_pc (AV_addr) and DW_AT_high_pc (either an absolute AV_addr or an offset AV_constantN/AV_constant_SLEB128/AV_constantULEB128) : that range + - DW_AT_ranges (DW_FORM_sec_offset/AV_sec_offset) : get a range list from .debug_ranges; interpret wrt the applicable base address of the compilation unit + - for compilation units: a DW_AT_ranges together with a DW_AT_low_pc to specify the default base address to use in interpeting location and range lists + +DW_OP_fbreg in location expressions evaluate the DW_AT_frame_base of +the closest enclosing function - which is either a location expression +or a location list (what happens if the ranges of that location list +don't cover where we are?) + +For each variable and formal parameter that has a DW_AT_name, we'll calculate a list of pairs of a concrete (low,high) range and a location expression. +*) + +let rec closest_enclosing_range c (dranges: range_list_list) (cu_base_address1: Nat_big_num.num) (parents: die list) : ( (Nat_big_num.num * Nat_big_num.num)list)option= + ((match parents with + | [] -> None + | die1::parents' -> + (match (find_attribute_value "DW_AT_low_pc" die1, find_attribute_value "DW_AT_high_pc" die1, find_attribute_value "DW_AT_ranges" die1) with + | (Some (AV_addr n), None, None ) -> Some [(n,Nat_big_num.add n(Nat_big_num.of_int 1))] (* unclear if this case is used? *) + | (Some (AV_addr n1), Some (AV_addr n2), None ) -> Some [(n1,n2)] + | (Some (AV_addr n1), Some (AV_constant_ULEB128 n2), None ) -> Some [(n1,Nat_big_num.add n1 n2)] (* should be mod all? *) + | (Some (AV_addr n1), Some (AV_constant_SLEB128 i2), None ) -> Some [(n1, Nat_big_num.abs ( Nat_big_num.add( n1) i2))] (* should + be mod all? *) + | (Some (AV_addr n1), Some (AV_constantN( _, _)), None ) -> failwith "AV_constantN in closest_enclosing_range" + + | (Some (AV_addr n1), Some (AV_block( n, bs)), None ) -> let n2 = (natural_of_bytes c.endianness bs) in Some [(n1,Nat_big_num.add n1 n2)] (* should be mod all? *) (* signed or unsigned interp? *) + + | (_, None, Some (AV_sec_offset n)) -> + let rlis = (snd (find_range_list dranges n)) in + let nns = (interpret_range_list cu_base_address1 rlis) in + Some nns + | (None, None, None ) -> closest_enclosing_range c dranges cu_base_address1 parents' + | (_, _, _ ) -> Some [] (*Assert_extra.failwith "unexpected attribute values in closest_enclosing_range"*) + ) + )) + +(* +If one of the DW_FORM_data<n> forms is used to represent a signed or unsigned integer, it +can be hard for a consumer to discover the context necessary to determine which +interpretation is intended. Producers are therefore strongly encouraged to use +DW_FORM_sdata or DW_FORM_udata for signed and unsigned integers respectively, +rather than DW_FORM_data<n>. +no kidding - if we get an AV_constantN for DW_AT_high_pc, should it be interpreted as signed or unsigned? *) + + +let rec closest_enclosing_frame_base dloc (base_address1: Nat_big_num.num) (parents: die list) : attribute_value option= + ((match parents with + | [] -> None + | die1::parents' -> + (match find_attribute_value "DW_AT_frame_base" die1 with + | Some av -> Some av + | None -> closest_enclosing_frame_base dloc base_address1 parents' + ) + )) + + + + +let interpreted_location_of_die c cuh (dloc: location_list_list) (dranges: range_list_list) (base_address1: Nat_big_num.num) (parents: die list) (die1: die) : ( (Nat_big_num.num * Nat_big_num.num * single_location_description)list)option= +( + + (* for a simple location expression bs, we look in the enclosing die + tree to find the associated pc range *)let location bs= + ((match closest_enclosing_range c dranges base_address1 (die1::parents) with + | Some nns -> + Some (Lem_list.map (fun (n1,n2) -> (n1,n2,bs)) nns) + | None -> + (* if there is no such range, we take the full 0 - 0xfff.fff range*) + Some [(Nat_big_num.of_int 0,(arithmetic_context_of_cuh cuh).ac_max,bs)] + )) in + + (match find_attribute_value "DW_AT_location" die1 with + | Some (AV_exprloc( n, bs)) -> location bs + | Some (AV_block( n, bs)) -> location bs + (* while for a location list, we take the associated pc range from + each element of the list *) + | Some (AV_sec_offset n) -> + let (_,llis) = (find_location_list dloc n) in + Some (interpret_location_list base_address1 llis) + | None -> None + )) + + +let cu_base_address cu:Nat_big_num.num= + ((match find_attribute_value "DW_AT_low_pc" cu.cu_die with + | Some (AV_addr n) -> n + | _ ->Nat_big_num.of_int 0 (*Nothing*) (*Assert_extra.failwith "no cu DW_AT_low_pc"*) + )) + + +(*val analyse_locations : dwarf -> analysed_location_data*) +let analyse_locations (d: dwarf) : analysed_location_data= + + (let c : p_context = ({ endianness = (d.d_endianness) }) in + + let (cuh_default : compilation_unit_header) = (let cu = (myhead d.d_compilation_units) in cu.cu_header) in + + (* find all DW_TAG_variable and DW_TAG_formal_parameter dies with a DW_AT_name and DW_AT_location attribute *) + let tags = (Lem_list.map tag_encode ["DW_TAG_variable"; "DW_TAG_formal_parameter"]) in + let dies : (compilation_unit * ( die list) * die) list = + (find_dies + (fun die1 -> + Lem_list.elem + instance_Basic_classes_Eq_Num_natural_dict die1.die_abbreviation_declaration.ad_tag tags + && (has_attribute "DW_AT_name" die1 + && has_attribute "DW_AT_location" die1)) + d) in + + Lem_list.map + (fun ((((cu:compilation_unit), (parents: die list), (die1: die)) as x)) -> + let base_address1 = (cu_base_address cu) in + let interpreted_locations : ( (Nat_big_num.num * Nat_big_num.num * single_location_description)list)option = + (interpreted_location_of_die c cuh_default d.d_loc d.d_ranges base_address1 parents die1) in + (x,interpreted_locations) + ) + dies) + + + +let pp_analysed_locations1 c cuh (nnls: (Nat_big_num.num * Nat_big_num.num * single_location_description) list) : string= + (myconcat "" + (Lem_list.map + (fun (n1,n2,bs) -> " " ^ (pphex n1 ^ (" " ^ (pphex n2 ^ (" " ^ (parse_and_pp_operations c cuh bs ^ "\n")))))) + nnls)) + +let pp_analysed_locations2 c cuh mnnls:string= + ((match mnnls with + | Some nnls -> pp_analysed_locations1 c cuh nnls + | None -> " <no locations>\n" + )) + +let pp_analysed_locations3 c cuh str (als: analysed_location_data) : string= + (myconcat "\n" + (Lem_list.map + (fun ((cu,parents,die1),mnnls) -> + pp_die_abbrev c cuh str(Nat_big_num.of_int 0) false parents die1 + ^ pp_analysed_locations2 c cuh mnnls + ) + als + )) + +let pp_analysed_location_data (d: dwarf) (als: analysed_location_data) : string= + (let c : p_context = ({ endianness = (d.d_endianness) }) in + let (cuh_default : compilation_unit_header) = (let cu = (myhead d.d_compilation_units) in cu.cu_header) in + pp_analysed_locations3 c (*HACK*) cuh_default d.d_str als) + + + +let pp_analysed_location_data_at_pc (d: dwarf) (alspc: analysed_location_data_at_pc) : string= + (myconcat "" (Lem_list.map + (fun ((cu,parents,die1),(n1,n2,sld,esl)) -> + " " ^ + (let name1 = + ((match find_name_of_die d.d_str die1 with + | Some s -> s + | None -> "<no name>\n" + )) in + (match esl with + | Success sl -> + name1 ^ (" @ " ^ (pp_single_location sl ^"\n")) + + | Fail e -> name1 ^ (" @ " ^ ("<fail: " ^ (e ^ ">\n"))) + )) + ) + alspc)) + + +(*val analysed_locations_at_pc : evaluation_context -> dwarf_static -> natural -> analysed_location_data_at_pc*) +let analysed_locations_at_pc + (ev) + (ds: dwarf_static) + (pc: Nat_big_num.num) + : analysed_location_data_at_pc= + +(let c : p_context = ({ endianness = (ds.ds_dwarf.d_endianness) }) in + + let xs = + (Lem_list.mapMaybe + (fun (cupd,mnns) -> + (match mnns with + | None -> None + | Some nns -> + let nns' = (List.filter (fun (n1,n2,sld) -> Nat_big_num.greater_equal pc n1 && Nat_big_num.less pc n2) nns) in + (match nns' with + | [] -> None + | _ -> Some (cupd,nns') + ) + )) + ds.ds_analysed_location_data) +in + +List.concat + (Lem_list.map + (fun ((cu,parents,die1),nns) -> + let ac = (arithmetic_context_of_cuh cu.cu_header) in + let base_address1 = (cu_base_address cu) in + let mfbloc : attribute_value option = + (closest_enclosing_frame_base ds.ds_dwarf.d_loc base_address1 parents) in + Lem_list.map + (fun (n1,n2,sld) -> + let el : single_location error = + (evaluate_location_description_bytes c ds.ds_dwarf.d_loc ds.ds_evaluated_frame_info cu.cu_header ac ev mfbloc pc sld) in + ((cu,parents,die1),(n1,n2,sld,el)) + ) + nns + ) + xs)) + +(*val names_of_address : dwarf -> analysed_location_data_at_pc -> natural -> list string*) +let names_of_address + (d: dwarf) + (alspc: analysed_location_data_at_pc) + (address: Nat_big_num.num) + : string list= + +(Lem_list.mapMaybe + (fun ((cu,parents,die1),(n1,n2,sld,esl)) -> + (match esl with + | Success (SL_simple (SL_memory_address a)) -> + if Nat_big_num.equal a address then + (match find_name_of_die d.d_str die1 with + | Some s -> Some s + | None -> None + ) + else + None + | Success _ -> None (* just suppress? *) + | Fail e -> None (* just suppress? *) + ) + ) + alspc) + + +(** ************************************************************ *) +(** ** evaluation of line-number info *) +(** ************************************************************ *) + +let initial_line_number_registers (lnh: line_number_header) : line_number_registers= + ({ + lnr_address =(Nat_big_num.of_int 0); + lnr_op_index =(Nat_big_num.of_int 0); + lnr_file =(Nat_big_num.of_int 1); + lnr_line =(Nat_big_num.of_int 1); + lnr_column =(Nat_big_num.of_int 0); + lnr_is_stmt = (lnh.lnh_default_is_stmt); + lnr_basic_block = false; + lnr_end_sequence = false; + lnr_prologue_end = false; + lnr_epilogue_begin = false; + lnr_isa =(Nat_big_num.of_int 0); + lnr_discriminator =(Nat_big_num.of_int 0); + }) + +let evaluate_line_number_operation + (lnh: line_number_header) + ((s: line_number_registers), (lnrs: line_number_registers list)) + (lno: line_number_operation) + : line_number_registers * line_number_registers list= + + (let new_address s operation_advance= (Nat_big_num.add s.lnr_address (Nat_big_num.mul + lnh.lnh_minimum_instruction_length + (Nat_big_num.div( Nat_big_num.add s.lnr_op_index operation_advance)lnh.lnh_maximum_operations_per_instruction))) in + let new_op_index s operation_advance= (Nat_big_num.modulus + ( Nat_big_num.add s.lnr_op_index operation_advance) lnh.lnh_maximum_operations_per_instruction) in + + (match lno with + | DW_LN_special adjusted_opcode -> + let operation_advance = (Nat_big_num.div adjusted_opcode lnh.lnh_line_range) in + let line_increment = (Nat_big_num.add lnh.lnh_line_base (( Nat_big_num.modulus adjusted_opcode lnh.lnh_line_range))) in + let s' = + ({ s with + lnr_line = (partialNaturalFromInteger ( Nat_big_num.add( s.lnr_line) line_increment)); + lnr_address = (new_address s operation_advance); + lnr_op_index = (new_op_index s operation_advance); + }) in + let lnrs' = (s'::lnrs) in + let s'' = +({ s' with + lnr_basic_block = false; + lnr_prologue_end = false; + lnr_epilogue_begin = false; + lnr_discriminator =(Nat_big_num.of_int 0); + }) in + (s'', lnrs') + | DW_LNS_copy -> + let lnrs' = (s::lnrs) in + let s' = +({ s with + lnr_basic_block = false; + lnr_prologue_end = false; + lnr_epilogue_begin = false; + lnr_discriminator =(Nat_big_num.of_int 0); + }) in + (s', lnrs') + | DW_LNS_advance_pc operation_advance -> + let s' = + ({ s with + lnr_address = (new_address s operation_advance); + lnr_op_index = (new_op_index s operation_advance); + }) in + (s', lnrs) + | DW_LNS_advance_line line_increment -> + let s' = ({ s with lnr_line = (partialNaturalFromInteger ( Nat_big_num.add( s.lnr_line) line_increment)) }) in (s', lnrs) + | DW_LNS_set_file n -> + let s' = ({ s with lnr_file = n }) in (s', lnrs) + | DW_LNS_set_column n -> + let s' = ({ s with lnr_column = n }) in (s', lnrs) + | DW_LNS_negate_stmt -> + let s' = ({ s with lnr_is_stmt = (not s.lnr_is_stmt) }) in (s', lnrs) + | DW_LNS_set_basic_block -> + let s' = ({ s with lnr_basic_block = true }) in (s', lnrs) + | DW_LNS_const_add_pc -> + let opcode =(Nat_big_num.of_int 255) in + let adjusted_opcode = (Nat_big_num.sub_nat opcode lnh.lnh_opcode_base) in + let operation_advance = (Nat_big_num.div adjusted_opcode lnh.lnh_line_range) in + let s' = + ({ s with + lnr_address = (new_address s operation_advance); + lnr_op_index = (new_op_index s operation_advance); + }) in + (s', lnrs) + | DW_LNS_fixed_advance_pc n -> + let s' = + ({ s with + lnr_address = (Nat_big_num.add s.lnr_address n); + lnr_op_index =(Nat_big_num.of_int 0); + }) in + (s', lnrs) + | DW_LNS_set_prologue_end -> + let s' = ({ s with lnr_prologue_end = true }) in (s', lnrs) + | DW_LNS_set_epilogue_begin -> + let s' = ({ s with lnr_epilogue_begin = true }) in (s', lnrs) + | DW_LNS_set_isa n -> + let s' = ({ s with lnr_isa = n }) in (s', lnrs) + | DW_LNE_end_sequence -> + let s' = ({ s with lnr_end_sequence = true }) in + let lnrs' = (s' :: lnrs) in + let s'' = (initial_line_number_registers lnh) in + (s'', lnrs') + | DW_LNE_set_address n -> + let s' = + ({ s with + lnr_address = n; + lnr_op_index =(Nat_big_num.of_int 0); + }) in + (s', lnrs) + | DW_LNE_define_file( s, n1, n2, n3) -> + failwith "DW_LNE_define_file not implemented" (*TODO: add to file list in header - but why is this in the spec? *) + | DW_LNE_set_discriminator n -> + let s' = ({ s with lnr_discriminator = n }) in (s', lnrs) + )) + +let rec evaluate_line_number_operations + (lnh: line_number_header) + ((s: line_number_registers), (lnrs: line_number_registers list)) + (lnos: line_number_operation list) + : line_number_registers * line_number_registers list= + ((match lnos with + | [] -> (s,lnrs) + | lno :: lnos' -> + let (s',lnrs') = + (evaluate_line_number_operation lnh (s,lnrs) lno) in + evaluate_line_number_operations lnh (s',lnrs') lnos' + )) + +let evaluate_line_number_program + (lnp:line_number_program) + : line_number_registers list= + (List.rev (snd (evaluate_line_number_operations lnp.lnp_header ((initial_line_number_registers lnp.lnp_header),[]) lnp.lnp_operations))) + + +let pp_line_number_registers lnr:string= + ("" + ^ ("address = " ^ (pphex lnr.lnr_address ^ ("\n" + ^ ("op_index = " ^ (Nat_big_num.to_string lnr.lnr_op_index ^ ("\n" + ^ ("file = " ^ (Nat_big_num.to_string lnr.lnr_file ^ ("\n" + ^ ("line = " ^ (Nat_big_num.to_string lnr.lnr_line ^ ("\n" + ^ ("column = " ^ (Nat_big_num.to_string lnr.lnr_column ^ ("\n" + ^ ("is_stmt = " ^ (string_of_bool lnr.lnr_is_stmt ^ ("\n" + ^ ("basic_block = " ^ (string_of_bool lnr.lnr_basic_block ^ ("\n" + ^ ("end_sequence = " ^ (string_of_bool lnr.lnr_end_sequence ^ ("\n" + ^ ("prologue_end = " ^ (string_of_bool lnr.lnr_prologue_end ^ ("\n" + ^ ("epilogue_begin = " ^ (string_of_bool lnr.lnr_epilogue_begin ^ ("\n" + ^ ("isa = " ^ (Nat_big_num.to_string lnr.lnr_isa ^ ("\n" + ^ ("discriminator = " ^ (pphex lnr.lnr_discriminator ^ "\n")))))))))))))))))))))))))))))))))))) + +let pp_line_number_registers_tight lnr : string list= + ([ + pphex lnr.lnr_address ; + Nat_big_num.to_string lnr.lnr_op_index ; + Nat_big_num.to_string lnr.lnr_file ; + Nat_big_num.to_string lnr.lnr_line ; + Nat_big_num.to_string lnr.lnr_column ; + string_of_bool lnr.lnr_is_stmt ; + string_of_bool lnr.lnr_basic_block ; + string_of_bool lnr.lnr_end_sequence ; + string_of_bool lnr.lnr_prologue_end ; + string_of_bool lnr.lnr_epilogue_begin ; + Nat_big_num.to_string lnr.lnr_isa ; + pphex lnr.lnr_discriminator + ]) + +let pp_line_number_registerss lnrs:string= + (pad_rows + ( + ["address"; "op_index"; "file"; "line"; "column"; "is_stmt"; "basic_block"; "end_sequence"; "prologue_end"; "epilogue_begin"; "isa"; "discriminator"] + :: + (Lem_list.map pp_line_number_registers_tight lnrs) + )) + +let pp_evaluated_line_info (eli: evaluated_line_info) : string= + (myconcat "\n" (Lem_list.map (fun (lnh,lnrs) -> pp_line_number_header lnh ^ ("\n" ^ pp_line_number_registerss lnrs)) eli)) + +(* readef example: +Decoded dump of debug contents of section .debug_line: + +CU: /var/local/stephen/work/devel/rsem/ppcmem2/system/tests-adhoc/simple-malloc/test-concurrent.c: +File name Line number Starting address +test-concurrent.c 11 0x400144 + +test-concurrent.c 12 0x40014c +test-concurrent.c 13 0x400154 +test-concurrent.c 14 0x400158 +test-concurrent.c 17 0x400160 + +/var/local/stephen/work/devel/rsem/ppcmem2/system/tests-adhoc/simple-malloc/../thread_start_aarch64.h: +thread_start_aarch64.h 34 0x400168 +thread_start_aarch64.h 36 0x400174 + +/var/local/stephen/work/devel/rsem/ppcmem2/system/tests-adhoc/simple-malloc/test-concurrent.c: +test-concurrent.c 19 0x400174 + +test-concurrent.c 20 0x40017c +test-concurrent.c 22 0x400180 + +CU: /var/local/stephen/work/devel/rsem/ppcmem2/system/tests-adhoc/simple-malloc/malloc.c: +... +*) + + +let source_lines_of_address (ds:dwarf_static) (a: Nat_big_num.num) : (string * Nat_big_num.num * line_number_registers) list= + (List.concat + (Lem_list.map + (fun (lnh, lnrs) -> + myfiltermaybe + (fun lnr -> + if Nat_big_num.equal a lnr.lnr_address && not lnr.lnr_end_sequence then + (match mynth ( Nat_big_num.sub_nat lnr.lnr_file(Nat_big_num.of_int 1)) lnh.lnh_file_names with + | Some lnfe -> + Some (string_of_bytes lnfe.lnfe_path, lnr.lnr_line, lnr) + | None -> + Some ("<source_lines_of_address: file entry not found>",Nat_big_num.of_int 0, lnr) + ) + else + None) + lnrs + ) + ds.ds_evaluated_line_info + )) + + +(** ************************************************************ *) +(** ** collecting all the statically calculated analysis info *) +(** ************************************************************ *) + +(*val extract_dwarf_static : elf_file -> maybe dwarf_static*) +let extract_dwarf_static f1:(dwarf_static)option= + ((match extract_dwarf f1 with + | None -> None + | Some dwarf1 -> + let _ = (my_debug5 (pp_dwarf dwarf1)) in + + let ald : analysed_location_data = + (analyse_locations dwarf1) in + let efi : evaluated_frame_info = + (evaluate_frame_info dwarf1) in + let eli : evaluated_line_info = + (Lem_list.map (fun lnp -> (lnp.lnp_header, evaluate_line_number_program lnp)) dwarf1.d_line_info) in + let ds = + ({ + ds_dwarf = dwarf1; + ds_analysed_location_data = ald; + ds_evaluated_frame_info = efi; + ds_evaluated_line_info = eli; + }) in + Some ds + )) + + + + +(** ************************************************************ *) +(** ** top level for main_elf ******************************** *) +(** ************************************************************ *) + +(*val harness_string_of_elf : elf_file -> byte_sequence -> string*) +let harness_string_of_elf f1 bs:string= + (let mds = (extract_dwarf_static f1) in + (match mds with + | None -> "<no dwarf information extracted>" + | Some ds -> + pp_dwarf ds.ds_dwarf + (* ^ analyse_locations_raw c d *) + ^ ("************** evaluation of frame data *************************\n" + ^ (pp_evaluated_frame_info ds.ds_evaluated_frame_info + ^ ("************** analysis of location data *************************\n" + ^ (pp_analysed_location_data ds.ds_dwarf ds.ds_analysed_location_data + ^ ("************** line info *************************\n" + ^ pp_evaluated_line_info ds.ds_evaluated_line_info))))) + )) + + +(*val harness_string_of_elf64_debug_info_section : elf64_file -> byte_sequence -> (*(natural -> string) -> (natural -> string) -> (natural -> string) -> elf64_header -> elf64_section_header_table -> string_table -> *) string*) +let harness_string_of_elf64_debug_info_section f1 bs0:string= + ( (*os proc usr hdr sht stbl*)harness_string_of_elf (ELF_File_64 f1) bs0) + +(*val harness_string_of_elf32_debug_info_section : elf32_file -> byte_sequence -> (* (natural -> string) -> (natural -> string) -> (natural -> string) -> elf32_header -> elf32_section_header_table -> string_table ->*) string*) +let harness_string_of_elf32_debug_info_section f1 bs0:string= + ( (*os proc usr hdr sht stbl*)harness_string_of_elf (ELF_File_32 f1) bs0) + |
