diff options
Diffstat (limited to 'src/elf_model/elf_section_header_table.lem')
| -rw-r--r-- | src/elf_model/elf_section_header_table.lem | 445 |
1 files changed, 445 insertions, 0 deletions
diff --git a/src/elf_model/elf_section_header_table.lem b/src/elf_model/elf_section_header_table.lem new file mode 100644 index 00000000..669a2dce --- /dev/null +++ b/src/elf_model/elf_section_header_table.lem @@ -0,0 +1,445 @@ +open import Basic_classes +open import Bool +open import Function +open import List +open import Maybe +open import Num +open import String + +open import Elf_types +open import Endianness +open import String_table + +open import Bitstring +open import Error +open import Missing_pervasives +open import Show + +(** Special section indices. *) + +(** [shn_undef]: marks an undefined, missing or irrelevant section reference. + *) +let shn_undef : nat = 0 +(** [shn_loreserve]: this specifies the lower bound of the range of reserved + * indices. + *) +let shn_loreserve : nat = 65280 (* 0xff00 *) +(** [shn_loproc]: start of the range reserved for processor-specific semantics. + *) +let shn_loproc : nat = 65280 (* 0xff00 *) +(** [shn_hiproc]: end of the range reserved for processor-specific semantics. + *) +let shn_hiproc : nat = 65311 (* 0xff1f *) +(** [shn_loos]: start of the range reserved for operating system-specific + * semantics. + *) +let shn_loos : nat = 65312 (* 0xff20 *) +(** [shn_hios]: end of the range reserved for operating system-specific + * semantics. + *) +let shn_hios : nat = 65343 (* 0xff3f *) +(** [shn_abs]: specifies the absolute values for the corresponding reference. + * Symbols defined relative to section number [shn_abs] have absolute values + * and are not affected by relocation. + *) +let shn_abs : nat = 65521 (* 0xfff1 *) +(** [shn_common]: symbols defined relative to this index are common symbols, + * such as unallocated C external variables. + *) +let shn_common : nat = 65522 (* 0xfff2 *) +(** [shn_xindex]: an escape value. It indicates the actual section header index + * is too large to fit in the containing field and is located in another + * location (specific to the structure where it appears). + *) +let shn_xindex : nat = 65535 (* 0xffff *) +(** [shn_hireserve]: specifies the upper-bound of reserved values. + *) +let shn_hireserve : nat = 65535 (* 0xffff *) + +val string_of_special_section_index : nat -> string +let string_of_special_section_index i = + if i = shn_undef then + "SHN_UNDEF" + else if i = shn_loreserve then + "SHN_LORESERVE" + else if i >= shn_loproc && i <= shn_hiproc then + "SHN_PROCESSOR_SPECIFIC" + else if i >= shn_loos && i <= shn_hios then + "SHN_OS_SPECIFIC" + else if i = shn_abs then + "SHN_ABS" + else if i = shn_common then + "SHN_COMMON" + else if i = shn_xindex then + "SHN_XINDEX" + else if i = shn_hireserve then + "SHN_HIRESERVE" + else + "SHN UNDEFINED" + +(** Section types. *) + +(** Marks the section header as being inactive. *) +let sht_null : nat = 0 +(** Section holds information defined by the program. *) +let sht_progbits : nat = 1 +(** The following two section types hold a symbol table. An object file may only + * have one symbol table of each of the respective types. The symtab provides + * a place for link editing, whereas the dynsym section holds a minimal set of + * dynamic linking symbols + *) +let sht_symtab : nat = 2 +let sht_dynsym : nat = 11 +(** Section holds a string table *) +let sht_strtab : nat = 3 +(** Section holds relocation entries with explicit addends. An object file may + * have multiple section of this type. + *) +let sht_rela : nat = 4 +(** Section holds a symbol hash table. An object file may only have a single + * hash table. + *) +let sht_hash : nat = 5 +(** Section holds information for dynamic linking. An object file may only have + * a single dynamic section. + *) +let sht_dynamic : nat = 6 +(** Section holds information that marks the file in some way. *) +let sht_note : nat = 7 +(** Section occupies no space in the file but otherwise resembles a progbits + * section. + *) +let sht_nobits : nat = 8 +(** Section holds relocation entries without explicit addends. An object file + * may have multiple section of this type. + *) +let sht_rel : nat = 9 +(** Section type is reserved but has an unspecified meaning. *) +let sht_shlib : nat = 10 +(** Section contains an array of pointers to initialisation functions. Each + * pointer is taken as a parameterless function with a void return type. + *) +let sht_init_array : nat = 14 +(** Section contains an array of pointers to termination functions. Each + * pointer is taken as a parameterless function with a void return type. + *) +let sht_fini_array : nat = 15 +(** Section contains an array of pointers to initialisation functions that are + * invoked before all other initialisation functions. Each + * pointer is taken as a parameterless function with a void return type. + *) +let sht_preinit_array : nat = 16 +(** Section defines a section group, i.e. a set of sections that are related and + * must be treated especially by the linker. May only appear in relocatable + * objects. + *) +let sht_group : nat = 17 +(** Section is associated with sections of type SHT_SYMTAB and is required if + * any of the section header indices referenced by that symbol table contains + * the escape value SHN_XINDEX. + * + * FIXME: Lem bug as [int] type used throughout Lem codebase, rather than + * [BigInt.t], so Lem chokes on these large constants below, hence the weird + * way in which they are written. + *) +let sht_symtab_shndx : nat = 18 +let sht_loos : nat = 3 * 1024 * 1024 * 512 (* 1610612736 (* 0x60000000 *) *) +let sht_hios : nat = (469762047 * 4) + 3 (* 1879048191 (* 0x6fffffff *) *) +let sht_loproc : nat = (469762048 * 4) (* 1879048192 (* 0x70000000 *) *) +let sht_hiproc : nat = (536870911 * 4) + 3 (* 2147483647 (* 0x7fffffff *) *) +let sht_louser : nat = (536870912 * 4) (* 2147483648 (* 0x80000000 *) *) +let sht_hiuser : nat = (603979775 * 4) + 3 (* 2415919103 (* 0x8fffffff *) *) + +val string_of_section_type : (nat -> string) -> (nat -> string) -> + (nat -> string) -> nat -> string +let string_of_section_type os proc user i = + if i = sht_null then + "SHT_NULL" + else if i = sht_progbits then + "SHT_PROGBITS" + else if i = sht_symtab then + "SHT_SYMTAB" + else if i = sht_strtab then + "SHT_STRTAB" + else if i = sht_rela then + "SHT_RELA" + else if i = sht_hash then + "SHT_HASH" + else if i = sht_dynamic then + "SHT_DYNAMIC" + else if i = sht_note then + "SHT_NOTE" + else if i = sht_nobits then + "SHT_NOBITS" + else if i = sht_rel then + "SHT_REL" + else if i = sht_shlib then + "SHT_SHLIB" + else if i = sht_dynsym then + "SHT_DYNSYM" + else if i = sht_init_array then + "SHT_INIT_ARRAY" + else if i = sht_fini_array then + "SHT_FINI_ARRAY" + else if i = sht_preinit_array then + "SHT_PREINIT_ARRAY" + else if i = sht_group then + "SHT_GROUP" + else if i = sht_symtab_shndx then + "SHT_SYMTAB_SHNDX" + else if i >= sht_loos && i <= sht_hios then + os i + else if i >= sht_loproc && i <= sht_hiproc then + proc i + else if i >= sht_louser && i <= sht_hiuser then + user i + else + "Undefined or invalid section type" + +(** Section header table entry type. *) + +(** [elf32_section_header_table_entry] is the type of entries in the section + * header table in 32-bit ELF files. Each entry in the table details a section + * in the body of the ELF file. + *) +type elf32_section_header_table_entry = + <| elf32_sh_name : elf32_word (** Name of the section *) + ; elf32_sh_type : elf32_word (** Type of the section and its semantics *) + ; elf32_sh_flags : elf32_word (** Flags associated with the section *) + ; elf32_sh_addr : elf32_addr (** Address of first byte of section in memory image *) + ; elf32_sh_offset : elf32_off (** Offset from beginning of file of first byte of section *) + ; elf32_sh_size : elf32_word (** Section size in bytes *) + ; elf32_sh_link : elf32_word (** Section header table index link *) + ; elf32_sh_info : elf32_word (** Extra information, contents depends on type of section *) + ; elf32_sh_addralign : elf32_word (** Alignment constraints for section *) + ; elf32_sh_entsize : elf32_word (** Size of each entry in table, if section is one *) + |> + +(** [elf64_section_header_table_entry] is the type of entries in the section + * header table in 64-bit ELF files. Each entry in the table details a section + * in the body of the ELF file. + *) +type elf64_section_header_table_entry = + <| elf64_sh_name : elf64_word (** Name of the section *) + ; elf64_sh_type : elf64_word (** Type of the section and its semantics *) + ; elf64_sh_flags : elf64_xword (** Flags associated with the section *) + ; elf64_sh_addr : elf64_addr (** Address of first byte of section in memory image *) + ; elf64_sh_offset : elf64_off (** Offset from beginning of file of first byte of section *) + ; elf64_sh_size : elf64_xword (** Section size in bytes *) + ; elf64_sh_link : elf64_word (** Section header table index link *) + ; elf64_sh_info : elf64_word (** Extra information, contents depends on type of section *) + ; elf64_sh_addralign : elf64_xword (** Alignment constraints for section *) + ; elf64_sh_entsize : elf64_xword (** Size of each entry in table, if section is one *) + |> + +val read_elf32_section_header_table_entry : endianness -> bitstring -> error (elf32_section_header_table_entry * bitstring) +let read_elf32_section_header_table_entry endian bs = + read_elf32_word endian bs >>= fun (sh_name, bs) -> + read_elf32_word endian bs >>= fun (sh_type, bs) -> + read_elf32_word endian bs >>= fun (sh_flags, bs) -> + read_elf32_addr endian bs >>= fun (sh_addr, bs) -> + read_elf32_off endian bs >>= fun (sh_offset, bs) -> + read_elf32_word endian bs >>= fun (sh_size, bs) -> + read_elf32_word endian bs >>= fun (sh_link, bs) -> + read_elf32_word endian bs >>= fun (sh_info, bs) -> + read_elf32_word endian bs >>= fun (sh_addralign, bs) -> + read_elf32_word endian bs >>= fun (sh_entsize, bs) -> + return (<| elf32_sh_name = sh_name; elf32_sh_type = sh_type; + elf32_sh_flags = sh_flags; elf32_sh_addr = sh_addr; + elf32_sh_offset = sh_offset; elf32_sh_size = sh_size; + elf32_sh_link = sh_link; elf32_sh_info = sh_info; + elf32_sh_addralign = sh_addralign; elf32_sh_entsize = sh_entsize |>, bs) + + +val read_elf64_section_header_table_entry : endianness -> bitstring -> error (elf64_section_header_table_entry * bitstring) +let read_elf64_section_header_table_entry endian bs = + read_elf64_word endian bs >>= fun (sh_name, bs) -> + read_elf64_word endian bs >>= fun (sh_type, bs) -> + read_elf64_xword endian bs >>= fun (sh_flags, bs) -> + read_elf64_addr endian bs >>= fun (sh_addr, bs) -> + read_elf64_off endian bs >>= fun (sh_offset, bs) -> + read_elf64_xword endian bs >>= fun (sh_size, bs) -> + read_elf64_word endian bs >>= fun (sh_link, bs) -> + read_elf64_word endian bs >>= fun (sh_info, bs) -> + read_elf64_xword endian bs >>= fun (sh_addralign, bs) -> + read_elf64_xword endian bs >>= fun (sh_entsize, bs) -> + return (<| elf64_sh_name = sh_name; elf64_sh_type = sh_type; + elf64_sh_flags = sh_flags; elf64_sh_addr = sh_addr; + elf64_sh_offset = sh_offset; elf64_sh_size = sh_size; + elf64_sh_link = sh_link; elf64_sh_info = sh_info; + elf64_sh_addralign = sh_addralign; elf64_sh_entsize = sh_entsize |>, bs) + +(** The [sht_print_bundle] type is used to tidy up other type signatures. Some of the + * top-level string_of_ functions require six or more functions passed to them, + * which quickly gets out of hand. This type is used to reduce that complexity. + * The first component of the type is an OS specific print function, the second is + * a processor specific print function. + *) +type sht_print_bundle = (nat -> string) * (nat -> string) * (nat -> string) + +val string_of_elf32_section_header_table_entry : sht_print_bundle -> elf32_section_header_table_entry -> string +let string_of_elf32_section_header_table_entry (os, proc, user) entry = + unlines [ + "\t" ^ "Name: " ^ show entry.elf32_sh_name + ; "\t" ^ "Type: " ^ string_of_section_type os proc user (nat_of_elf32_word entry.elf32_sh_type) + ; "\t" ^ "Flags: " ^ show entry.elf32_sh_flags + ; "\t" ^ "Address: " ^ show entry.elf32_sh_addr + ; "\t" ^ "Size: " ^ show entry.elf32_sh_size + ] + +val string_of_elf64_section_header_table_entry : sht_print_bundle -> elf64_section_header_table_entry -> string +let string_of_elf64_section_header_table_entry (os, proc, user) entry = + unlines [ + "\t" ^ "Name: " ^ show entry.elf64_sh_name + ; "\t" ^ "Type: " ^ string_of_section_type os proc user (nat_of_elf64_word entry.elf64_sh_type) + ; "\t" ^ "Flags: " ^ show entry.elf64_sh_flags + ; "\t" ^ "Address: " ^ show entry.elf64_sh_addr + ; "\t" ^ "Size: " ^ show entry.elf64_sh_size + ] + +val string_of_elf32_section_header_table_entry' : sht_print_bundle -> string_table -> elf32_section_header_table_entry -> string +let string_of_elf32_section_header_table_entry' (os, proc, user) stbl entry = + let name = + match get_string_at (nat_of_elf32_word entry.elf32_sh_name) stbl with + | Fail _ -> "Invalid index into string table" + | Success i -> i + end + in + unlines [ + "\t" ^ "Name: " ^ name + ; "\t" ^ "Type: " ^ string_of_section_type os proc user (nat_of_elf32_word entry.elf32_sh_type) + ; "\t" ^ "Flags: " ^ show entry.elf32_sh_flags + ; "\t" ^ "Address: " ^ show entry.elf32_sh_addr + ; "\t" ^ "Size: " ^ show entry.elf32_sh_size + ] + +val string_of_elf64_section_header_table_entry' : sht_print_bundle -> string_table -> elf64_section_header_table_entry -> string +let string_of_elf64_section_header_table_entry' (os, proc, user) stbl entry = + let name = + match get_string_at (nat_of_elf64_word entry.elf64_sh_name) stbl with + | Fail _ -> "Invalid index into string table" + | Success i -> i + end + in + unlines [ + "\t" ^ "Name: " ^ name + ; "\t" ^ "Type: " ^ string_of_section_type os proc user (nat_of_elf64_word entry.elf64_sh_type) + ; "\t" ^ "Flags: " ^ show entry.elf64_sh_flags + ; "\t" ^ "Address: " ^ show entry.elf64_sh_addr + ; "\t" ^ "Size: " ^ show entry.elf64_sh_size + ] + +let string_of_elf32_section_header_table_entry_default = + string_of_elf32_section_header_table_entry + ((const "*Default OS specific print*"), + (const "*Default processor specific print*"), + (const "*Default user specific print*")) + +instance (Show elf32_section_header_table_entry) + let show = string_of_elf32_section_header_table_entry_default +end + +let string_of_elf64_section_header_table_entry_default = + string_of_elf64_section_header_table_entry + ((const "*Default OS specific print*"), + (const "*Default processor specific print*"), + (const "*Default user specific print*")) + +instance (Show elf64_section_header_table_entry) + let show = string_of_elf64_section_header_table_entry_default +end + +(** Section header table type. *) + +(** Type [elf32_section_header_table] represents a section header table for 32-bit + * ELF files. A section header table is an array (implemented as a list, here) + * of section header table entries. + *) +type elf32_section_header_table = + list elf32_section_header_table_entry + +class (HasElf32SectionHeaderTable 'a) + val get_elf32_section_header_table : 'a -> maybe elf32_section_header_table +end + +(** Type [elf64_section_header_table] represents a section header table for 64-bit + * ELF files. A section header table is an array (implemented as a list, here) + * of section header table entries. + *) +type elf64_section_header_table = + list elf64_section_header_table_entry + +class (HasElf64SectionHeaderTable 'a) + val get_elf64_section_header_table : 'a -> maybe elf64_section_header_table +end + +let rec read_elf32_section_header_table' endian bs0 = + if length bs0 = 0 then + return [] + else + read_elf32_section_header_table_entry endian bs0 >>= fun (entry, bs1) -> + read_elf32_section_header_table' endian bs1 >>= fun tail -> + return (entry::tail) + +val read_elf32_section_header_table : nat -> endianness -> bitstring -> error (elf32_section_header_table * bitstring) +let read_elf32_section_header_table table_size endian bs0 = + let (eat, rest) = partition table_size bs0 in + read_elf32_section_header_table' endian eat >>= fun entries -> + return (entries, rest) +;; + +let rec read_elf64_section_header_table' endian bs0 = + if length bs0 = 0 then + return [] + else + read_elf64_section_header_table_entry endian bs0 >>= fun (entry, bs1) -> + read_elf64_section_header_table' endian bs1 >>= fun tail -> + return (entry::tail) + +val read_elf64_section_header_table : nat -> endianness -> bitstring -> error (elf64_section_header_table * bitstring) +let read_elf64_section_header_table table_size endian bs0 = + let (eat, rest) = partition table_size bs0 in + read_elf64_section_header_table' endian eat >>= fun entries -> + return (entries, rest) +;; + +val elf32_size_correct : elf32_section_header_table_entry -> elf32_section_header_table -> bool +let elf32_size_correct hdr tbl = + match nat_of_elf32_word hdr.elf32_sh_size with + | 0 -> true + | m -> m = List.length tbl + end +;; + +val is_valid_elf32_section_header_table : elf32_section_header_table -> bool +let is_valid_elf32_section_header_table tbl = + match tbl with + | [] -> false + | x::xs -> + nat_of_elf32_word x.elf32_sh_name = 0 && + nat_of_elf32_word x.elf32_sh_type = sht_null && + nat_of_elf32_word x.elf32_sh_flags = 0 && + nat_of_elf32_addr x.elf32_sh_addr = 0 && + nat_of_elf32_off x.elf32_sh_offset = 0 && + nat_of_elf32_word x.elf32_sh_info = 0 && + nat_of_elf32_word x.elf32_sh_addralign = 0 && + nat_of_elf32_word x.elf32_sh_entsize = 0 && + elf32_size_correct x tbl + (* XXX: more correctness criteria in time *) + end + +val string_of_elf32_section_header_table : sht_print_bundle -> elf32_section_header_table -> string +let string_of_elf32_section_header_table sht_bdl tbl = + unlines (List.map (string_of_elf32_section_header_table_entry sht_bdl) tbl) + +val string_of_elf32_section_header_table' : sht_print_bundle -> string_table -> elf32_section_header_table -> string +let string_of_elf32_section_header_table' sht_bdl stbl tbl = + unlines (List.map (string_of_elf32_section_header_table_entry' sht_bdl stbl) tbl) + +val string_of_elf64_section_header_table : sht_print_bundle -> elf64_section_header_table -> string +let string_of_elf64_section_header_table sht_bdl tbl = + unlines (List.map (string_of_elf64_section_header_table_entry sht_bdl) tbl) + +val string_of_elf64_section_header_table' : sht_print_bundle -> string_table -> elf64_section_header_table -> string +let string_of_elf64_section_header_table' sht_bdl stbl tbl = + unlines (List.map (string_of_elf64_section_header_table_entry' sht_bdl stbl) tbl)
\ No newline at end of file |
