diff options
| author | Alasdair Armstrong | 2017-09-07 16:54:20 +0100 |
|---|---|---|
| committer | Alasdair Armstrong | 2017-09-07 16:54:20 +0100 |
| commit | 842165c1171fde332bd42e7520338c59a797f76b (patch) | |
| tree | 75b61297b6d9b6e4810542390eb1371afc2f183f /lib/ocaml_rts/linksem/elf_dynamic.ml | |
| parent | 8124c487b576661dfa7a0833415d07d0978bc43e (diff) | |
Add ocaml run-time and updates to sail for ocaml backend
Diffstat (limited to 'lib/ocaml_rts/linksem/elf_dynamic.ml')
| -rw-r--r-- | lib/ocaml_rts/linksem/elf_dynamic.ml | 1202 |
1 files changed, 1202 insertions, 0 deletions
diff --git a/lib/ocaml_rts/linksem/elf_dynamic.ml b/lib/ocaml_rts/linksem/elf_dynamic.ml new file mode 100644 index 00000000..0355337e --- /dev/null +++ b/lib/ocaml_rts/linksem/elf_dynamic.ml @@ -0,0 +1,1202 @@ +(*Generated by Lem from elf_dynamic.lem.*) +(** [elf_dynamic] module exports types and definitions relating to the dynamic + * section and dynamic linking functionality of an ELF file. + *) + +open Lem_basic_classes +open Lem_bool +open Lem_list +open Lem_num +open Lem_string + +open Byte_sequence +open Endianness +open Error +open Show +open String_table + +open Elf_file +open Elf_header +open Elf_relocation +open Elf_section_header_table +open Elf_program_header_table +open Elf_types_native_uint + +(** Validity checks *) + +(** [is_elf32_valid_program_header_table_for_dynamic_linking pht] checks whether + * a program header table [pht] is a valid program header table for an ELF file + * that will be potentially dynamically linked. Returns true if there is exactly + * one segment header of type [elf_pt_interp], i.e. contains a string pointing + * to the requested dynamic interpreter. + *) +(*val is_elf32_valid_program_header_table_for_dynamic_linking : elf32_program_header_table -> + bool*) +let is_elf32_valid_program_header_table_for_dynamic_linking pht:bool= + (List.length (List.filter (fun x -> Nat_big_num.equal (Nat_big_num.of_string (Uint32.to_string x.elf32_p_type)) elf_pt_interp) pht) = 1) + +(** [is_elf64_valid_program_header_table_for_dynamic_linking pht] checks whether + * a program header table [pht] is a valid program header table for an ELF file + * that will be potentially dynamically linked. Returns true if there is exactly + * one segment header of type [elf_pt_interp], i.e. contains a string pointing + * to the requested dynamic interpreter. + *) +(*val is_elf64_valid_program_header_table_for_dynamic_linking : elf64_program_header_table -> + bool*) +let is_elf64_valid_program_header_table_for_dynamic_linking pht:bool= + (List.length (List.filter (fun x -> Nat_big_num.equal (Nat_big_num.of_string (Uint32.to_string x.elf64_p_type)) elf_pt_interp) pht) = 1) + +(** Dynamic section entry *) + +(** [dyn_union] represents the C-union type used in the definition of [elf32_dyn] + * and [elf64_dyn] types below. Some section tags correspond to entries where + * the fields are either unspecified or ignored, hence the presence of the + * [D_Ignored] constructor. + *) +type( 'a, 'b) dyn_union + = D_Val of 'a + | D_Ptr of 'b + | D_Ignored of byte_sequence + +(** [elf32_dyn] captures the notion of an ELF32 dynamic section entry. + * Specialises the [dyn_union] type above to using [elf32_word] values and + * [elf32_addr] pointers. + *) +type elf32_dyn = + { elf32_dyn_tag : Int32.t (** The type of the entry. *) + ; elf32_dyn_d_un : (Uint32.uint32, Uint32.uint32) dyn_union (** The value of the entry, stored as a union. *) + } + +(** [elf64_dyn] captures the notion of an ELF32 dynamic section entry. + * Specialises the [dyn_union] type above to using [elf64_xword] values and + * [elf64_addr] pointers. + *) +type elf64_dyn = + { elf64_dyn_tag : Int64.t (** The type of the entry. *) + ; elf64_dyn_d_un : (Uint64.uint64, Uint64.uint64) dyn_union (** The value of the entry, stored as a union. *) + } + +(** Dynamic section tags *) + +(** [dt_null] marks the end of the dynamic array *) +let dt_null : Nat_big_num.num= (Nat_big_num.of_int 0) +(** [dt_needed] holds the string table offset of a string containing the name of + * a needed library. + *) +let dt_needed : Nat_big_num.num= (Nat_big_num.of_int 1) +(** [dt_pltrelsz] holds the size in bytes of relocation entries associated with + * the PLT. + *) +let dt_pltrelsz : Nat_big_num.num= (Nat_big_num.of_int 2) +(** [dt_pltgot] holds an address associated with the PLT or GOT. *) +let dt_pltgot : Nat_big_num.num= (Nat_big_num.of_int 3) +(** [dt_hash] holds the address of a symbol-table hash. *) +let dt_hash : Nat_big_num.num= (Nat_big_num.of_int 4) +(** [dt_strtab] holds the address of the string table. *) +let dt_strtab : Nat_big_num.num= (Nat_big_num.of_int 5) +(** [dt_symtab] holds the address of a symbol table. *) +let dt_symtab : Nat_big_num.num= (Nat_big_num.of_int 6) +(** [dt_rela] holds the address of a relocation table. *) +let dt_rela : Nat_big_num.num= (Nat_big_num.of_int 7) +(** [dt_relasz] holds the size in bytes of the relocation table. *) +let dt_relasz : Nat_big_num.num= (Nat_big_num.of_int 8) +(** [dt_relaent] holds the size in bytes of a relocation table entry. *) +let dt_relaent : Nat_big_num.num= (Nat_big_num.of_int 9) +(** [dt_strsz] holds the size in bytes of the string table. *) +let dt_strsz : Nat_big_num.num= (Nat_big_num.of_int 10) +(** [dt_syment] holds the size in bytes of a symbol table entry. *) +let dt_syment : Nat_big_num.num= (Nat_big_num.of_int 11) +(** [dt_init] holds the address of the initialisation function. *) +let dt_init : Nat_big_num.num= (Nat_big_num.of_int 12) +(** [dt_fini] holds the address of the finalisation function. *) +let dt_fini : Nat_big_num.num= (Nat_big_num.of_int 13) +(** [dt_soname] holds the string table offset of a string containing the shared- + * object name. + *) +let dt_soname : Nat_big_num.num= (Nat_big_num.of_int 14) +(** [dt_rpath] holds the string table offset of a string containing the library + * search path. + *) +let dt_rpath : Nat_big_num.num= (Nat_big_num.of_int 15) +(** [dt_symbolic] alters the linker's symbol resolution algorithm so that names + * are resolved first from the shared object file itself, rather than the + * executable file. + *) +let dt_symbolic : Nat_big_num.num= (Nat_big_num.of_int 16) +(** [dt_rel] is similar to [dt_rela] except its table has implicit addends. *) +let dt_rel : Nat_big_num.num= (Nat_big_num.of_int 17) +(** [dt_relsz] holds the size in bytes of the [dt_rel] relocation table. *) +let dt_relsz : Nat_big_num.num= (Nat_big_num.of_int 18) +(** [dt_relent] holds the size in bytes of a [dt_rel] relocation entry. *) +let dt_relent : Nat_big_num.num= (Nat_big_num.of_int 19) +(** [dt_pltrel] specifies the type of relocation entry to which the PLT refers. *) +let dt_pltrel : Nat_big_num.num= (Nat_big_num.of_int 20) +(** [dt_debug] is used for debugging and its purpose is not specified in the ABI. + * Programs using this entry are not ABI-conformant. + *) +let dt_debug : Nat_big_num.num= (Nat_big_num.of_int 21) +(** [dt_textrel] absence of this entry indicates that no relocation entry should + * cause a modification to a non-writable segment. Otherwise, if present, one + * or more relocation entries may request modifications to a non-writable + * segment. + *) +let dt_textrel : Nat_big_num.num= (Nat_big_num.of_int 22) +(** [dt_jmprel]'s member holds the address of relocation entries associated with + * the PLT. + *) +let dt_jmprel : Nat_big_num.num= (Nat_big_num.of_int 23) +(** [dt_bindnow] instructs the linker to process all relocations for the object + * containing the entry before transferring control to the program. + *) +let dt_bindnow : Nat_big_num.num= (Nat_big_num.of_int 24) +(** [dt_init_array] holds the address to the array of pointers to initialisation + * functions. + *) +let dt_init_array : Nat_big_num.num= (Nat_big_num.of_int 25) +(** [dt_fini_array] holds the address to the array of pointers to finalisation + * functions. + *) +let dt_fini_array : Nat_big_num.num= (Nat_big_num.of_int 26) +(** [dt_init_arraysz] holds the size in bytes of the array of pointers to + * initialisation functions. + *) +let dt_init_arraysz : Nat_big_num.num= (Nat_big_num.of_int 27) +(** [dt_fini_arraysz] holds the size in bytes of the array of pointers to + * finalisation functions. + *) +let dt_fini_arraysz : Nat_big_num.num= (Nat_big_num.of_int 28) +(** [dt_runpath] holds an offset into the string table holding a string containing + * the library search path. + *) +let dt_runpath : Nat_big_num.num= (Nat_big_num.of_int 29) +(** [dt_flags] holds flag values specific to the object being loaded. *) +let dt_flags : Nat_big_num.num= (Nat_big_num.of_int 30) +let dt_encoding : Nat_big_num.num= (Nat_big_num.of_int 32) +(** [dt_preinit_array] holds the address to the array of pointers of pre- + * initialisation functions. + *) +let dt_preinit_array : Nat_big_num.num= (Nat_big_num.of_int 32) +(** [dt_preinit_arraysz] holds the size in bytes of the array of pointers of + * pre-initialisation functions. + *) +let dt_preinit_arraysz : Nat_big_num.num= (Nat_big_num.of_int 33) +(** [dt_loos] and [dt_hios]: this inclusive range is reserved for OS-specific + * semantics. + *) +let dt_loos : Nat_big_num.num= (Nat_big_num.add ( Nat_big_num.mul(Nat_big_num.of_int 2)(Nat_big_num.of_int 805306374))(Nat_big_num.of_int 1)) (* 0x6000000D *) +let dt_hios : Nat_big_num.num= ( Nat_big_num.mul(Nat_big_num.of_int 2)(Nat_big_num.of_int 939522048)) (* 0x6ffff000 *) +(** [dt_loproc] and [dt_hiproc]: this inclusive range is reserved for processor + * specific semantics. + *) +let dt_loproc : Nat_big_num.num= ( Nat_big_num.mul(Nat_big_num.of_int 2)(Nat_big_num.of_int 939524096)) (* 0x70000000 *) +let dt_hiproc : Nat_big_num.num= (Nat_big_num.add ( Nat_big_num.mul(Nat_big_num.of_int 2)(Nat_big_num.of_int 1073741823))(Nat_big_num.of_int 1)) (* 0x7fffffff *) + +(** [string_of_dynamic_tag so t os proc] produces a string-based representation of + * dynamic section tag [t]. For tag values between LO_OS and HI_OS [os] is + * used to produce the resulting value. For tag values between LO_PROC and + * HI_PROC [proc] is used to produce the resulting value. Boolean flag [so] + * indicates whether the flag in question is derived from a shared object file, + * which alters the printing of ENCODING and PRE_INITARRAY flags. + *) +(*val string_of_dynamic_tag : bool -> natural -> (natural -> bool) -> (natural -> string) -> (natural -> string) + -> string*) +let string_of_dynamic_tag shared_object tag os_additional_ranges os proc:string= + (if Nat_big_num.equal tag dt_null then + "NULL" + else if Nat_big_num.equal tag dt_needed then + "NEEDED" + else if Nat_big_num.equal tag dt_pltrelsz then + "PLTRELSZ" + else if Nat_big_num.equal tag dt_pltgot then + "PLTGOT" + else if Nat_big_num.equal tag dt_hash then + "HASH" + else if Nat_big_num.equal tag dt_strtab then + "STRTAB" + else if Nat_big_num.equal tag dt_symtab then + "SYMTAB" + else if Nat_big_num.equal tag dt_rela then + "RELA" + else if Nat_big_num.equal tag dt_relasz then + "RELASZ" + else if Nat_big_num.equal tag dt_relaent then + "RELAENT" + else if Nat_big_num.equal tag dt_strsz then + "STRSZ" + else if Nat_big_num.equal tag dt_syment then + "SYMENT" + else if Nat_big_num.equal tag dt_init then + "INIT" + else if Nat_big_num.equal tag dt_fini then + "FINI" + else if Nat_big_num.equal tag dt_soname then + "SONAME" + else if Nat_big_num.equal tag dt_rpath then + "RPATH" + else if Nat_big_num.equal tag dt_symbolic then + "SYMBOLIC" + else if Nat_big_num.equal tag dt_rel then + "REL" + else if Nat_big_num.equal tag dt_relsz then + "RELSZ" + else if Nat_big_num.equal tag dt_relent then + "RELENT" + else if Nat_big_num.equal tag dt_pltrel then + "PLTREL" + else if Nat_big_num.equal tag dt_debug then + "DEBUG" + else if Nat_big_num.equal tag dt_textrel then + "TEXTREL" + else if Nat_big_num.equal tag dt_jmprel then + "JMPREL" + else if Nat_big_num.equal tag dt_bindnow then + "BIND_NOW" + else if Nat_big_num.equal tag dt_init_array then + "INIT_ARRAY" + else if Nat_big_num.equal tag dt_fini_array then + "FINI_ARRAY" + else if Nat_big_num.equal tag dt_init_arraysz then + "INIT_ARRAYSZ" + else if Nat_big_num.equal tag dt_fini_arraysz then + "FINI_ARRAYSZ" + else if Nat_big_num.equal tag dt_runpath then + "RUNPATH" + else if Nat_big_num.equal tag dt_flags then + "FLAGS" + else if Nat_big_num.equal tag dt_encoding then + if not shared_object then + "ENCODING" + else + "PREINIT_ARRAY" + else if Nat_big_num.equal tag dt_preinit_arraysz then + "PREINIT_ARRAYSZ" + else if Nat_big_num.greater_equal tag dt_loproc && Nat_big_num.less_equal tag dt_hiproc then + proc tag + else if Nat_big_num.greater_equal tag dt_loos && Nat_big_num.less_equal tag dt_hios then + os tag + else if os_additional_ranges tag then + os tag + else + "Invalid dynamic section tag") + +(** [tag_correspondence] is a type used to emulate the functionality of a C-union + * in Lem. The type records whether the union should be interpreted as a value, + * a pointer, or a "do not care" value. An accompanying function will map a + * dynamic section tag to a [tag_correspondence], so that transcription functions + * know how to properly use the [dyn_union] value in a dynamic section entry. + *) +type tag_correspondence + = C_Val (** [dyn_union] should be interpreted as a value. *) + | C_Ptr (** [dyn_union] should be interpreted as a pointer. *) + | C_Ignored (** [dyn_union] is irrelevant, so we do not care. *) + +(** [tag_correspondence_of_tag tag os_additional_ranges os proc] produces a + * [tag_correspondence] value for a given dynamic tag, [tag]. Some tag values + * are reserved for interpretation by the OS or processor supplement (i.e. the + * ABI). We therefore also take in a predicate, [os_additional_ranges], that + * recognises when a tag is "special" for a given ABI, and a means of interpreting + * that tag, using [os] and [proc] functions. + *) +(*val tag_correspondence_of_tag : bool -> natural -> (natural -> bool) -> (natural -> error tag_correspondence) -> + (natural -> error tag_correspondence) -> error tag_correspondence*) +let tag_correspondence_of_tag shared_object tag os_additional_ranges os proc:(tag_correspondence)error= + (if Nat_big_num.equal tag dt_null then + return C_Ignored + else if Nat_big_num.equal tag dt_needed then + return C_Val + else if Nat_big_num.equal tag dt_pltrelsz then + return C_Val + else if Nat_big_num.equal tag dt_pltgot then + return C_Ptr + else if Nat_big_num.equal tag dt_hash then + return C_Ptr + else if Nat_big_num.equal tag dt_strtab then + return C_Ptr + else if Nat_big_num.equal tag dt_symtab then + return C_Ptr + else if Nat_big_num.equal tag dt_rela then + return C_Ptr + else if Nat_big_num.equal tag dt_relasz then + return C_Val + else if Nat_big_num.equal tag dt_relaent then + return C_Val + else if Nat_big_num.equal tag dt_strsz then + return C_Val + else if Nat_big_num.equal tag dt_syment then + return C_Val + else if Nat_big_num.equal tag dt_init then + return C_Ptr + else if Nat_big_num.equal tag dt_fini then + return C_Ptr + else if Nat_big_num.equal tag dt_soname then + return C_Val + else if Nat_big_num.equal tag dt_rpath then + return C_Val + else if Nat_big_num.equal tag dt_symbolic then + return C_Ignored + else if Nat_big_num.equal tag dt_rel then + return C_Ptr + else if Nat_big_num.equal tag dt_relsz then + return C_Val + else if Nat_big_num.equal tag dt_relent then + return C_Val + else if Nat_big_num.equal tag dt_pltrel then + return C_Val + else if Nat_big_num.equal tag dt_debug then + return C_Ptr + else if Nat_big_num.equal tag dt_textrel then + return C_Ignored + else if Nat_big_num.equal tag dt_jmprel then + return C_Ptr + else if Nat_big_num.equal tag dt_bindnow then + return C_Ignored + else if Nat_big_num.equal tag dt_init_array then + return C_Ptr + else if Nat_big_num.equal tag dt_fini_array then + return C_Ptr + else if Nat_big_num.equal tag dt_init_arraysz then + return C_Val + else if Nat_big_num.equal tag dt_fini_arraysz then + return C_Val + else if Nat_big_num.equal tag dt_runpath then + return C_Val + else if Nat_big_num.equal tag dt_flags then + return C_Val + else if Nat_big_num.equal tag dt_encoding then + if not shared_object then + return C_Ignored + else + return C_Ptr + else if Nat_big_num.equal tag dt_preinit_arraysz then + return C_Val + else if Nat_big_num.greater_equal tag dt_loproc && Nat_big_num.less_equal tag dt_hiproc then + proc tag + else if Nat_big_num.greater_equal tag dt_loos && Nat_big_num.less_equal tag dt_hios then + os tag + else if os_additional_ranges tag then + os tag + else + fail ("tag_correspondence_of_tag: invalid dynamic section tag")) + +(** [read_elf32_dyn endian bs0 so os_additional_ranges os proc] reads an [elf32_dyn] + * record from byte sequence [bs0], assuming endianness [endian]. As mentioned + * above some ABIs reserve additional tag values for their own purposes. These + * are recognised by the predicate [os_additional_ranges] and interpreted by + * the functions [os] and [proc]. Fails if the transcription of the record from + * [bs0] fails, or if [os] or [proc] fail. + *) +(*val read_elf32_dyn : endianness -> byte_sequence -> bool -> (natural -> bool) -> (natural -> error tag_correspondence) -> + (natural -> error tag_correspondence) -> error (elf32_dyn * byte_sequence)*) +let read_elf32_dyn endian bs0 shared_object os_additional_ranges os proc:(elf32_dyn*byte_sequence)error= + (read_elf32_sword endian bs0 >>= (fun (tag0, bs1) -> + let tag = (Nat_big_num.abs (Nat_big_num.of_int32 tag0)) in + tag_correspondence_of_tag shared_object tag os_additional_ranges os proc >>= (fun corr -> + (match corr with + | C_Ptr -> + read_elf32_addr endian bs1 >>= (fun (ptr, bs2) -> + return ({ elf32_dyn_tag = tag0 ; elf32_dyn_d_un = (D_Ptr ptr) }, bs2)) + | C_Val -> + read_elf32_word endian bs1 >>= (fun (vl, bs2) -> + return ({ elf32_dyn_tag = tag0 ; elf32_dyn_d_un = (D_Val vl) }, bs2)) + | C_Ignored -> + (match endian with + | Big -> + read_4_bytes_be bs1 >>= (fun ((b1, b2, b3, b4), bs2) -> + let cut = (Byte_sequence.from_byte_lists [[b1; b2; b3; b4]]) in + return ({ elf32_dyn_tag = tag0 ; elf32_dyn_d_un = (D_Ignored cut) }, bs2)) + | Little -> + read_4_bytes_le bs1 >>= (fun ((b1, b2, b3, b4), bs2) -> + let cut = (Byte_sequence.from_byte_lists [[b1; b2; b3; b4]]) in + return ({ elf32_dyn_tag = tag0 ; elf32_dyn_d_un = (D_Ignored cut) }, bs2)) + ) + )))) + +(** [read_elf64_dyn endian bs0 os_additional_ranges os proc] reads an [elf64_dyn] + * record from byte sequence [bs0], assuming endianness [endian]. As mentioned + * above some ABIs reserve additional tag values for their own purposes. These + * are recognised by the predicate [os_additional_ranges] and interpreted by + * the functions [os] and [proc]. Fails if the transcription of the record from + * [bs0] fails, or if [os] or [proc] fail. + *) +(*val read_elf64_dyn : endianness -> byte_sequence -> bool -> (natural -> bool) -> + (natural -> error tag_correspondence) -> (natural -> error tag_correspondence) -> + error (elf64_dyn * byte_sequence)*) +let read_elf64_dyn endian bs0 shared_object os_additional_ranges os proc:(elf64_dyn*byte_sequence)error= + (read_elf64_sxword endian bs0 >>= (fun (tag0, bs1) -> + let tag = (Nat_big_num.abs (Nat_big_num.of_int64 tag0)) in + tag_correspondence_of_tag shared_object tag os_additional_ranges os proc >>= (fun corr -> + (match corr with + | C_Ptr -> + read_elf64_addr endian bs1 >>= (fun (ptr, bs2) -> + return ({ elf64_dyn_tag = tag0 ; elf64_dyn_d_un = (D_Ptr ptr) }, bs2)) + | C_Val -> + read_elf64_xword endian bs1 >>= (fun (vl, bs2) -> + return ({ elf64_dyn_tag = tag0 ; elf64_dyn_d_un = (D_Val vl) }, bs2)) + | C_Ignored -> + (match endian with + | Big -> + read_8_bytes_be bs1 >>= (fun ((b1, b2, b3, b4, b5, b6, b7, b8), bs2) -> + let cut = (Byte_sequence.from_byte_lists [[b1; b2; b3; b4; b5; b6; b7; b8]]) in + return ({ elf64_dyn_tag = tag0 ; elf64_dyn_d_un = (D_Ignored cut) }, bs2)) + | Little -> + read_8_bytes_le bs1 >>= (fun ((b1, b2, b3, b4, b5, b6, b7, b8), bs2) -> + let cut = (Byte_sequence.from_byte_lists [[b1; b2; b3; b4; b5; b6; b7; b8]]) in + return ({ elf64_dyn_tag = tag0 ; elf64_dyn_d_un = (D_Ignored cut) }, bs2)) + ) + )))) + +(** [obtain_elf32_dynamic_section_contents' endian bs0 os_additional_ranges os + * proc] exhaustively reads in [elf32_dyn] values from byte sequence [bs0], + * interpreting ABI-specific dynamic tags with [os_additional_ranges], [os], and + * [proc] as mentioned above. Fails if [bs0]'s length modulo the size of an + * [elf32_dyn] entry is not 0. + *) +(*val obtain_elf32_dynamic_section_contents' : endianness -> byte_sequence -> + bool -> (natural -> bool) -> (natural -> error tag_correspondence) -> + (natural -> error tag_correspondence) -> error (list elf32_dyn)*) +let rec obtain_elf32_dynamic_section_contents' endian bs0 shared_object os_additional_ranges os proc:((elf32_dyn)list)error= + (if Nat_big_num.equal (Byte_sequence.length0 bs0)(Nat_big_num.of_int 0) then + return [] + else + read_elf32_dyn endian bs0 shared_object os_additional_ranges os proc >>= (fun (head, bs0) -> + if Nat_big_num.equal (Nat_big_num.of_int32 head.elf32_dyn_tag) ( dt_null) then (* DT_NULL marks end of array *) + return [head] + else + obtain_elf32_dynamic_section_contents' endian bs0 shared_object os_additional_ranges os proc >>= (fun tail -> + return (head::tail)))) + +(** [obtain_elf64_dynamic_section_contents' endian bs0 os_additional_ranges os + * proc] exhaustively reads in [elf64_dyn] values from byte sequence [bs0], + * interpreting ABI-specific dynamic tags with [os_additional_ranges], [os], and + * [proc] as mentioned above. Fails if [bs0]'s length modulo the size of an + * [elf64_dyn] entry is not 0. + *) +(*val obtain_elf64_dynamic_section_contents' : endianness -> byte_sequence -> + bool -> (natural -> bool) -> (natural -> error tag_correspondence) -> + (natural -> error tag_correspondence) -> error (list elf64_dyn)*) +let rec obtain_elf64_dynamic_section_contents' endian bs0 shared_object os_additional_ranges os proc:((elf64_dyn)list)error= + (if Nat_big_num.equal (Byte_sequence.length0 bs0)(Nat_big_num.of_int 0) then + return [] + else + read_elf64_dyn endian bs0 shared_object os_additional_ranges os proc >>= (fun (head, bs0) -> + if Nat_big_num.equal (Nat_big_num.of_int64 head.elf64_dyn_tag) ( dt_null) then (* DT_NULL marks end of array *) + return [head] + else + obtain_elf64_dynamic_section_contents' endian bs0 shared_object os_additional_ranges os proc >>= (fun tail -> + return (head::tail)))) + +(** [obtain_elf32_dynamic_section_contents' f1 os_additional_ranges os + * proc bs0] exhaustively reads in [elf32_dyn] values from byte sequence [bs0], + * obtaining endianness and the section header table from [elf32_file] f1, + * interpreting ABI-specific dynamic tags with [os_additional_ranges], [os], and + * [proc] as mentioned above. Fails if [bs0]'s length modulo the size of an + * [elf32_dyn] entry is not 0. + *) +(*val obtain_elf32_dynamic_section_contents : elf32_file -> + (natural -> bool) -> (natural -> error tag_correspondence) -> + (natural -> error tag_correspondence) -> byte_sequence -> error (list elf32_dyn)*) +let obtain_elf32_dynamic_section_contents f1 os_additional_ranges os proc bs0:((elf32_dyn)list)error= + (let endian = (get_elf32_header_endianness f1.elf32_file_header) in + let sht = (f1.elf32_file_section_header_table) in + let shared_object = (is_elf32_shared_object_file f1.elf32_file_header) in + (match List.filter (fun ent -> Nat_big_num.equal (Nat_big_num.of_string (Uint32.to_string ent.elf32_sh_type)) sht_dynamic) sht with + | [] -> fail "obtain_elf32_dynamic_section_contents: no SHT_DYNAMIC section header entries" + | [dyn] -> + let off = (Nat_big_num.of_string (Uint32.to_string dyn.elf32_sh_offset)) in + let siz = (Nat_big_num.of_string (Uint32.to_string dyn.elf32_sh_size)) in + Byte_sequence.offset_and_cut off siz bs0 >>= (fun rel -> + obtain_elf32_dynamic_section_contents' endian rel shared_object os_additional_ranges os proc) + | _ -> fail "obtain_elf32_dynamic_section_contents: multiple SHT_DYNAMIC section header entries" + )) + +(** [obtain_elf64_dynamic_section_contents' f1 os_additional_ranges os + * proc bs0] exhaustively reads in [elf64_dyn] values from byte sequence [bs0], + * obtaining endianness and the section header table from [elf64_file] f1, + * interpreting ABI-specific dynamic tags with [os_additional_ranges], [os], and + * [proc] as mentioned above. Fails if [bs0]'s length modulo the size of an + * [elf64_dyn] entry is not 0. + *) +(*val obtain_elf64_dynamic_section_contents : elf64_file -> + (natural -> bool) -> (natural -> error tag_correspondence) -> + (natural -> error tag_correspondence) -> byte_sequence -> error (list elf64_dyn)*) +let obtain_elf64_dynamic_section_contents f1 os_additional_ranges os proc bs0:((elf64_dyn)list)error= + (let endian = (get_elf64_header_endianness f1.elf64_file_header) in + let sht = (f1.elf64_file_section_header_table) in + let shared_object = (is_elf64_shared_object_file f1.elf64_file_header) in + (match List.filter (fun ent -> Nat_big_num.equal (Nat_big_num.of_string (Uint32.to_string ent.elf64_sh_type)) sht_dynamic) sht with + | [] -> fail "obtain_elf64_dynamic_section_contents: no SHT_DYNAMIC section header entries" + | [dyn] -> + let off = (Nat_big_num.of_string (Uint64.to_string dyn.elf64_sh_offset)) in + let siz = (Ml_bindings.nat_big_num_of_uint64 dyn.elf64_sh_size) in + Byte_sequence.offset_and_cut off siz bs0 >>= (fun rel -> + obtain_elf64_dynamic_section_contents' endian rel shared_object os_additional_ranges os proc) + | _ -> fail "obtain_elf64_dynamic_section_contents: multiple SHT_DYNAMIC section header entries" + )) + +(** DT Flags values *) + +(** [df_origin] specific that the object being loaded may make reference to the + * $(ORIGIN) substitution string. + *) +let df_origin : Nat_big_num.num= (Nat_big_num.of_int 1) (* 0x1 *) +(** [df_symbolic] changes the linker's symbol resolution algorithm, resolving + * symbols first from the shared object file rather than the executable file. + *) +let df_symbolic : Nat_big_num.num= (Nat_big_num.of_int 2) (* 0x2 *) +(** [df_textrel] if this flag is not set then no relocation entry should cause + * modification to a non-writable segment. + *) +let df_textrel : Nat_big_num.num= (Nat_big_num.of_int 4) (* 0x4 *) +(** [df_bindnow] if set this instructs the linker to process all relocation entries + * of the containing object before transferring control to the program. + *) +let df_bindnow : Nat_big_num.num= (Nat_big_num.of_int 8) (* 0x8 *) +(** [df_static_tls] if set instructs the linker to reject all attempts to load + * the containing file dynamically. + *) +let df_static_tls : Nat_big_num.num= (Nat_big_num.of_int 16) (* 0x10 *) + +(** [check_flag] is a utility function for testing whether a flag is set. + * TODO: so simple it is probably unneccessary now. + *) +(*val check_flag : natural -> natural -> bool*) +let check_flag m pos:bool= ( Nat_big_num.equal m pos) + +(** [string_of_dt_flag f] produces a string-based representation of dynamic + * section flag [f]. + *) +(*val string_of_dt_flag : natural -> string*) +let string_of_dt_flag flag:string= + (if check_flag flag(Nat_big_num.of_int 0) then + "None" + else if check_flag flag df_origin then + "ORIGIN" + else if check_flag flag df_bindnow then + "BIND_NOW" + else if check_flag flag df_symbolic then + "SYMBOLIC" + else if check_flag flag df_textrel then + "TEXTREL" + else if check_flag flag df_static_tls then + "STATIC_TLS" + else if check_flag flag ( Nat_big_num.add df_bindnow df_static_tls) then + "BIND_NOW STATIC_TLS" + else if check_flag flag ( Nat_big_num.add df_static_tls df_symbolic) then + "SYMBOLIC STATIC_TLS" + else (* XXX: add more as needed *) + "Invalid dynamic section flag") + +(** [rel_type] represents the two types of relocation records potentially present + * in an ELF file: relocation, and relocation with addends. + *) +type rel_type + = Rel (** Plain relocation type. *) + | RelA (** Relocation with addends type. *) + +(** [string_of_rel_type r] produces a string-based representation of [rel_type], + * [r]. + *) +(*val string_of_rel_type : rel_type -> string*) +let string_of_rel_type r:string= + ((match r with + | Rel -> "REL" + | RelA -> "RELA" + )) + +(** Type [dyn_value] represents the value of an ELF dynamic section entry. Values + * can represent various different types of objects (e.g. paths to libraries, or + * flags, or sizes of other entries in a file), and this type collates them all. + * Parameterised over two type variables so the type can be shared between ELF32 + * and ELF64. + *) +type( 'addr, 'size) dyn_value + = Address of 'addr (** An address. *) + | Size of 'size (** A size (in bytes). *) + | FName of string (** A filename. *) + | SOName of string (** A shared object name. *) + | Path of string (** A path to some directory. *) + | RPath of string (** A "run path". *) + | RunPath of string (** A "run path". *) + | Library of string (** A library path. *) + | Flags1 of Nat_big_num.num (** Flags. *) + | Flags of Nat_big_num.num (** Flags. *) + | Numeric of Nat_big_num.num (** An uninterpreted numeric value. *) + | Checksum of Nat_big_num.num (** A checksum value *) + | RelType of rel_type (** A relocation entry type. *) + | Timestamp of Nat_big_num.num (** A timestamp value. *) + | Null (** A null (0) value. *) + | Ignored (** An ignored value. *) + +(** [elf32_dyn_value] and [elf64_dyn_value] are specialisations of [dyn_value] + * fixing the correct types for the ['addr] and ['size] type variables. + *) +type elf32_dyn_value = (Uint32.uint32, Uint32.uint32) dyn_value +type elf64_dyn_value = (Uint64.uint64, Uint64.uint64) dyn_value + +(** [get_string_table_of_elf32_dyn_section endian dyns sht bs0] searches through + * dynamic section entries [dyns] looking for one pointing to a string table, looks + * up the corresponding section header [sht] pointed to by that dynamic + * section entry, finds the section in [bs0] and decodes a string table from that + * section assuming endianness [endian]. May fail. + *) +(*val get_string_table_of_elf32_dyn_section : endianness -> list elf32_dyn -> + elf32_section_header_table -> byte_sequence -> error string_table*) +let get_string_table_of_elf32_dyn_section endian dyns sht bs0:(string_table)error= + (let strtabs = +(List.filter (fun x -> Nat_big_num.equal +(Nat_big_num.of_int32 x.elf32_dyn_tag) ( dt_strtab) + ) dyns) + in + (match strtabs with + | [strtab] -> + (match strtab.elf32_dyn_d_un with + | D_Val v -> fail "get_string_table_of_elf32_dyn_section: STRTAB must be a PTR" + | D_Ptr p -> + let sect = +(List.filter (fun s -> +(s.elf32_sh_addr = p) && +(s.elf32_sh_type = Uint32.of_string (Nat_big_num.to_string sht_strtab)) + ) sht) + in + (match sect with + | [] -> fail "get_string_table_of_elf32_dyn_section: no section entry with same address as STRTAB" + | [s] -> + let off = (Nat_big_num.of_string (Uint32.to_string s.elf32_sh_offset)) in + let siz = (Nat_big_num.of_string (Uint32.to_string s.elf32_sh_size)) in + Byte_sequence.offset_and_cut off siz bs0 >>= (fun rel -> + let strings = (Byte_sequence.string_of_byte_sequence rel) in + return (String_table.mk_string_table strings (Missing_pervasives.null_char))) + | _ -> fail "get_string_table_of_elf32_dyn_section: multiple section entries with same address as STRTAB" + ) + | D_Ignored i -> fail "get_string_table_of_elf32_dyn_section: STRTAB must be a PTR" + ) + | [] -> fail "get_string_table_of_elf32_dyn_section: no string table entry" + | _ -> fail "get_string_table_of_elf32_dyn_section: multiple string table entries" + )) + +(** [get_string_table_of_elf64_dyn_section endian dyns sht bs0] searches through + * dynamic section entries [dyns] looking for one pointing to a string table, looks + * up the corresponding section header [sht] pointed to by that dynamic + * section entry, finds the section in [bs0] and decodes a string table from that + * section assuming endianness [endian]. May fail. + *) +(*val get_string_table_of_elf64_dyn_section : endianness -> list elf64_dyn -> + elf64_section_header_table -> byte_sequence -> error string_table*) +let get_string_table_of_elf64_dyn_section endian dyns sht bs0:(string_table)error= + (let strtabs = +(List.filter (fun x -> Nat_big_num.equal +(Nat_big_num.of_int64 x.elf64_dyn_tag) ( dt_strtab) + ) dyns) + in + (match strtabs with + | [strtab] -> + (match strtab.elf64_dyn_d_un with + | D_Val v -> fail "get_string_table_of_elf64_dyn_section: STRTAB must be a PTR" + | D_Ptr p -> + let sect = +(List.filter (fun s -> +(s.elf64_sh_addr = p) && +(s.elf64_sh_type = Uint32.of_string (Nat_big_num.to_string sht_strtab)) + ) sht) + in + (match sect with + | [] -> fail "get_string_table_of_elf64_dyn_section: no section entry with same address as STRTAB" + | [s] -> + let off = (Nat_big_num.of_string (Uint64.to_string s.elf64_sh_offset)) in + let siz = (Ml_bindings.nat_big_num_of_uint64 s.elf64_sh_size) in + Byte_sequence.offset_and_cut off siz bs0 >>= (fun rel -> + let strings = (Byte_sequence.string_of_byte_sequence rel) in + return (String_table.mk_string_table strings Missing_pervasives.null_char)) + | _ -> fail "get_string_table_of_elf64_dyn_section: multiple section entries with same address as STRTAB" + ) + | D_Ignored i -> fail "get_string_table_of_elf64_dyn_section: STRTAB must be a PTR" + ) + | [] -> fail "get_string_table_of_elf64_dyn_section: no string table entry" + | _ -> fail "get_string_table_of_elf64_dyn_section: multiple string table entries" + )) + +(** [get_value_of_elf32_dyn so dyn os_additional_ranges os proc stab] returns the value + * stored in a dynamic section entry [dyn], using [os_additional_ranges] and + * [os] to decode ABI-reserved tags. String table [stab] is used to correctly + * decode library and run paths, etc. + * May fail. + *) +(*val get_value_of_elf32_dyn : bool -> elf32_dyn -> (natural -> bool) -> + (elf32_dyn -> string_table -> error elf32_dyn_value) -> + (elf32_dyn -> string_table -> error elf32_dyn_value) -> + string_table -> error elf32_dyn_value*) +let get_value_of_elf32_dyn shared_object dyn os_additional_ranges os proc stab:(((Uint32.uint32),(Uint32.uint32))dyn_value)error= + (let tag = (Nat_big_num.abs (Nat_big_num.of_int32 dyn.elf32_dyn_tag)) in + if Nat_big_num.equal tag dt_null then + return Null + else if Nat_big_num.equal tag dt_needed then + (match dyn.elf32_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf32_dyn_entry: NEEDED must be a Val" + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: NEEDED must be a Val" + ) >>= (fun off -> + let off = (Nat_big_num.of_string (Uint32.to_string off)) in + String_table.get_string_at off stab >>= (fun str -> + return (Library str))) + else if Nat_big_num.equal tag dt_pltrelsz then + (match dyn.elf32_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf32_dyn_entry: PLTRELSZ must be a Val" + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: PLTRELSZ must be a Val" + ) >>= (fun sz -> + return (Size sz)) + else if Nat_big_num.equal tag dt_pltgot then + (match dyn.elf32_dyn_d_un with + | D_Val v -> fail "get_value_of_elf32_dyn_entry: PLTGOT must be a PTR" + | D_Ptr p -> return p + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: PLTGOT must be a PTR" + ) >>= (fun ptr -> + return (Address ptr)) + else if Nat_big_num.equal tag dt_hash then + (match dyn.elf32_dyn_d_un with + | D_Val v -> fail "get_value_of_elf32_dyn_entry: HASH must be a PTR" + | D_Ptr p -> return p + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: HASH must be a PTR" + ) >>= (fun ptr -> + return (Address ptr)) + else if Nat_big_num.equal tag dt_strtab then + (match dyn.elf32_dyn_d_un with + | D_Val v -> fail "get_value_of_elf32_dyn_entry: STRTAB must be a PTR" + | D_Ptr p -> return p + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: STRTAB must be a PTR" + ) >>= (fun ptr -> + return (Address ptr)) + else if Nat_big_num.equal tag dt_symtab then + (match dyn.elf32_dyn_d_un with + | D_Val v -> fail "get_value_of_elf32_dyn_entry: SYMTAB must be a PTR" + | D_Ptr p -> return p + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: SYMTAB must be a PTR" + ) >>= (fun ptr -> + return (Address ptr)) + else if Nat_big_num.equal tag dt_rela then + (match dyn.elf32_dyn_d_un with + | D_Val v -> fail "get_value_of_elf32_dyn_entry: RELA must be a PTR" + | D_Ptr p -> return p + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: RELA must be a PTR" + ) >>= (fun ptr -> + return (Address ptr)) + else if Nat_big_num.equal tag dt_relasz then + (match dyn.elf32_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf32_dyn_entry: RELASZ must be a VAL" + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: RELASZ must be a VAL" + ) >>= (fun sz -> + return (Size sz)) + else if Nat_big_num.equal tag dt_relaent then + (match dyn.elf32_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf32_dyn_entry: RELAENT must be a VAL" + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: RELAENT must be a VAL" + ) >>= (fun sz -> + return (Size sz)) + else if Nat_big_num.equal tag dt_strsz then + (match dyn.elf32_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf32_dyn_entry: STRSZ must be a VAL" + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: STRSZ must be a VAL" + ) >>= (fun sz -> + return (Size sz)) + else if Nat_big_num.equal tag dt_syment then + (match dyn.elf32_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf32_dyn_entry: SYMENT must be a VAL" + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: SYMENT must be a VAL" + ) >>= (fun sz -> + return (Size sz)) + else if Nat_big_num.equal tag dt_init then + (match dyn.elf32_dyn_d_un with + | D_Val v -> fail "get_value_of_elf32_dyn_entry: INIT must be a PTR" + | D_Ptr p -> return p + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: INIT must be a PTR" + ) >>= (fun ptr -> + return (Address ptr)) + else if Nat_big_num.equal tag dt_fini then + (match dyn.elf32_dyn_d_un with + | D_Val v -> fail "get_value_of_elf32_dyn_entry: FINI must be a PTR" + | D_Ptr p -> return p + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: FINI must be a PTR" + ) >>= (fun ptr -> + return (Address ptr)) + else if Nat_big_num.equal tag dt_soname then + (match dyn.elf32_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf32_dyn_entry: SONAME must be a Val" + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: SONAME must be a Val" + ) >>= (fun off -> + let off = (Nat_big_num.of_string (Uint32.to_string off)) in + String_table.get_string_at off stab >>= (fun str -> + return (SOName str))) + else if Nat_big_num.equal tag dt_rpath then + (match dyn.elf32_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf32_dyn_entry: RPATH must be a Val" + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: RPATH must be a Val" + ) >>= (fun off -> + let off = (Nat_big_num.of_string (Uint32.to_string off)) in + String_table.get_string_at off stab >>= (fun str -> + return (RPath str))) + else if Nat_big_num.equal tag dt_symbolic then + return Null + else if Nat_big_num.equal tag dt_rel then + (match dyn.elf32_dyn_d_un with + | D_Val v -> fail "get_value_of_elf32_dyn_entry: REL must be a PTR" + | D_Ptr p -> return p + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: REL must be a PTR" + ) >>= (fun ptr -> + return (Address ptr)) + else if Nat_big_num.equal tag dt_relsz then + (match dyn.elf32_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf32_dyn_entry: RELSZ must be a VAL" + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: RELSZ must be a VAL" + ) >>= (fun sz -> + return (Size sz)) + else if Nat_big_num.equal tag dt_relent then + (match dyn.elf32_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf32_dyn_entry: RELENT must be a VAL" + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: RELENT must be a VAL" + ) >>= (fun sz -> + return (Size sz)) + else if Nat_big_num.equal tag dt_pltrel then + (match dyn.elf32_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf32_dyn_entry: PLTREL must be a VAL" + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: PLTREL must be a VAL" + ) >>= (fun r -> + if Nat_big_num.equal (Nat_big_num.of_string (Uint32.to_string r)) dt_rel then + return (RelType Rel) + else if Nat_big_num.equal (Nat_big_num.of_string (Uint32.to_string r)) dt_rela then + return (RelType RelA) + else + fail "get_value_of_elf32_dyn_entry: PLTREL neither REL nor RELA") + else if Nat_big_num.equal tag dt_debug then + return Null + else if Nat_big_num.equal tag dt_textrel then + return Null + else if Nat_big_num.equal tag dt_jmprel then + (match dyn.elf32_dyn_d_un with + | D_Val v -> fail "get_value_of_elf32_dyn_entry: JMPREL must be a PTR" + | D_Ptr p -> return p + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: JMPREL must be a PTR" + ) >>= (fun ptr -> + return (Address ptr)) + else if Nat_big_num.equal tag dt_bindnow then + return Ignored + else if Nat_big_num.equal tag dt_init_array then + (match dyn.elf32_dyn_d_un with + | D_Val v -> fail "get_value_of_elf32_dyn_entry: INIT_ARRAY must be a PTR" + | D_Ptr p -> return p + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: INIT_ARRAY must be a PTR" + ) >>= (fun ptr -> + return (Address ptr)) + else if Nat_big_num.equal tag dt_fini_array then + (match dyn.elf32_dyn_d_un with + | D_Val v -> fail "get_value_of_elf32_dyn_entry: FINI_ARRAY must be a PTR" + | D_Ptr p -> return p + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: FINI_ARRAY must be a PTR" + ) >>= (fun ptr -> + return (Address ptr)) + else if Nat_big_num.equal tag dt_init_arraysz then + (match dyn.elf32_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf32_dyn_entry: INIT_ARRAYSZ must be a VAL" + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: INIT_ARRAYSZ must be a VAL" + ) >>= (fun sz -> + return (Size sz)) + else if Nat_big_num.equal tag dt_fini_arraysz then + (match dyn.elf32_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf32_dyn_entry: FINI_ARRAYSZ must be a VAL" + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: FINI_ARRAYSZ must be a VAL" + ) >>= (fun sz -> + return (Size sz)) + else if Nat_big_num.equal tag dt_runpath then + (match dyn.elf32_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf32_dyn_entry: RUNPATH must be a Val" + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: RUNPATH must be a Val" + ) >>= (fun off -> + let off = (Nat_big_num.of_string (Uint32.to_string off)) in + String_table.get_string_at off stab >>= (fun str -> + return (RunPath str))) + else if Nat_big_num.equal tag dt_flags then + (match dyn.elf32_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf32_dyn_entry: FLAGS must be a Val" + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: FLAGS must be a Val" + ) >>= (fun flags -> + return (Flags (Nat_big_num.of_string (Uint32.to_string flags)))) + else if Nat_big_num.equal tag dt_encoding then + if not shared_object then + return Ignored + else + (match dyn.elf32_dyn_d_un with + | D_Val v -> fail "get_value_of_elf32_dyn_entry: PREINIT_ARRAY must be a PTR" + | D_Ptr p -> return p + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: PREINIT_ARRAY must be a PTR" + ) >>= (fun ptr -> + return (Address ptr)) + else if Nat_big_num.equal tag dt_preinit_arraysz then + (match dyn.elf32_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf32_dyn_entry: PREINIT_ARRAYSZ must be a VAL" + | D_Ignored i -> fail "get_value_of_elf32_dyn_entry: PREINIT_ARRAYSZ must be a VAL" + ) >>= (fun sz -> + return (Checksum (Nat_big_num.of_string (Uint32.to_string sz)))) (** XXX: bug in readelf does not print this as a size! *) + else if Nat_big_num.greater_equal tag dt_loproc && Nat_big_num.less_equal tag dt_hiproc then + proc dyn stab + else if Nat_big_num.greater_equal tag dt_loos && Nat_big_num.less_equal tag dt_hios then + os dyn stab + else if os_additional_ranges tag then + os dyn stab + else + fail "get_value_of_elf32_dyn: unrecognised tag type") + +(** [get_value_of_elf64_dyn dyn os_additional_ranges os proc stab] returns the value + * stored in a dynamic section entry [dyn], using [os_additional_ranges] and + * [os] to decode ABI-reserved tags. String table [stab] is used to correctly + * decode library and run paths, etc. + * May fail. + *) +(*val get_value_of_elf64_dyn : bool -> elf64_dyn -> (natural -> bool) -> + (elf64_dyn -> string_table -> error elf64_dyn_value) -> + (elf64_dyn -> string_table -> error elf64_dyn_value) -> + string_table -> error elf64_dyn_value*) +let get_value_of_elf64_dyn shared_object dyn os_additional_ranges os_dyn proc_dyn stab:(((Uint64.uint64),(Uint64.uint64))dyn_value)error= + (let tag = (Nat_big_num.abs (Nat_big_num.of_int64 dyn.elf64_dyn_tag)) in + if Nat_big_num.equal tag dt_null then + return Null + else if Nat_big_num.equal tag dt_needed then + (match dyn.elf64_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf64_dyn_entry: NEEDED must be a Val" + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: NEEDED must be a Val" + ) >>= (fun off -> + let off = (Ml_bindings.nat_big_num_of_uint64 off) in + String_table.get_string_at off stab >>= (fun str -> + return (Library str))) + else if Nat_big_num.equal tag dt_pltrelsz then + (match dyn.elf64_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf64_dyn_entry: PLTRELSZ must be a Val" + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: PLTRELSZ must be a Val" + ) >>= (fun sz -> + return (Size sz)) + else if Nat_big_num.equal tag dt_pltgot then + (match dyn.elf64_dyn_d_un with + | D_Val v -> fail "get_value_of_elf64_dyn_entry: PLTGOT must be a PTR" + | D_Ptr p -> return p + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: PLTGOT must be a PTR" + ) >>= (fun ptr -> + return (Address ptr)) + else if Nat_big_num.equal tag dt_hash then + (match dyn.elf64_dyn_d_un with + | D_Val v -> fail "get_value_of_elf64_dyn_entry: HASH must be a PTR" + | D_Ptr p -> return p + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: HASH must be a PTR" + ) >>= (fun ptr -> + return (Address ptr)) + else if Nat_big_num.equal tag dt_strtab then + (match dyn.elf64_dyn_d_un with + | D_Val v -> fail "get_value_of_elf64_dyn_entry: STRTAB must be a PTR" + | D_Ptr p -> return p + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: STRTAB must be a PTR" + ) >>= (fun ptr -> + return (Address ptr)) + else if Nat_big_num.equal tag dt_symtab then + (match dyn.elf64_dyn_d_un with + | D_Val v -> fail "get_value_of_elf64_dyn_entry: SYMTAB must be a PTR" + | D_Ptr p -> return p + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: SYMTAB must be a PTR" + ) >>= (fun ptr -> + return (Address ptr)) + else if Nat_big_num.equal tag dt_rela then + (match dyn.elf64_dyn_d_un with + | D_Val v -> fail "get_value_of_elf64_dyn_entry: RELA must be a PTR" + | D_Ptr p -> return p + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: RELA must be a PTR" + ) >>= (fun ptr -> + return (Address ptr)) + else if Nat_big_num.equal tag dt_relasz then + (match dyn.elf64_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf64_dyn_entry: RELASZ must be a VAL" + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: RELASZ must be a VAL" + ) >>= (fun sz -> + return (Size sz)) + else if Nat_big_num.equal tag dt_relaent then + (match dyn.elf64_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf64_dyn_entry: RELAENT must be a VAL" + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: RELAENT must be a VAL" + ) >>= (fun sz -> + return (Size sz)) + else if Nat_big_num.equal tag dt_strsz then + (match dyn.elf64_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf64_dyn_entry: STRSZ must be a VAL" + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: STRSZ must be a VAL" + ) >>= (fun sz -> + return (Size sz)) + else if Nat_big_num.equal tag dt_syment then + (match dyn.elf64_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf64_dyn_entry: SYMENT must be a VAL" + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: SYMENT must be a VAL" + ) >>= (fun sz -> + return (Size sz)) + else if Nat_big_num.equal tag dt_init then + (match dyn.elf64_dyn_d_un with + | D_Val v -> fail "get_value_of_elf64_dyn_entry: INIT must be a PTR" + | D_Ptr p -> return p + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: INIT must be a PTR" + ) >>= (fun ptr -> + return (Address ptr)) + else if Nat_big_num.equal tag dt_fini then + (match dyn.elf64_dyn_d_un with + | D_Val v -> fail "get_value_of_elf64_dyn_entry: FINI must be a PTR" + | D_Ptr p -> return p + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: FINI must be a PTR" + ) >>= (fun ptr -> + return (Address ptr)) + else if Nat_big_num.equal tag dt_soname then + (match dyn.elf64_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf64_dyn_entry: SONAME must be a Val" + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: SONAME must be a Val" + ) >>= (fun off -> + let off = (Ml_bindings.nat_big_num_of_uint64 off) in + String_table.get_string_at off stab >>= (fun str -> + return (SOName str))) + else if Nat_big_num.equal tag dt_rpath then + (match dyn.elf64_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf64_dyn_entry: RPATH must be a Val" + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: RPATH must be a Val" + ) >>= (fun off -> + let off = (Ml_bindings.nat_big_num_of_uint64 off) in + String_table.get_string_at off stab >>= (fun str -> + return (RPath str))) + else if Nat_big_num.equal tag dt_symbolic then + return Null + else if Nat_big_num.equal tag dt_rel then + (match dyn.elf64_dyn_d_un with + | D_Val v -> fail "get_value_of_elf64_dyn_entry: REL must be a PTR" + | D_Ptr p -> return p + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: REL must be a PTR" + ) >>= (fun ptr -> + return (Address ptr)) + else if Nat_big_num.equal tag dt_relsz then + (match dyn.elf64_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf64_dyn_entry: RELSZ must be a VAL" + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: RELSZ must be a VAL" + ) >>= (fun sz -> + return (Size sz)) + else if Nat_big_num.equal tag dt_relent then + (match dyn.elf64_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf64_dyn_entry: RELENT must be a VAL" + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: RELENT must be a VAL" + ) >>= (fun sz -> + return (Size sz)) + else if Nat_big_num.equal tag dt_pltrel then + (match dyn.elf64_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf64_dyn_entry: PLTREL must be a VAL" + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: PLTREL must be a VAL" + ) >>= (fun r -> + if Nat_big_num.equal (Ml_bindings.nat_big_num_of_uint64 r) dt_rel then + return (RelType Rel) + else if Nat_big_num.equal (Ml_bindings.nat_big_num_of_uint64 r) dt_rela then + return (RelType RelA) + else + fail "get_value_of_elf64_dyn_entry: PLTREL neither REL nor RELA") + else if Nat_big_num.equal tag dt_debug then + return Null + else if Nat_big_num.equal tag dt_textrel then + return Null + else if Nat_big_num.equal tag dt_jmprel then + (match dyn.elf64_dyn_d_un with + | D_Val v -> fail "get_value_of_elf64_dyn_entry: JMPREL must be a PTR" + | D_Ptr p -> return p + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: JMPREL must be a PTR" + ) >>= (fun ptr -> + return (Address ptr)) + else if Nat_big_num.equal tag dt_bindnow then + return Ignored + else if Nat_big_num.equal tag dt_init_array then + (match dyn.elf64_dyn_d_un with + | D_Val v -> fail "get_value_of_elf64_dyn_entry: INIT_ARRAY must be a PTR" + | D_Ptr p -> return p + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: INIT_ARRAY must be a PTR" + ) >>= (fun ptr -> + return (Address ptr)) + else if Nat_big_num.equal tag dt_fini_array then + (match dyn.elf64_dyn_d_un with + | D_Val v -> fail "get_value_of_elf64_dyn_entry: FINI_ARRAY must be a PTR" + | D_Ptr p -> return p + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: FINI_ARRAY must be a PTR" + ) >>= (fun ptr -> + return (Address ptr)) + else if Nat_big_num.equal tag dt_init_arraysz then + (match dyn.elf64_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf64_dyn_entry: INIT_ARRAYSZ must be a VAL" + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: INIT_ARRAYSZ must be a VAL" + ) >>= (fun sz -> + return (Size sz)) + else if Nat_big_num.equal tag dt_fini_arraysz then + (match dyn.elf64_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf64_dyn_entry: FINI_ARRAYSZ must be a VAL" + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: FINI_ARRAYSZ must be a VAL" + ) >>= (fun sz -> + return (Size sz)) + else if Nat_big_num.equal tag dt_runpath then + (match dyn.elf64_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf64_dyn_entry: RUNPATH must be a Val" + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: RUNPATH must be a Val" + ) >>= (fun off -> + let off = (Ml_bindings.nat_big_num_of_uint64 off) in + String_table.get_string_at off stab >>= (fun str -> + return (RunPath str))) + else if Nat_big_num.equal tag dt_flags then + (match dyn.elf64_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf64_dyn_entry: FLAGS must be a Val" + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: FLAGS must be a Val" + ) >>= (fun flags -> + return (Flags (Ml_bindings.nat_big_num_of_uint64 flags))) + else if Nat_big_num.equal tag dt_encoding then + if not shared_object then + return Ignored + else + (match dyn.elf64_dyn_d_un with + | D_Val v -> fail "get_value_of_elf64_dyn_entry: PREINIT_ARRAY must be a PTR" + | D_Ptr p -> return p + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: PREINIT_ARRAY must be a PTR" + ) >>= (fun ptr -> + return (Address ptr)) + else if Nat_big_num.equal tag dt_preinit_arraysz then + (match dyn.elf64_dyn_d_un with + | D_Val v -> return v + | D_Ptr p -> fail "get_value_of_elf64_dyn_entry: PREINIT_ARRAYSZ must be a VAL" + | D_Ignored i -> fail "get_value_of_elf64_dyn_entry: PREINIT_ARRAYSZ must be a VAL" + ) >>= (fun sz -> + return (Checksum (Ml_bindings.nat_big_num_of_uint64 sz))) (** XXX: bug in readelf does not print this as a size! *) + else if Nat_big_num.greater_equal tag dt_loproc && Nat_big_num.less_equal tag dt_hiproc then + proc_dyn dyn stab + else if Nat_big_num.greater_equal tag dt_loos && Nat_big_num.less_equal tag dt_hios then + os_dyn dyn stab + else if os_additional_ranges tag then + os_dyn dyn stab + else + fail "get_value_of_elf64_dyn: unrecognised tag type") |
