summaryrefslogtreecommitdiff
path: root/lib/ocaml_rts/linksem/elf_file.ml
diff options
context:
space:
mode:
authorAlasdair Armstrong2017-09-07 16:54:20 +0100
committerAlasdair Armstrong2017-09-07 16:54:20 +0100
commit842165c1171fde332bd42e7520338c59a797f76b (patch)
tree75b61297b6d9b6e4810542390eb1371afc2f183f /lib/ocaml_rts/linksem/elf_file.ml
parent8124c487b576661dfa7a0833415d07d0978bc43e (diff)
Add ocaml run-time and updates to sail for ocaml backend
Diffstat (limited to 'lib/ocaml_rts/linksem/elf_file.ml')
-rw-r--r--lib/ocaml_rts/linksem/elf_file.ml1198
1 files changed, 1198 insertions, 0 deletions
diff --git a/lib/ocaml_rts/linksem/elf_file.ml b/lib/ocaml_rts/linksem/elf_file.ml
new file mode 100644
index 00000000..fda353f8
--- /dev/null
+++ b/lib/ocaml_rts/linksem/elf_file.ml
@@ -0,0 +1,1198 @@
+(*Generated by Lem from elf_file.lem.*)
+(** Module [elf_file] packages all components of an ELF file up into a single
+ * record, provides I/O routines for this record, as well as other utility
+ * functions that operate on an entire ELF file.
+ *)
+
+open Lem_basic_classes
+open Lem_bool
+open Lem_list
+open Lem_num
+open Lem_maybe
+open Lem_string
+
+open Elf_header
+open Elf_interpreted_section
+open Elf_interpreted_segment
+open Elf_types_native_uint
+open Elf_section_header_table
+open Elf_symbol_table
+open Elf_program_header_table
+
+open String_table
+
+open Byte_sequence
+open Error
+open Missing_pervasives
+open Show
+
+(** [elf32_file] record captures the internal structure of an ELF32 file.
+ * Invariant: length of the program header and section header tables should match
+ * the length of their interpreted counterparts, and the nth element of the
+ * (program/section) header table must correspond to the nth element of the
+ * interpreted (segments/sections), respectively.
+ *)
+type elf32_file =
+ { elf32_file_header : elf32_header (** The file header. *)
+ ; elf32_file_program_header_table : elf32_program_header_table (** The program header table. *)
+ ; elf32_file_section_header_table : elf32_section_header_table (** The section header table. *)
+ ; elf32_file_interpreted_segments : elf32_interpreted_segments (** A more usable interpretation of the file's segments. *)
+ ; elf32_file_interpreted_sections : elf32_interpreted_sections (** A more usable interpretation of the file's sections. *)
+ ; elf32_file_bits_and_bobs : (Nat_big_num.num * byte_sequence) list (** The uninterpreted "rubbish" that may appear in gaps in the binary file. *)
+ }
+
+(** [bytes_of_elf32_file f1] blits ELF file [f1] to a byte sequence, ready for
+ * writing to a binary file. Fails if the invariant on [elf32_file] mentioned
+ * above is not respected.
+ *)
+(*val bytes_of_elf32_file : elf32_file -> error byte_sequence*)
+let bytes_of_elf32_file ef:(byte_sequence)error=
+ (let endian = (get_elf32_header_endianness ef.elf32_file_header) in
+ let hdr_bytes = (bytes_of_elf32_header ef.elf32_file_header) in
+ let hdr_layout = (Nat_big_num.of_int 0, hdr_bytes) in
+ let pht_bytes = (bytes_of_elf32_program_header_table endian ef.elf32_file_program_header_table) in
+ let sht_bytes = (bytes_of_elf32_section_header_table endian ef.elf32_file_section_header_table) in
+ let pht_off = (Nat_big_num.of_string (Uint32.to_string ef.elf32_file_header.elf32_phoff)) in
+ let sht_off = (Nat_big_num.of_string (Uint32.to_string ef.elf32_file_header.elf32_shoff)) in
+ let pht_layout = (pht_off, pht_bytes) in
+ let sht_layout = (sht_off, sht_bytes) in
+ let bab_layout = (ef.elf32_file_bits_and_bobs) in
+ if List.length ef.elf32_file_program_header_table =
+ List.length ef.elf32_file_interpreted_segments then
+ if List.length ef.elf32_file_section_header_table =
+ List.length ef.elf32_file_interpreted_sections then
+ let segs_zip = (Lem_list.list_combine ef.elf32_file_program_header_table ef.elf32_file_interpreted_segments) in
+ let sects_zip = (Lem_list.list_combine ef.elf32_file_section_header_table ef.elf32_file_interpreted_sections) in
+ let segs_layout =
+(Lem_list.map (fun (seg, interp_seg) ->
+ (Nat_big_num.of_string (Uint32.to_string seg.elf32_p_offset), interp_seg.elf32_segment_body)
+ ) (List.filter (fun (x, _) -> not (x.elf32_p_filesz = (Uint32.of_string (Nat_big_num.to_string (Nat_big_num.of_int 0))))) segs_zip))
+ in
+ let sects_layout =
+(Lem_list.map (fun (sect, interp_sect) ->
+ (Nat_big_num.of_string (Uint32.to_string sect.elf32_sh_offset), interp_sect.elf32_section_body)
+ ) (List.filter (fun (x, _) -> not (x.elf32_sh_type = (Uint32.of_string (Nat_big_num.to_string sht_nobits)))) sects_zip))
+ in
+ let pre_layout = (List.rev_append (List.rev (List.rev_append (List.rev (List.rev_append (List.rev [hdr_layout; pht_layout; sht_layout]) sects_layout)) segs_layout)) bab_layout) in
+ let final_layout =
+(List.sort (fun (off_x, _) (off_y, _) -> Nat_big_num.compare off_x off_y)
+ pre_layout)
+ in
+ let concats =
+(foldM (fun x y ->
+ let (current_offset, so_far) = x in
+ let (point_to_add, body) = y in
+ if Nat_big_num.less point_to_add current_offset then
+ let diff = (Nat_big_num.sub_nat current_offset point_to_add) in
+ (* Completely contained inside other segment *)
+ if Nat_big_num.less (Byte_sequence.length0 body) diff then
+ return (current_offset, so_far)
+ else
+ Byte_sequence.partition0 diff body >>= (fun (_, cut) ->
+ let concat3 = (Byte_sequence.concat0 [so_far; cut]) in
+ let delta = (Nat_big_num.add current_offset (Byte_sequence.length0 cut)) in
+ return (delta, concat3))
+ else
+ let diff = (Nat_big_num.sub_nat point_to_add current_offset) in
+ let reps = (Byte_sequence.create diff '\000') in
+ let concat3 = (Byte_sequence.concat0 [so_far; reps; body]) in
+ let delta = (Nat_big_num.add point_to_add (Byte_sequence.length0 body)) in
+ return (delta, concat3)
+ ) (Nat_big_num.of_int 0, Byte_sequence.empty) final_layout)
+ in
+ concats >>= (fun (offset, body) ->
+ return body)
+ else
+ fail "bytes_of_elf32_file: interpreted sections and section header table must have same length"
+ else
+ fail "bytes_of_elf32_file: interpreted segments and program header table must have same length")
+
+(** [elf64_file] record captures the internal structure of an ELF32 file.
+ * Invariant: length of the program header and section header tables should match
+ * the length of their interpreted counterparts, and the nth element of the
+ * (program/section) header table must correspond to the nth element of the
+ * interpreted (segments/sections), respectively.
+ *)
+type elf64_file =
+ { elf64_file_header : elf64_header (** The file header. *)
+ ; elf64_file_program_header_table : elf64_program_header_table (** The program header table. *)
+ ; elf64_file_section_header_table : elf64_section_header_table (** The section header table. *)
+ ; elf64_file_interpreted_segments : elf64_interpreted_segments (** A more usable interpretation of the file's segments. *)
+ ; elf64_file_interpreted_sections : elf64_interpreted_sections (** A more usable interpretation of the file's sections. *)
+ ; elf64_file_bits_and_bobs : (Nat_big_num.num * byte_sequence) list (** The uninterpreted "rubbish" that may appear in gaps in the binary file. *)
+ }
+
+
+type elf_file =
+ | ELF_File_32 of elf32_file
+ | ELF_File_64 of elf64_file
+
+
+
+
+(** [bytes_of_elf64_file f1] blits ELF file [f1] to a byte sequence, ready for
+ * writing to a binary file. Fails if the invariant on [elf64_file] mentioned
+ * above is not respected.
+ *)
+(*val bytes_of_elf64_file : elf64_file -> error byte_sequence*)
+let bytes_of_elf64_file ef:(byte_sequence)error=
+ (let endian = (get_elf64_header_endianness ef.elf64_file_header) in
+ let hdr_bytes = (bytes_of_elf64_header ef.elf64_file_header) in
+ let hdr_layout = (Nat_big_num.of_int 0, hdr_bytes) in
+ let pht_bytes = (bytes_of_elf64_program_header_table endian ef.elf64_file_program_header_table) in
+ let sht_bytes = (bytes_of_elf64_section_header_table endian ef.elf64_file_section_header_table) in
+ let pht_off = (Nat_big_num.of_string (Uint64.to_string ef.elf64_file_header.elf64_phoff)) in
+ let sht_off = (Nat_big_num.of_string (Uint64.to_string ef.elf64_file_header.elf64_shoff)) in
+ let pht_layout = (pht_off, pht_bytes) in
+ let sht_layout = (sht_off, sht_bytes) in
+ let bab_layout = (ef.elf64_file_bits_and_bobs) in
+ if (* List.length ef.elf64_file_program_header_table =
+ List.length ef.elf64_file_interpreted_segments *) true then
+ if List.length ef.elf64_file_section_header_table =
+ List.length ef.elf64_file_interpreted_sections then
+ let segs_zip = (Lem_list.list_combine ef.elf64_file_program_header_table ef.elf64_file_interpreted_segments) in
+ let sects_zip = (Lem_list.list_combine ef.elf64_file_section_header_table ef.elf64_file_interpreted_sections) in
+ let segs_layout = ([]) (*
+ List.map (fun (seg, interp_seg) ->
+ (natural_of_elf64_off seg.elf64_p_offset, interp_seg.elf64_segment_body)
+ ) (List.filter (fun (x, _) -> x.elf64_p_filesz <> elf64_xword_of_natural 0) segs_zip) *)
+ in
+ let sects_layout =
+(Lem_list.map (fun (sect, interp_sect) ->
+ (Nat_big_num.of_string (Uint64.to_string sect.elf64_sh_offset), interp_sect.elf64_section_body)
+ ) (List.filter (fun (x, _) -> not (x.elf64_sh_type = (Uint32.of_string (Nat_big_num.to_string sht_nobits)))) sects_zip))
+ in
+ let pre_layout = (List.rev_append (List.rev (List.rev_append (List.rev (List.rev_append (List.rev [hdr_layout; pht_layout; sht_layout]) sects_layout)) segs_layout)) bab_layout) in
+ let final_layout =
+(List.sort (fun (off_x, _) (off_y, _) -> Nat_big_num.compare off_x off_y)
+ pre_layout)
+ in
+ let concats =
+(foldM (fun x y ->
+ let (current_offset, so_far) = x in
+ let (point_to_add, body) = y in
+ if Nat_big_num.less point_to_add current_offset then
+ let diff = (Nat_big_num.sub_nat current_offset point_to_add) in
+ (* Completely contained inside other segment *)
+ if Nat_big_num.less (Byte_sequence.length0 body) diff then
+ return (current_offset, so_far)
+ else
+ Byte_sequence.partition0 diff body >>= (fun (_, cut) ->
+ let concat3 = (Byte_sequence.concat0 [so_far; cut]) in
+ let delta = (Nat_big_num.add current_offset (Byte_sequence.length0 cut)) in
+ return (delta, concat3))
+ else
+ let diff = (Nat_big_num.sub_nat point_to_add current_offset) in
+ let reps = (Byte_sequence.create diff '\000') in
+ let concat3 = (Byte_sequence.concat0 [so_far; reps; body]) in
+ let delta = (Nat_big_num.add point_to_add (Byte_sequence.length0 body)) in
+ return (delta, concat3)
+ ) (Nat_big_num.of_int 0, Byte_sequence.empty) final_layout)
+ in
+ concats >>= (fun (offset, body) ->
+ return body)
+ else
+ fail "bytes_of_elf64_file: interpreted sections and section header table must have same length"
+ else
+ fail "bytes_of_elf64_file: interpreted segments and program header table must have same length")
+
+(** [obtain_elf32_program_header_table hdr bs0] reads a file's program header table
+ * from byte sequence [bs0] using information gleaned from the file header [hdr].
+ * Fails if transcription fails.
+ *)
+(*val obtain_elf32_program_header_table : elf32_header -> byte_sequence
+ -> error elf32_program_header_table*)
+let obtain_elf32_program_header_table hdr bs0:((elf32_program_header_table_entry)list)error=
+ (let endian = (get_elf32_header_endianness hdr) in
+ let pentries = (Nat_big_num.of_string (Uint32.to_string hdr.elf32_phnum)) in
+ let pentry_size = (Nat_big_num.of_string (Uint32.to_string hdr.elf32_phentsize)) in
+ let psize = (Nat_big_num.mul pentries pentry_size) in
+ if Nat_big_num.equal psize(Nat_big_num.of_int 0) then
+ return []
+ else
+ let poffset = (Nat_big_num.of_string (Uint32.to_string hdr.elf32_phoff)) in
+ Byte_sequence.offset_and_cut poffset psize bs0 >>= (fun pexact ->
+ (* Byte sequence irrelevant below as exact size used... *)
+ read_elf32_program_header_table psize endian pexact >>= (fun (pht, _) ->
+ return pht)))
+
+(** [obtain_elf64_program_header_table hdr bs0] reads a file's program header table
+ * from byte sequence [bs0] using information gleaned from the file header [hdr].
+ * Fails if transcription fails.
+ *)
+(*val obtain_elf64_program_header_table : elf64_header -> byte_sequence
+ -> error elf64_program_header_table*)
+let obtain_elf64_program_header_table hdr bs0:((elf64_program_header_table_entry)list)error=
+ (let endian = (get_elf64_header_endianness hdr) in
+ let pentries = (Nat_big_num.of_string (Uint32.to_string hdr.elf64_phnum)) in
+ let pentry_size = (Nat_big_num.of_string (Uint32.to_string hdr.elf64_phentsize)) in
+ let psize = (Nat_big_num.mul pentries pentry_size) in
+ if Nat_big_num.equal psize(Nat_big_num.of_int 0) then
+ return []
+ else
+ let poffset = (Nat_big_num.of_string (Uint64.to_string hdr.elf64_phoff)) in
+ Byte_sequence.offset_and_cut poffset psize bs0 >>= (fun pexact ->
+ (* Byte sequence irrelevant below as exact size used... *)
+ read_elf64_program_header_table psize endian pexact >>= (fun (pht, _) ->
+ return pht)))
+
+(** [obtain_elf32_section_header_table hdr bs0] reads a file's section header table
+ * from byte sequence [bs0] using information gleaned from the file header [hdr].
+ * Fails if transcription fails.
+ *)
+(*val obtain_elf32_section_header_table : elf32_header -> byte_sequence
+ -> error elf32_section_header_table*)
+let obtain_elf32_section_header_table hdr bs0:((elf32_section_header_table_entry)list)error=
+ (let endian = (get_elf32_header_endianness hdr) in
+ let sentries = (Nat_big_num.of_string (Uint32.to_string hdr.elf32_shnum)) in
+ let sentry_size = (Nat_big_num.of_string (Uint32.to_string hdr.elf32_shentsize)) in
+ let ssize = (Nat_big_num.mul sentries sentry_size) in
+ if Nat_big_num.equal ssize(Nat_big_num.of_int 0) then
+ return []
+ else
+ let soffset = (Nat_big_num.of_string (Uint32.to_string hdr.elf32_shoff)) in
+ Byte_sequence.offset_and_cut soffset ssize bs0 >>= (fun sexact ->
+ (* Byte sequence irrelevant below as exact size used... *)
+ read_elf32_section_header_table ssize endian sexact >>= (fun (sht, _) ->
+ return sht)))
+
+(** [obtain_elf64_section_header_table hdr bs0] reads a file's section header table
+ * from byte sequence [bs0] using information gleaned from the file header [hdr].
+ * Fails if transcription fails.
+ *)
+(*val obtain_elf64_section_header_table : elf64_header -> byte_sequence -> error elf64_section_header_table*)
+let obtain_elf64_section_header_table hdr bs0:((elf64_section_header_table_entry)list)error=
+ (let endian = (get_elf64_header_endianness hdr) in
+ let sentries = (Nat_big_num.of_string (Uint32.to_string hdr.elf64_shnum)) in
+ let sentry_size = (Nat_big_num.of_string (Uint32.to_string hdr.elf64_shentsize)) in
+ let ssize = (Nat_big_num.mul sentries sentry_size) in
+ if Nat_big_num.equal ssize(Nat_big_num.of_int 0) then
+ return []
+ else
+ let soffset = (Nat_big_num.of_string (Uint64.to_string hdr.elf64_shoff)) in
+ Byte_sequence.offset_and_cut soffset ssize bs0 >>= (fun sexact ->
+ (* Byte sequence irrelevant below as exact size used... *)
+ read_elf64_section_header_table ssize endian sexact >>= (fun (sht, _) ->
+ return sht)))
+
+(** [obtain_elf32_section_header_string_table hdr sht bs0] reads a file's section
+ * header string table from byte sequence [bs0] using information gleaned from
+ * the file header [hdr] and section header table [sht].
+ * Fails if transcription fails.
+ *)
+(*val obtain_elf32_section_header_string_table : elf32_header ->
+ elf32_section_header_table -> byte_sequence -> error (maybe string_table)*)
+let obtain_elf32_section_header_string_table hdr sht bs0:((string_table)option)error=
+ (if Nat_big_num.equal (Nat_big_num.of_string (Uint32.to_string hdr.elf32_shstrndx)) shn_undef then
+ return None
+ else
+ (match Ml_bindings.list_index_big_int (Nat_big_num.of_string (Uint32.to_string hdr.elf32_shstrndx)) sht with
+ None -> fail "no section header string table"
+ | Some x -> return x
+ ) >>= (fun sh ->
+ Byte_sequence.offset_and_cut (Nat_big_num.of_string (Uint32.to_string sh.elf32_sh_offset)) (Nat_big_num.of_string (Uint32.to_string sh.elf32_sh_size)) bs0 >>= (fun sexact ->
+ return (Some (string_table_of_byte_sequence sexact)))))
+
+(** [obtain_elf64_section_header_string_table hdr sht bs0] reads a file's section
+ * header string table from byte sequence [bs0] using information gleaned from
+ * the file header [hdr] and section header table [sht].
+ * Fails if transcription fails.
+ *)
+(*val obtain_elf64_section_header_string_table : elf64_header ->
+ elf64_section_header_table -> byte_sequence -> error (maybe string_table)*)
+let obtain_elf64_section_header_string_table hdr sht bs0:((string_table)option)error=
+ (if Nat_big_num.equal (Nat_big_num.of_string (Uint32.to_string hdr.elf64_shstrndx)) shn_undef then
+ return None
+ else
+ (match Ml_bindings.list_index_big_int (Nat_big_num.of_string (Uint32.to_string hdr.elf64_shstrndx)) sht with
+ None -> fail "no section header string table"
+ | Some x -> return x
+ ) >>= (fun sh ->
+ Byte_sequence.offset_and_cut (Nat_big_num.of_string (Uint64.to_string sh.elf64_sh_offset)) (Ml_bindings.nat_big_num_of_uint64 sh.elf64_sh_size) bs0 >>= (fun sexact ->
+ return (Some (string_table_of_byte_sequence sexact)))))
+
+(** [obtain_elf32_interpreted_segments pht bs0] generates the interpreted segments
+ * of an ELF file from the uninterpreted program header table entries in [pht],
+ * read from byte sequence [bs0]. Makes working with segments easier.
+ * May fail if transcription of any segment fails.
+ *)
+(*val obtain_elf32_interpreted_segments : elf32_program_header_table -> byte_sequence
+ -> error elf32_interpreted_segments*)
+let obtain_elf32_interpreted_segments pht bdy:((elf32_interpreted_segment)list)error=
+ (mapM (fun ph ->
+ let offset = (Nat_big_num.of_string (Uint32.to_string ph.elf32_p_offset)) in
+ let size2 = (Nat_big_num.of_string (Uint32.to_string ph.elf32_p_filesz)) in
+ (if Nat_big_num.equal size2(Nat_big_num.of_int 0) then
+ return Byte_sequence.empty
+ else
+ Byte_sequence.offset_and_cut offset size2 bdy) >>= (fun relevant ->
+ let vaddr = (Nat_big_num.of_string (Uint32.to_string ph.elf32_p_vaddr)) in
+ let paddr = (Nat_big_num.of_string (Uint32.to_string ph.elf32_p_paddr)) in
+ let memsz = (Nat_big_num.of_string (Uint32.to_string ph.elf32_p_memsz)) in
+ let typ = (Nat_big_num.of_string (Uint32.to_string ph.elf32_p_type)) in
+ let align = (Nat_big_num.of_string (Uint32.to_string ph.elf32_p_align)) in
+ let flags = (elf32_interpret_program_header_flags ph.elf32_p_flags) in
+ if Nat_big_num.less memsz size2 then
+ fail "obtain_elf32_interpreted_segments: memory size of segment cannot be less than file size"
+ else
+ return { elf32_segment_body = relevant; elf32_segment_type = typ;
+ elf32_segment_size = size2; elf32_segment_memsz = memsz;
+ elf32_segment_base = vaddr; elf32_segment_flags = flags;
+ elf32_segment_paddr = paddr; elf32_segment_align = align;
+ elf32_segment_offset = offset })
+ ) pht)
+
+(** [obtain_elf64_interpreted_segments pht bs0] generates the interpreted segments
+ * of an ELF file from the uninterpreted program header table entries in [pht],
+ * read from byte sequence [bs0]. Makes working with segments easier.
+ * May fail if transcription of any segment fails.
+ *)
+(*val obtain_elf64_interpreted_segments : elf64_program_header_table -> byte_sequence
+ -> error elf64_interpreted_segments*)
+let obtain_elf64_interpreted_segments pht bdy:((elf64_interpreted_segment)list)error=
+ (mapM (fun ph ->
+ let offset = (Nat_big_num.of_string (Uint64.to_string ph.elf64_p_offset)) in
+ let size2 = (Ml_bindings.nat_big_num_of_uint64 ph.elf64_p_filesz) in
+ (if Nat_big_num.equal size2(Nat_big_num.of_int 0) then
+ return Byte_sequence.empty
+ else
+ Byte_sequence.offset_and_cut offset size2 bdy) >>= (fun relevant ->
+ let vaddr = (Ml_bindings.nat_big_num_of_uint64 ph.elf64_p_vaddr) in
+ let paddr = (Ml_bindings.nat_big_num_of_uint64 ph.elf64_p_paddr) in
+ let memsz = (Ml_bindings.nat_big_num_of_uint64 ph.elf64_p_memsz) in
+ let typ = (Nat_big_num.of_string (Uint32.to_string ph.elf64_p_type)) in
+ let align = (Ml_bindings.nat_big_num_of_uint64 ph.elf64_p_align) in
+ let flags = (elf64_interpret_program_header_flags ph.elf64_p_flags) in
+ if Nat_big_num.less memsz size2 then
+ fail "obtain_elf64_interpreted_segments: memory size of segment cannot be less than file size"
+ else
+ return { elf64_segment_body = relevant; elf64_segment_type = typ;
+ elf64_segment_size = size2; elf64_segment_memsz = memsz;
+ elf64_segment_base = vaddr; elf64_segment_flags = flags;
+ elf64_segment_align = align; elf64_segment_paddr = paddr;
+ elf64_segment_offset = offset })
+ ) pht)
+
+(** [obtain_elf32_interpreted_section sht bs0] generates the interpreted sections
+ * of an ELF file from the uninterpreted section header table entries in [sht],
+ * read from byte sequence [bs0]. Makes working with sections easier.
+ * May fail if transcription of any section fails.
+ *)
+(*val obtain_elf32_interpreted_sections : maybe string_table -> elf32_section_header_table
+ -> byte_sequence -> error elf32_interpreted_sections*)
+let obtain_elf32_interpreted_sections shstrtab sht bs0:((elf32_interpreted_section)list)error=
+ (mapM (fun sh ->
+ let offset = (Nat_big_num.of_string (Uint32.to_string sh.elf32_sh_offset)) in
+ let size2 = (Nat_big_num.of_string (Uint32.to_string sh.elf32_sh_size)) in
+ let name1 = (Nat_big_num.of_string (Uint32.to_string sh.elf32_sh_name)) in
+ let typ = (Nat_big_num.of_string (Uint32.to_string sh.elf32_sh_type)) in
+ let filesz = (if Nat_big_num.equal typ sht_nobits then Nat_big_num.of_int 0 else size2) in
+ let flags = (Nat_big_num.of_string (Uint32.to_string sh.elf32_sh_flags)) in
+ let base = (Nat_big_num.of_string (Uint32.to_string sh.elf32_sh_addr)) in
+ let link1 = (Nat_big_num.of_string (Uint32.to_string sh.elf32_sh_link)) in
+ let info = (Nat_big_num.of_string (Uint32.to_string sh.elf32_sh_info)) in
+ let align = (Nat_big_num.of_string (Uint32.to_string sh.elf32_sh_addralign)) in
+ let entry_size = (Nat_big_num.of_string (Uint32.to_string sh.elf32_sh_entsize)) in
+ let name_string =
+((match shstrtab with
+ None -> ""
+ | Some shstrtab ->
+ (match (get_string_at name1 shstrtab) with
+ | Success n -> n
+ | Fail _ -> ""
+ )
+ ))
+ in
+ (if Nat_big_num.equal filesz(Nat_big_num.of_int 0) then
+ return Byte_sequence.empty
+ else
+ Byte_sequence.offset_and_cut offset filesz bs0) >>= (fun relevant ->
+ return { elf32_section_name = name1; elf32_section_type = typ;
+ elf32_section_size = size2; elf32_section_offset = offset;
+ elf32_section_flags = flags; elf32_section_addr = base;
+ elf32_section_link = link1; elf32_section_info = info;
+ elf32_section_align = align; elf32_section_body = relevant;
+ elf32_section_entsize = entry_size;
+ elf32_section_name_as_string = name_string })
+ ) sht)
+
+(** [obtain_elf64_interpreted_section sht bs0] generates the interpreted sections
+ * of an ELF file from the uninterpreted section header table entries in [sht],
+ * read from byte sequence [bs0]. Makes working with sections easier.
+ * May fail if transcription of any section fails.
+ *)
+(*val obtain_elf64_interpreted_sections : maybe string_table -> elf64_section_header_table
+ -> byte_sequence -> error elf64_interpreted_sections*)
+let obtain_elf64_interpreted_sections shstrtab sht bs0:((elf64_interpreted_section)list)error=
+ (mapM (fun sh ->
+ let offset = (Nat_big_num.of_string (Uint64.to_string sh.elf64_sh_offset)) in
+ let size2 = (Ml_bindings.nat_big_num_of_uint64 sh.elf64_sh_size) in
+ let name1 = (Nat_big_num.of_string (Uint32.to_string sh.elf64_sh_name)) in
+ let typ = (Nat_big_num.of_string (Uint32.to_string sh.elf64_sh_type)) in
+ let filesz = (if Nat_big_num.equal typ sht_nobits then Nat_big_num.of_int 0 else size2) in
+ let flags = (Ml_bindings.nat_big_num_of_uint64 sh.elf64_sh_flags) in
+ let base = (Ml_bindings.nat_big_num_of_uint64 sh.elf64_sh_addr) in
+ let link1 = (Nat_big_num.of_string (Uint32.to_string sh.elf64_sh_link)) in
+ let info = (Nat_big_num.of_string (Uint32.to_string sh.elf64_sh_info)) in
+ let align = (Ml_bindings.nat_big_num_of_uint64 sh.elf64_sh_addralign) in
+ let entry_size = (Ml_bindings.nat_big_num_of_uint64 sh.elf64_sh_entsize) in
+ let name_string =
+((match shstrtab with
+ None -> ""
+ | Some shstrtab ->
+ (match (get_string_at name1 shstrtab) with
+ | Success n -> n
+ | Fail _ -> ""
+ )
+ ))
+ in
+ (if Nat_big_num.equal filesz(Nat_big_num.of_int 0) then
+ return Byte_sequence.empty
+ else
+ Byte_sequence.offset_and_cut offset filesz bs0) >>= (fun relevant ->
+ return { elf64_section_name = name1; elf64_section_type = typ;
+ elf64_section_size = size2; elf64_section_offset = offset;
+ elf64_section_flags = flags; elf64_section_addr = base;
+ elf64_section_link = link1; elf64_section_info = info;
+ elf64_section_align = align; elf64_section_body = relevant;
+ elf64_section_entsize = entry_size;
+ elf64_section_name_as_string = name_string })
+ ) sht)
+
+(** [find_first_not_in_range e rngs] for every pair (start, end) in [rngs], finds
+ * the first element, beginning counting from [e], that does not lie between
+ * a start and end value.
+ *)
+(*val find_first_not_in_range : natural -> list (natural * natural) -> natural*)
+let rec find_first_not_in_range start ranges:Nat_big_num.num=
+ ((match List.filter (fun (x, y) -> Nat_big_num.greater_equal start x && Nat_big_num.less_equal start y) ranges with
+ | [] -> start
+ | _ -> find_first_not_in_range ( Nat_big_num.add start(Nat_big_num.of_int 1)) ranges
+ ))
+
+(** [find_first_in_range e rngs] for every pair (start, end) in [rngs], finds
+ * the first element, beginning counting from [e], that lies between
+ * a start and end value.
+ *)
+(*val find_first_in_range : natural -> list (natural * natural) -> natural*)
+let rec find_first_in_range start ranges:Nat_big_num.num=
+ ((match List.filter (fun (x, y) -> Nat_big_num.greater_equal start x && Nat_big_num.less_equal start y) ranges with
+ | [] -> find_first_in_range ( Nat_big_num.add start(Nat_big_num.of_int 1)) ranges
+ | _ -> start
+ ))
+
+(** [compute_differences start max ranges] is a utility function used for calculating
+ * "dead" spots in an ELF file not covered by any of the interpreted structure
+ * that nevertheless need recording in the bits_and_bobs field of each ELF record
+ * in order to maintain in-out roundtripping up to exact binary equivalence.
+ *)
+(*val compute_differences : natural -> natural -> list (natural * natural) -> error (list (natural * natural))*)
+let rec compute_differences start max ranges:((Nat_big_num.num*Nat_big_num.num)list)error=
+ (if Nat_big_num.equal start max then
+ return []
+ else if Nat_big_num.greater start max then
+ fail "compute_differences: passed maximum"
+ else
+ let first = (find_first_not_in_range start ranges) in
+ if Nat_big_num.greater_equal first max then
+ return []
+ else
+ let last1 = (find_first_in_range first ranges) in
+ if Nat_big_num.greater last1 max then
+ return [(first, max)]
+ else
+ compute_differences last1 max ranges >>= (fun tail ->
+ return ((first, last1)::tail)))
+
+(** [obtain_elf32_bits_and_bobs hdr pht segs sht sects bs0] identifies and records
+ * the "dead" spots of an ELF file not covered by any meaningful structure of the
+ * ELF file format.
+ *)
+(*val obtain_elf32_bits_and_bobs : elf32_header -> elf32_program_header_table -> elf32_interpreted_segments
+ -> elf32_section_header_table -> elf32_interpreted_sections -> byte_sequence -> error (list (natural * byte_sequence))*)
+let obtain_elf32_bits_and_bobs hdr segs interp_segs sects interp_sects bs0:((Nat_big_num.num*byte_sequence)list)error=
+ (let hdr_off_len = (Nat_big_num.of_int 0, Nat_big_num.of_string (Uint32.to_string hdr.elf32_ehsize)) in
+ let pht_off = (Nat_big_num.of_string (Uint32.to_string hdr.elf32_phoff)) in
+ let pht_len = (Nat_big_num.mul (Nat_big_num.of_string (Uint32.to_string hdr.elf32_phentsize)) (Nat_big_num.of_string (Uint32.to_string hdr.elf32_phnum))) in
+ let pht_off_len = (pht_off, Nat_big_num.add pht_off pht_len) in
+ let sht_off = (Nat_big_num.of_string (Uint32.to_string hdr.elf32_shoff)) in
+ let sht_len = (Nat_big_num.mul (Nat_big_num.of_string (Uint32.to_string hdr.elf32_shentsize)) (Nat_big_num.of_string (Uint32.to_string hdr.elf32_shnum))) in
+ let sht_off_len = (sht_off, Nat_big_num.add sht_off sht_len) in
+ if List.length interp_segs = List.length segs then
+ let seg_zip = (Lem_list.list_combine segs interp_segs) in
+ if List.length interp_sects = List.length sects then
+ let sect_zip = (Lem_list.list_combine sects interp_sects) in
+ let seg_off_len =
+(Lem_list.map (fun (seg, interp_seg) ->
+ let start = (Nat_big_num.of_string (Uint32.to_string seg.elf32_p_offset)) in
+ let len = (interp_seg.elf32_segment_size) in
+ (start, Nat_big_num.add start len)) seg_zip)
+ in
+ let sect_off_len =
+(Lem_list.map (fun (sect, interp_sect) ->
+ let start = (Nat_big_num.of_string (Uint32.to_string sect.elf32_sh_offset)) in
+ let len = (interp_sect.elf32_section_size) in
+ (start, Nat_big_num.add start len)) sect_zip)
+ in
+ let pre_layout = (hdr_off_len :: (pht_off_len :: (sht_off_len :: List.rev_append (List.rev seg_off_len) sect_off_len))) in
+ let layout =
+(List.sort (fun (off_x, _) (off_y, _) ->
+ Nat_big_num.compare off_x off_y
+ ) pre_layout)
+ in
+ compute_differences(Nat_big_num.of_int 0) (Byte_sequence.length0 bs0) layout >>= (fun diffs ->
+ mapM (fun (start, len) ->
+ Byte_sequence.offset_and_cut start ( Nat_big_num.sub_nat len start) bs0 >>= (fun rel ->
+ return (start, rel))
+ ) diffs)
+ else
+ fail "obtain_elf32_bits_and_bobs: section header table and interpreted section differ in length"
+ else
+ fail "obtain_elf32_bits_and_bobs: program header table and interpreted segments differ in length")
+
+(** [obtain_elf64_bits_and_bobs hdr pht segs sht sects bs0] identifies and records
+ * the "dead" spots of an ELF file not covered by any meaningful structure of the
+ * ELF file format.
+ *)
+(*val obtain_elf64_bits_and_bobs : elf64_header -> elf64_program_header_table -> elf64_interpreted_segments
+ -> elf64_section_header_table -> elf64_interpreted_sections -> byte_sequence -> error (list (natural * byte_sequence))*)
+let obtain_elf64_bits_and_bobs hdr segs interp_segs sects interp_sects bs0:((Nat_big_num.num*byte_sequence)list)error=
+ (let hdr_off_len = (Nat_big_num.of_int 0, Nat_big_num.of_string (Uint32.to_string hdr.elf64_ehsize)) in
+
+ let pht_off = (Nat_big_num.of_string (Uint64.to_string hdr.elf64_phoff)) in
+ let pht_len = (Nat_big_num.mul (Nat_big_num.of_string (Uint32.to_string hdr.elf64_phentsize)) (Nat_big_num.of_string (Uint32.to_string hdr.elf64_phnum))) in
+ let pht_off_len = (pht_off, Nat_big_num.add pht_off pht_len) in
+ let sht_off = (Nat_big_num.of_string (Uint64.to_string hdr.elf64_shoff)) in
+ let sht_len = (Nat_big_num.mul (Nat_big_num.of_string (Uint32.to_string hdr.elf64_shentsize)) (Nat_big_num.of_string (Uint32.to_string hdr.elf64_shnum))) in
+ let sht_off_len = (sht_off, Nat_big_num.add sht_off sht_len) in
+ if List.length interp_segs = List.length segs then
+ let seg_zip = (Lem_list.list_combine segs interp_segs) in
+ if List.length interp_sects = List.length sects then
+ let sect_zip = (Lem_list.list_combine sects interp_sects) in
+ let seg_off_len =
+(Lem_list.map (fun (seg, interp_seg) ->
+ let start = (Nat_big_num.of_string (Uint64.to_string seg.elf64_p_offset)) in
+ let len = (interp_seg.elf64_segment_size) in
+ (start, Nat_big_num.add start len)) seg_zip)
+ in
+ let sect_off_len =
+(Lem_list.map (fun (sect, interp_sect) ->
+ let start = (Nat_big_num.of_string (Uint64.to_string sect.elf64_sh_offset)) in
+ let len = (interp_sect.elf64_section_size) in
+ (start, Nat_big_num.add start len)) sect_zip)
+ in
+ let pre_layout = (hdr_off_len :: (pht_off_len :: (sht_off_len :: List.rev_append (List.rev seg_off_len) sect_off_len))) in
+ let layout =
+(List.sort (fun (off_x, _) (off_y, _) ->
+ Nat_big_num.compare off_x off_y
+ ) pre_layout)
+ in
+ compute_differences(Nat_big_num.of_int 0) (Byte_sequence.length0 bs0) layout >>= (fun diffs ->
+ mapM (fun (start, finish) ->
+ Byte_sequence.offset_and_cut start ( Nat_big_num.sub_nat finish start) bs0 >>= (fun rel ->
+ return (start, rel))
+ ) diffs)
+ else
+ fail "obtain_elf64_bits_and_bobs: section header table and interpreted section differ in length"
+ else
+ fail "obtain_elf64_bits_and_bobs: program header table and interpreted segments differ in length")
+
+(** [read_elf32_file bs0] reads an ELF32 file from byte sequence [bs0]. Fails if
+ * transcription fails.
+ *)
+(*val read_elf32_file : byte_sequence -> error elf32_file*)
+let read_elf32_file bs0:(elf32_file)error=
+ (read_elf32_header bs0 >>= (fun (hdr, bs1) ->
+ obtain_elf32_program_header_table hdr bs0 >>= (fun pht ->
+ obtain_elf32_section_header_table hdr bs0 >>= (fun sht ->
+ obtain_elf32_section_header_string_table hdr sht bs0 >>= (fun shstrtab ->
+ obtain_elf32_interpreted_segments pht bs0 >>= (fun segs ->
+ obtain_elf32_interpreted_sections shstrtab sht bs0 >>= (fun sects ->
+ obtain_elf32_bits_and_bobs hdr pht segs sht sects bs0 >>= (fun bits_and_bobs ->
+ return { elf32_file_header = hdr;
+ elf32_file_program_header_table = pht;
+ elf32_file_section_header_table = sht;
+ elf32_file_interpreted_segments = segs;
+ elf32_file_interpreted_sections = sects;
+ elf32_file_bits_and_bobs = bits_and_bobs }))))))))
+
+(** [read_elf64_file bs0] reads an ELF64 file from byte sequence [bs0]. Fails if
+ * transcription fails.
+ *)
+(*val read_elf64_file : byte_sequence -> error elf64_file*)
+let read_elf64_file bs0:(elf64_file)error=
+ (read_elf64_header bs0 >>= (fun (hdr, bs1) ->
+ obtain_elf64_program_header_table hdr bs0 >>= (fun pht ->
+ obtain_elf64_section_header_table hdr bs0 >>= (fun sht ->
+ obtain_elf64_section_header_string_table hdr sht bs0 >>= (fun shstrtab ->
+ obtain_elf64_interpreted_segments pht bs0 >>= (fun segs ->
+ obtain_elf64_interpreted_sections shstrtab sht bs0 >>= (fun sects ->
+ obtain_elf64_bits_and_bobs hdr pht segs sht sects bs0 >>= (fun bits_and_bobs ->
+ return { elf64_file_header = hdr;
+ elf64_file_program_header_table = pht;
+ elf64_file_section_header_table = sht;
+ elf64_file_interpreted_segments = segs;
+ elf64_file_interpreted_sections = sects;
+ elf64_file_bits_and_bobs = bits_and_bobs }))))))))
+
+(** [get_elf32_file_secton_header_string_table f1] returns the ELF file, [f1],
+ * section header string table.
+ * TODO: why is this not using obtain_elf32_section_header_string_table above?
+ *)
+(*val get_elf32_file_section_header_string_table : elf32_file -> error string_table*)
+let get_elf32_file_section_header_string_table f3:(string_table)error=
+ (let hdr = (f3.elf32_file_header) in
+ let sht = (f3.elf32_file_section_header_table) in
+ let segs = (f3.elf32_file_interpreted_segments) in
+ let idx1 = (Nat_big_num.of_string (Uint32.to_string hdr.elf32_shstrndx)) in
+ bytes_of_elf32_file f3 >>= (fun bs0 ->
+ (match Ml_bindings.list_index_big_int idx1 sht with
+ | None -> fail "obtain_elf32_string_table: invalid offset into section header table"
+ | Some sect ->
+ let offset = (Nat_big_num.of_string (Uint32.to_string sect.elf32_sh_offset)) in
+ let size2 = (Nat_big_num.of_string (Uint32.to_string sect.elf32_sh_size)) in
+ Byte_sequence.offset_and_cut offset size2 bs0 >>= (fun rel ->
+ let strings = (Byte_sequence.string_of_byte_sequence rel) in
+ return (String_table.mk_string_table strings Missing_pervasives.null_char))
+ )))
+
+(** [get_elf64_file_secton_header_string_table f1] returns the ELF file, [f1],
+ * section header string table.
+ * TODO: why is this not using obtain_elf64_section_header_string_table above?
+ *)
+(*val get_elf64_file_section_header_string_table : elf64_file -> error string_table*)
+let get_elf64_file_section_header_string_table f3:(string_table)error=
+ (let hdr = (f3.elf64_file_header) in
+ let sht = (f3.elf64_file_section_header_table) in
+ let segs = (f3.elf64_file_interpreted_segments) in
+ let idx1 = (Nat_big_num.of_string (Uint32.to_string hdr.elf64_shstrndx)) in
+ bytes_of_elf64_file f3 >>= (fun bs0 ->
+ (match Ml_bindings.list_index_big_int idx1 sht with
+ | None -> fail "obtain_elf64_string_table: invalid offset into section header table"
+ | Some sect ->
+ let offset = (Nat_big_num.of_string (Uint64.to_string sect.elf64_sh_offset)) in
+ let size2 = (Ml_bindings.nat_big_num_of_uint64 sect.elf64_sh_size) in
+ Byte_sequence.offset_and_cut offset size2 bs0 >>= (fun rel ->
+ let strings = (Byte_sequence.string_of_byte_sequence rel) in
+ return (String_table.mk_string_table strings Missing_pervasives.null_char))
+ )))
+
+(*val find_elf32_symbols_by_symtab_idx : natural -> elf32_file -> error (elf32_symbol_table * string_table * natural)*)
+let find_elf32_symbols_by_symtab_idx sec_idx f:((elf32_symbol_table_entry)list*string_table*Nat_big_num.num)error=
+ ((match Lem_list.list_index f.elf32_file_interpreted_sections (Nat_big_num.to_int sec_idx) with
+ None -> fail "impossible: interpreted section found but not indexable"
+ | Some sec -> return sec
+ ) >>= (fun sec ->
+ (match Lem_list.list_index f.elf32_file_interpreted_sections (Nat_big_num.to_int sec.elf32_section_link) with
+ None -> fail "no associated strtab"
+ | Some strs -> return strs
+ ) >>= (fun strs ->
+ let strings = (Byte_sequence.string_of_byte_sequence strs.elf32_section_body) in
+ let strtab = (String_table.mk_string_table strings null_char) in
+ let endian = (get_elf32_header_endianness f.elf32_file_header) in
+ read_elf32_symbol_table endian sec.elf32_section_body >>= (fun symtab ->
+ return (symtab, strtab, sec_idx)))))
+
+(*val find_elf32_symtab_by_type : natural -> elf32_file -> error (elf32_symbol_table * string_table * natural)*)
+let find_elf32_symtab_by_type t f:(elf32_symbol_table*string_table*Nat_big_num.num)error=
+ (let found_symtab_index = (find_index0 (fun sh -> Nat_big_num.equal sh.elf32_section_type t) f.elf32_file_interpreted_sections) in
+ (match found_symtab_index with
+ None -> fail "no such symtab"
+ | Some sec_idx -> return sec_idx
+ ) >>= (fun sec_idx -> find_elf32_symbols_by_symtab_idx sec_idx f))
+
+(*val find_elf64_symbols_by_symtab_idx : natural -> elf64_file -> error (elf64_symbol_table * string_table * natural)*)
+let find_elf64_symbols_by_symtab_idx sec_idx f:((elf64_symbol_table_entry)list*string_table*Nat_big_num.num)error=
+ ((match Lem_list.list_index f.elf64_file_interpreted_sections (Nat_big_num.to_int sec_idx) with
+ None -> fail "impossible: interpreted section found but not indexable"
+ | Some sec -> return sec
+ ) >>= (fun sec ->
+ (match Lem_list.list_index f.elf64_file_interpreted_sections (Nat_big_num.to_int sec.elf64_section_link) with
+ None -> fail "no associated strtab"
+ | Some strs -> return strs
+ ) >>= (fun strs ->
+ let strings = (Byte_sequence.string_of_byte_sequence strs.elf64_section_body) in
+ let strtab = (String_table.mk_string_table strings null_char) in
+ let endian = (get_elf64_header_endianness f.elf64_file_header) in
+ read_elf64_symbol_table endian sec.elf64_section_body >>= (fun symtab ->
+ return (symtab, strtab, sec_idx)))))
+
+(*val find_elf64_symtab_by_type : natural -> elf64_file -> error (elf64_symbol_table * string_table * natural)*)
+let find_elf64_symtab_by_type t f:(elf64_symbol_table*string_table*Nat_big_num.num)error=
+ (let found_symtab_index = (find_index0 (fun sh -> Nat_big_num.equal sh.elf64_section_type t) f.elf64_file_interpreted_sections) in
+ (match found_symtab_index with
+ None -> fail "no such symtab"
+ | Some sec_idx -> return sec_idx
+ ) >>= (fun sec_idx -> find_elf64_symbols_by_symtab_idx sec_idx f))
+
+(** [get_elf32_file_symbol_string_table f1] returns the ELF file [f1] symbol
+ * string table. May fail.
+ *)
+(*val get_elf32_file_symbol_string_table : elf32_file -> error string_table*)
+let get_elf32_file_symbol_string_table f3:(string_table)error=
+ (let hdr = (f3.elf32_file_header) in
+ let sht = (f3.elf32_file_section_header_table) in
+ let segs = (f3.elf32_file_interpreted_segments) in
+ let strtabs = (Missing_pervasives.mapMaybei (fun index sect ->
+ if Nat_big_num.equal (Nat_big_num.of_string (Uint32.to_string sect.elf32_sh_type)) sht_strtab then
+ if Nat_big_num.equal index (Nat_big_num.of_string (Uint32.to_string hdr.elf32_shstrndx)) then
+ None
+ else
+ Some sect
+ else
+ None) sht)
+ in
+ bytes_of_elf32_file f3 >>= (fun bs0 ->
+ mapM (fun sect ->
+ let offset = (Nat_big_num.of_string (Uint32.to_string sect.elf32_sh_offset)) in
+ let size2 = (Nat_big_num.of_string (Uint32.to_string sect.elf32_sh_size)) in
+ Byte_sequence.offset_and_cut offset size2 bs0 >>= (fun bs1 ->
+ let strings = (Byte_sequence.string_of_byte_sequence bs1) in
+ return (String_table.mk_string_table strings Missing_pervasives.null_char))) strtabs
+ >>= (fun strings ->
+ String_table.concat1 strings)))
+
+(** [get_elf64_file_symbol_string_table f1] returns the ELF file [f1] symbol
+ * string table. May fail.
+ *)
+(*val get_elf64_file_symbol_string_table : elf64_file -> error string_table*)
+let get_elf64_file_symbol_string_table f3:(string_table)error=
+ (let hdr = (f3.elf64_file_header) in
+ let sht = (f3.elf64_file_section_header_table) in
+ let segs = (f3.elf64_file_interpreted_segments) in
+ let strtabs = (Missing_pervasives.mapMaybei (fun index sect ->
+ if Nat_big_num.equal (Nat_big_num.of_string (Uint32.to_string sect.elf64_sh_type)) sht_strtab then
+ if Nat_big_num.equal index (Nat_big_num.of_string (Uint32.to_string hdr.elf64_shstrndx)) then
+ None
+ else
+ Some sect
+ else
+ None) sht)
+ in
+ bytes_of_elf64_file f3 >>= (fun bs0 ->
+ mapM (fun sect ->
+ let offset = (Nat_big_num.of_string (Uint64.to_string sect.elf64_sh_offset)) in
+ let size2 = (Ml_bindings.nat_big_num_of_uint64 sect.elf64_sh_size) in
+ Byte_sequence.offset_and_cut offset size2 bs0 >>= (fun bs1 ->
+ let strings = (Byte_sequence.string_of_byte_sequence bs1) in
+ return (String_table.mk_string_table strings Missing_pervasives.null_char))) strtabs
+ >>= (fun strings ->
+ String_table.concat1 strings)))
+
+(** [get_elf32_file_symbol_table f1] returns the ELF file [f1] symbol
+ * table. May fail.
+ *)
+(*val get_elf32_file_symbol_table : elf32_file -> error elf32_symbol_table*)
+let get_elf32_file_symbol_table f3:((elf32_symbol_table_entry)list)error=
+ (let hdr = (f3.elf32_file_header) in
+ let sht = (f3.elf32_file_section_header_table) in
+ let segs = (f3.elf32_file_interpreted_segments) in
+ let endian = (get_elf32_header_endianness hdr) in
+ let symtabs = (List.filter (fun sect -> Nat_big_num.equal
+(Nat_big_num.of_string (Uint32.to_string sect.elf32_sh_type)) sht_symtab
+ ) sht)
+ in
+ (match symtabs with
+ | [] -> return []
+ | [symtab] ->
+ let offset = (Nat_big_num.of_string (Uint32.to_string symtab.elf32_sh_offset)) in
+ let size2 = (Nat_big_num.of_string (Uint32.to_string symtab.elf32_sh_size)) in
+ bytes_of_elf32_file f3 >>= (fun bs0 ->
+ Byte_sequence.offset_and_cut offset size2 bs0 >>= (fun relevant ->
+ read_elf32_symbol_table endian relevant))
+ | _ ->
+ fail "obtain_elf32_symbol_table: an ELF file may only have one symbol table of type SHT_SYMTAB"
+ ))
+
+(** [get_elf64_file_symbol_table f1] returns the ELF file [f1] symbol
+ * table. May fail.
+ *)
+(*val get_elf64_file_symbol_table : elf64_file -> error elf64_symbol_table*)
+let get_elf64_file_symbol_table f3:((elf64_symbol_table_entry)list)error=
+ (let hdr = (f3.elf64_file_header) in
+ let sht = (f3.elf64_file_section_header_table) in
+ let segs = (f3.elf64_file_interpreted_segments) in
+ let endian = (get_elf64_header_endianness hdr) in
+ let symtabs = (List.filter (fun sect -> Nat_big_num.equal
+(Nat_big_num.of_string (Uint32.to_string sect.elf64_sh_type)) sht_symtab
+ ) sht)
+ in
+ (match symtabs with
+ | [] -> return []
+ | [symtab] ->
+ let offset = (Nat_big_num.of_string (Uint64.to_string symtab.elf64_sh_offset)) in
+ let size2 = (Ml_bindings.nat_big_num_of_uint64 symtab.elf64_sh_size) in
+ bytes_of_elf64_file f3 >>= (fun bs0 ->
+ Byte_sequence.offset_and_cut offset size2 bs0 >>= (fun relevant ->
+ read_elf64_symbol_table endian relevant))
+ | _ ->
+ fail "obtain_elf64_symbol_table: an ELF file may only have one symbol table of type SHT_SYMTAB"
+ ))
+
+(** [get_elf32_file_dynamic_symbol_table f1] returns the ELF file [f1] dynamic
+ * symbol table. May fail.
+ *)
+(*val get_elf32_file_dynamic_symbol_table : elf32_file -> error elf32_symbol_table*)
+let get_elf32_file_dynamic_symbol_table ef:((elf32_symbol_table_entry)list)error=
+ (let hdr = (ef.elf32_file_header) in
+ let sht = (ef.elf32_file_section_header_table) in
+ let segs = (ef.elf32_file_interpreted_segments) in
+ let endian = (get_elf32_header_endianness hdr) in
+ let symtabs = (List.filter (fun sect -> Nat_big_num.equal
+(Nat_big_num.of_string (Uint32.to_string sect.elf32_sh_type)) sht_dynsym
+ ) sht)
+ in
+ (match symtabs with
+ | [] -> return []
+ | [symtab] ->
+ let offset = (Nat_big_num.of_string (Uint32.to_string symtab.elf32_sh_offset)) in
+ let size2 = (Nat_big_num.of_string (Uint32.to_string symtab.elf32_sh_size)) in
+ bytes_of_elf32_file ef >>= (fun bs0 ->
+ Byte_sequence.offset_and_cut offset size2 bs0 >>= (fun relevant ->
+ read_elf32_symbol_table endian relevant))
+ | _ ->
+ fail "obtain_elf32_dynamic_symbol_table: an ELF file may only have one symbol table of type SHT_DYNSYM"
+ ))
+
+(** [get_elf64_file_dynamic_symbol_table f1] returns the ELF file [f1] dynamic
+ * symbol table. May fail.
+ *)
+(*val get_elf64_file_dynamic_symbol_table : elf64_file -> error elf64_symbol_table*)
+let get_elf64_file_dynamic_symbol_table ef:((elf64_symbol_table_entry)list)error=
+ (let hdr = (ef.elf64_file_header) in
+ let sht = (ef.elf64_file_section_header_table) in
+ let segs = (ef.elf64_file_interpreted_segments) in
+ let endian = (get_elf64_header_endianness hdr) in
+ let symtabs = (List.filter (fun sect -> Nat_big_num.equal
+(Nat_big_num.of_string (Uint32.to_string sect.elf64_sh_type)) sht_dynsym
+ ) sht)
+ in
+ (match symtabs with
+ | [] -> return []
+ | [symtab] ->
+ let offset = (Nat_big_num.of_string (Uint64.to_string symtab.elf64_sh_offset)) in
+ let size2 = (Ml_bindings.nat_big_num_of_uint64 symtab.elf64_sh_size) in
+ bytes_of_elf64_file ef >>= (fun bs0 ->
+ Byte_sequence.offset_and_cut offset size2 bs0 >>= (fun relevant ->
+ read_elf64_symbol_table endian relevant))
+ | _ ->
+ fail "obtain_elf64_dynamic_symbol_table: an ELF file may only have one symbol table of type SHT_DYNSYM"
+ ))
+
+(** [get_elf32_file_symbol_table_by_index f1 index] returns the ELF file [f1]
+ * symbol table that is pointed to by the section header table entry at index
+ * [index]. May fail if index is out of range, or otherwise.
+ *)
+(*val get_elf32_symbol_table_by_index : elf32_file -> natural -> error elf32_symbol_table*)
+let get_elf32_symbol_table_by_index ef link1:(elf32_symbol_table)error=
+ (let hdr = (ef.elf32_file_header) in
+ let sht = (ef.elf32_file_section_header_table) in
+ let sects = (ef.elf32_file_interpreted_sections) in
+ let endian = (get_elf32_header_endianness hdr) in
+ (match Lem_list.list_index sects (Nat_big_num.to_int link1) with
+ | None -> fail "get_elf32_symbol_table_by_index: invalid index"
+ | Some sym ->
+ read_elf32_symbol_table endian sym.elf32_section_body
+ ))
+
+(** [get_elf32_file_string_table_by_index f1 index] returns the ELF file [f1]
+ * string table that is pointed to by the section header table entry at index
+ * [index]. May fail if index is out of range, or otherwise.
+ *)
+(*val get_elf32_string_table_by_index : elf32_file -> natural -> error string_table*)
+let get_elf32_string_table_by_index ef link1:(string_table)error=
+ (let hdr = (ef.elf32_file_header) in
+ let sht = (ef.elf32_file_section_header_table) in
+ let sects = (ef.elf32_file_interpreted_sections) in
+ (match Lem_list.list_index sects (Nat_big_num.to_int link1) with
+ | None -> fail "get_elf32_string_table_by_index: invalid index"
+ | Some sym -> return (mk_string_table (Byte_sequence.string_of_byte_sequence sym.elf32_section_body) Missing_pervasives.null_char)
+ ))
+
+(** [get_elf64_file_symbol_table_by_index f1 index] returns the ELF file [f1]
+ * symbol table that is pointed to by the section header table entry at index
+ * [index]. May fail if index is out of range, or otherwise.
+ *)
+(*val get_elf64_symbol_table_by_index : elf64_file -> natural -> error elf64_symbol_table*)
+let get_elf64_symbol_table_by_index ef link1:(elf64_symbol_table)error=
+ (let hdr = (ef.elf64_file_header) in
+ let sht = (ef.elf64_file_section_header_table) in
+ let sects = (ef.elf64_file_interpreted_sections) in
+ let endian = (get_elf64_header_endianness hdr) in
+ (match Lem_list.list_index sects (Nat_big_num.to_int link1) with
+ | None -> fail "get_elf64_symbol_table_by_index: invalid index"
+ | Some sym ->
+ read_elf64_symbol_table endian sym.elf64_section_body
+ ))
+
+(** [get_elf64_file_string_table_by_index f1 index] returns the ELF file [f1]
+ * string table that is pointed to by the section header table entry at index
+ * [index]. May fail if index is out of range, or otherwise.
+ *)
+(*val get_elf64_string_table_by_index : elf64_file -> natural -> error string_table*)
+let get_elf64_string_table_by_index ef link1:(string_table)error=
+ (let hdr = (ef.elf64_file_header) in
+ let sht = (ef.elf64_file_section_header_table) in
+ let sects = (ef.elf64_file_interpreted_sections) in
+ (match Lem_list.list_index sects (Nat_big_num.to_int link1) with
+ | None -> fail "get_elf64_string_table_by_index: invalid index"
+ | Some sym -> return (mk_string_table (Byte_sequence.string_of_byte_sequence sym.elf64_section_body) Missing_pervasives.null_char)
+ ))
+
+(** [segment_provenance] records whether a segment that appears in an executable
+ * process image has been derived directly from an ELF file, or was automatically
+ * created when the image calculation process noticed a segment with a memory
+ * size greater than its file size.
+ * Really a PPCMemism and not strictly needed for the ELF model itself.
+ *)
+type segment_provenance
+ = FromELF (** Segment derived directly from the source ELF file. *)
+ | AutoGenerated (** Automatically generated during process extraction as memory size is greater than file size. *)
+
+(** [elf32_executable_process_image] is a process image for ELF32 files. Contains
+ * all that is necessary to load the executable components of an ELF32 file
+ * and begin execution.
+ * XXX: (segments, provenance), entry point, machine type
+ *)
+type elf32_executable_process_image =
+ ( (elf32_interpreted_segment * segment_provenance)list * Nat_big_num.num * Nat_big_num.num)
+
+(** [elf64_executable_process_image] is a process image for ELF64 files. Contains
+ * all that is necessary to load the executable components of an ELF64 file
+ * and begin execution.
+ * XXX: (segments, provenance), entry point, machine type
+ *)
+type elf64_executable_process_image =
+ ( (elf64_interpreted_segment * segment_provenance)list * Nat_big_num.num * Nat_big_num.num)
+
+(** [get_elf32_executable_image f1] extracts an executable process image from an
+ * executable ELF file. May fail if extraction is impossible.
+ *)
+(*val get_elf32_executable_image : elf32_file -> error elf32_executable_process_image*)
+let get_elf32_executable_image f3:((elf32_interpreted_segment*segment_provenance)list*Nat_big_num.num*Nat_big_num.num)error=
+ (if is_elf32_executable_file f3.elf32_file_header then
+ let entr = (f3.elf32_file_header.elf32_entry) in
+ let segs = (f3.elf32_file_interpreted_segments) in
+ let mach = (f3.elf32_file_header.elf32_machine) in
+ (match List.filter (fun sg -> Nat_big_num.equal sg.elf32_segment_type elf_pt_load) segs with
+ | [] -> fail "get_elf32_executable_image: an executable ELF file must have at least one loadable segment"
+ | load ->
+ mapM (fun sg ->
+ if Nat_big_num.equal sg.elf32_segment_memsz(Nat_big_num.of_int 0) then
+ return []
+ else if Nat_big_num.equal sg.elf32_segment_memsz sg.elf32_segment_size then
+ return [(sg, FromELF)]
+ else if Nat_big_num.less sg.elf32_segment_size sg.elf32_segment_memsz then
+ (* Cannot be negative due to check in constructing [segs]. *)
+ let diff = (Nat_big_num.sub_nat sg.elf32_segment_memsz sg.elf32_segment_size) in
+ let zeros1 = (Byte_sequence.zeros diff) in
+ let addr = (Nat_big_num.add sg.elf32_segment_base sg.elf32_segment_size) in
+ let align = (sg.elf32_segment_align) in
+ let paddr = (sg.elf32_segment_paddr) in
+ let seg =
+({ elf32_segment_body = zeros1; elf32_segment_type = (sg.elf32_segment_type);
+ elf32_segment_size = diff; elf32_segment_memsz = diff;
+ elf32_segment_base = addr; elf32_segment_flags = (sg.elf32_segment_flags);
+ elf32_segment_align = align; elf32_segment_paddr = paddr;
+ elf32_segment_offset = (sg.elf32_segment_offset) })
+ in
+ return [(sg, FromELF); (seg, AutoGenerated)]
+ else
+ fail "get_elf32_executable_image: invariant invalidated") load >>= (fun bs_base ->
+ return (List.concat bs_base, Nat_big_num.of_string (Uint32.to_string entr), Nat_big_num.of_string (Uint32.to_string mach)))
+ )
+ else
+ fail "get_elf32_executable_image: not an ELF executable file")
+
+(** [get_elf64_executable_image f1] extracts an executable process image from an
+ * executable ELF file. May fail if extraction is impossible.
+ *)
+(*val get_elf64_executable_image : elf64_file -> error elf64_executable_process_image*)
+let get_elf64_executable_image f3:((elf64_interpreted_segment*segment_provenance)list*Nat_big_num.num*Nat_big_num.num)error=
+ (if is_elf64_executable_file f3.elf64_file_header then
+ let entr = (f3.elf64_file_header.elf64_entry) in
+ let segs = (f3.elf64_file_interpreted_segments) in
+ let mach = (f3.elf64_file_header.elf64_machine) in
+ (match List.filter (fun sg -> Nat_big_num.equal sg.elf64_segment_type elf_pt_load) segs with
+ | [] -> fail "get_elf64_executable_image: an executable ELF file must have at least one loadable segment"
+ | load ->
+ mapM (fun sg ->
+ if Nat_big_num.equal sg.elf64_segment_memsz(Nat_big_num.of_int 0) then
+ return []
+ else if Nat_big_num.equal sg.elf64_segment_memsz sg.elf64_segment_size then
+ return [(sg, FromELF)]
+ else if Nat_big_num.less sg.elf64_segment_size sg.elf64_segment_memsz then
+ (* Cannot be negative due to check in constructing [segs]. *)
+ let diff = (Nat_big_num.sub_nat sg.elf64_segment_memsz sg.elf64_segment_size) in
+ let zeros1 = (Byte_sequence.zeros diff) in
+ let addr = (Nat_big_num.add sg.elf64_segment_base sg.elf64_segment_size) in
+ let align = (sg.elf64_segment_align) in
+ let paddr = (sg.elf64_segment_paddr) in
+ let seg =
+({ elf64_segment_body = zeros1; elf64_segment_type = (sg.elf64_segment_type);
+ elf64_segment_size = diff; elf64_segment_memsz = diff;
+ elf64_segment_base = addr; elf64_segment_flags = (sg.elf64_segment_flags);
+ elf64_segment_align = align; elf64_segment_paddr = paddr;
+ elf64_segment_offset = (sg.elf64_segment_offset) })
+ in
+ return [(sg, FromELF); (seg, AutoGenerated)]
+ else
+ fail "get_elf64_executable_image: invariant invalidated") load >>= (fun bs_base ->
+ return (List.concat bs_base, Ml_bindings.nat_big_num_of_uint64 entr, Nat_big_num.of_string (Uint32.to_string mach)))
+ )
+ else
+ fail "elf64_get_executable_image: not an executable ELF file")
+
+(** [global_symbol_init_info] records the name, type, size, address, chunk
+ * of initialisation data (if relevant for that symbol), and binding, of every
+ * global symbol in an ELF file.
+ * Another PPCMemism.
+ *)
+type global_symbol_init_info
+ = (string * (Nat_big_num.num * Nat_big_num.num * Nat_big_num.num * byte_sequence option * Nat_big_num.num)) list
+
+(** [get_elf32_file_global_symbol_init f1] extracts the global symbol init info
+ * for ELF file [f1]. May fail.
+ *)
+(*val get_elf32_file_global_symbol_init : elf32_file -> error global_symbol_init_info*)
+let get_elf32_file_global_symbol_init f3:((string*(Nat_big_num.num*Nat_big_num.num*Nat_big_num.num*(byte_sequence)option*Nat_big_num.num))list)error=
+ (if is_elf32_executable_file f3.elf32_file_header then
+ let segs = (f3.elf32_file_interpreted_segments) in
+ bytes_of_elf32_file f3 >>= (fun bs0 ->
+ get_elf32_file_symbol_table f3 >>= (fun symtab ->
+ get_elf32_file_symbol_string_table f3 >>= (fun strtab ->
+ Elf_symbol_table.get_elf32_symbol_image_address symtab strtab >>= (fun strs ->
+ let mapped = (mapM (fun (symbol, (typ, size2, addr, bind)) ->
+ if Nat_big_num.equal typ Elf_symbol_table.stt_object then
+ get_elf32_executable_image f3 >>= (fun (img2, entry, mach) ->
+ let chunks1 =
+(List.filter (fun (chunk, _) -> Nat_big_num.greater_equal
+ addr chunk.elf32_segment_base &&
+ (if Nat_big_num.greater size2(Nat_big_num.of_int 0)
+ then Nat_big_num.less_equal (Nat_big_num.add addr size2) (Nat_big_num.add chunk.elf32_segment_base chunk.elf32_segment_size)
+ (* We don't consider a zero-size symbol one byte after a section
+ (i.e. addr = segment_base + segment_size) to be inside that section. *)
+ else Nat_big_num.less (Nat_big_num.add addr size2) (Nat_big_num.add chunk.elf32_segment_base chunk.elf32_segment_size))
+ ) img2)
+ in
+ (match chunks1 with
+ | [] -> fail "get_elf32_global_symbol_init: global variable not present in executable image"
+ | [(x, _)] ->
+ let rebase = (Nat_big_num.sub_nat addr x.elf32_segment_base) in
+ Byte_sequence.offset_and_cut rebase size2 x.elf32_segment_body >>= (fun relevant ->
+ return (symbol, (typ, size2, addr, Some relevant, bind)))
+ | x::xs -> fail "get_elf32_global_symbol_init: invariant failed, global variable appears in multiple segments"
+ ))
+ else
+ return (symbol, (typ, size2, addr, None, bind))) strs)
+ in
+ mapped))))
+ else
+ fail "get_elf32_file_global_symbol_init: not an executable ELF file")
+
+(** [get_elf64_file_global_symbol_init f1] extracts the global symbol init info
+ * for ELF file [f1]. May fail.
+ *)
+(*val get_elf64_file_global_symbol_init : elf64_file -> error global_symbol_init_info*)
+let get_elf64_file_global_symbol_init f3:((string*(Nat_big_num.num*Nat_big_num.num*Nat_big_num.num*(byte_sequence)option*Nat_big_num.num))list)error=
+ (if is_elf64_executable_file f3.elf64_file_header then
+ let segs = (f3.elf64_file_interpreted_segments) in
+ bytes_of_elf64_file f3 >>= (fun bs0 ->
+ get_elf64_file_symbol_table f3 >>= (fun symtab ->
+ get_elf64_file_symbol_string_table f3 >>= (fun strtab ->
+ Elf_symbol_table.get_elf64_symbol_image_address symtab strtab >>= (fun strs ->
+ let mapped = (mapM (fun (symbol, (typ, size2, addr, bind)) ->
+ if Nat_big_num.equal typ Elf_symbol_table.stt_object then
+ get_elf64_executable_image f3 >>= (fun (img2, entry, mach) ->
+ let chunks1 =
+(List.filter (fun (chunk, _) -> Nat_big_num.greater_equal
+ addr chunk.elf64_segment_base &&
+ (if Nat_big_num.greater size2(Nat_big_num.of_int 0)
+ then Nat_big_num.less_equal (Nat_big_num.add addr size2) (Nat_big_num.add chunk.elf64_segment_base chunk.elf64_segment_size)
+ (* We don't consider a zero-size symbol one byte after a section
+ (i.e. addr = segment_base + segment_size) to be inside that section. *)
+ else Nat_big_num.less (Nat_big_num.add addr size2) (Nat_big_num.add chunk.elf64_segment_base chunk.elf64_segment_size))
+ ) img2)
+ in
+ (match chunks1 with
+ | [] -> fail "get_elf64_global_symbol_init: global variable not present in executable image"
+ | [(x, _)] ->
+ let rebase = (Nat_big_num.sub_nat addr x.elf64_segment_base) in
+ Byte_sequence.offset_and_cut rebase size2 x.elf64_segment_body >>= (fun relevant ->
+ return (symbol, (typ, size2, addr, Some relevant, bind)))
+ | x::xs -> fail "get_elf64_global_symbol_init: invariant failed, global variable appears in multiple segments"
+ ))
+ else
+ return (symbol, (typ, size2, addr, None, bind))) strs)
+ in
+ mapped))))
+ else
+ fail "get_elf64_global_symbol_init: not an executable ELF file")
+
+(** [string_of_elf32_file hdr_bdl pht_bdl sht_bdl f1] produces a string-based
+ * representation of ELF file [f1] using ABI-specific print bundles [hdr_bdl],
+ * [pht_bdl] and [sht_bdl].
+ *)
+(*val string_of_elf32_file : hdr_print_bundle -> pht_print_bundle -> sht_print_bundle -> elf32_file -> string*)
+let string_of_elf32_file hdr_bdl pht_bdl sht_bdl f3:string=
+ ((match get_elf32_file_section_header_string_table f3 with
+ | Fail err ->
+ unlines [
+ "\nError obtaining ELF section header string table:"
+ ; err
+ ]
+ | Success strtab ->
+ unlines [
+ "\n*Type elf32_file:"
+ ; "**Header:"
+ ; string_of_elf32_header hdr_bdl f3.elf32_file_header
+ ; "**Program header table:"
+ ; string_of_elf32_program_header_table pht_bdl f3.elf32_file_program_header_table
+ ; "**Section header table:"
+ ; string_of_elf32_section_header_table' sht_bdl strtab f3.elf32_file_section_header_table
+ ; "**Bits and bobs (unused junk space):"
+ ; string_of_list
+ (instance_Show_Show_tup2_dict instance_Show_Show_Num_natural_dict
+ instance_Show_Show_Byte_sequence_byte_sequence_dict) f3.elf32_file_bits_and_bobs
+ ]
+ ))
+
+(** [string_of_elf64_file hdr_bdl pht_bdl sht_bdl f1] produces a string-based
+ * representation of ELF file [f1] using ABI-specific print bundles [hdr_bdl],
+ * [pht_bdl] and [sht_bdl].
+ *)
+(*val string_of_elf64_file : hdr_print_bundle -> pht_print_bundle -> sht_print_bundle -> elf64_file -> string*)
+let string_of_elf64_file hdr_bdl pht_bdl sht_bdl f3:string=
+ ((match get_elf64_file_section_header_string_table f3 with
+ | Fail err ->
+ unlines [
+ "\nError obtaining ELF section header string table:"
+ ; err
+ ]
+ | Success strtab ->
+ unlines [
+ "\n*Type elf64_file:"
+ ; "**Header:"
+ ; string_of_elf64_header hdr_bdl f3.elf64_file_header
+ ; "**Program header table:"
+ ; string_of_elf64_program_header_table pht_bdl f3.elf64_file_program_header_table
+ ; "**Section header table:"
+ ; string_of_elf64_section_header_table' sht_bdl strtab f3.elf64_file_section_header_table
+ ; "**Bits and bobs (unused junk space):"
+ ; string_of_list
+ (instance_Show_Show_tup2_dict instance_Show_Show_Num_natural_dict
+ instance_Show_Show_Byte_sequence_byte_sequence_dict) f3.elf64_file_bits_and_bobs
+ ]
+ ))
+
+(** [flag_is_set flag v] checks whether flag [flag] is set in [v].
+ * TODO: move elsewhere. Check whether this is still being used.
+ *)
+(*val flag_is_set : natural -> natural -> bool*)
+let flag_is_set flag v:bool=
+(
+ (* HACK: convert to elf64_xword first. Flags never live
+ * in objects bigger than 64 bits. *)Uint64.logand
+ (Uint64.of_string (Nat_big_num.to_string v))
+ (Uint64.of_string (Nat_big_num.to_string flag))
+ = (Uint64.of_string (Nat_big_num.to_string flag)))