123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844(*Generated by Lem from memory_image.lem.*)openLem_basic_classesopenLem_functionopenLem_stringopenLem_tupleopenLem_boolopenLem_listopenLem_sortingopenLem_map(*import Map_extra*)openLem_setopenLem_set_extraopenMultimapopenLem_numopenLem_maybeopenLem_assert_extraopenShowopenByte_patternopenByte_sequenceopenElf_fileopenElf_headeropenElf_interpreted_segmentopenElf_interpreted_sectionopenElf_program_header_tableopenElf_section_header_tableopenElf_symbol_tableopenElf_types_native_uintopenElf_relocationopenEndiannessopenMissing_pervasives(* Now we can define memory images *)(* An element might have an address/offset, and it has some contents. *)typeelement={startpos:Nat_big_num.numoption;length1:Nat_big_num.numoption;contents:byte_pattern}(* HMM -- ideally I want to fold these into the memory image notion
* and the startpos thingy. *)typeallocated_symbols_map=(string,(Nat_big_num.num*Nat_big_num.num))Pmap.map(* start, length *)(* Instead of modelling address calculations (in linker scripts) like so:
type address_expr = natural -> allocated_symbols_map -> natural
( pos -> environment -> result address )
... we model it as expressions in terms of CursorPosition. HMM.
*)typeexpr_operand=Varofstring|CursorPosition(* only valid in certain expressions... HMM *)|ConstantofNat_big_num.num|UnOpof(expr_unary_operation*expr_operand)|BinOpof(expr_binary_operation*expr_operand*expr_operand)andexpr_unary_operation=Negofexpr_operand|BitwiseInverseofexpr_operandandexpr_binary_operation=Addof(expr_operand*expr_operand)|Subof(expr_operand*expr_operand)|BitwiseAndof(expr_operand*expr_operand)|BitwiseOrof(expr_operand*expr_operand)typeexpr_binary_relation=Lt|Lte|Gt|Gte|Eq|Neqtypeexpr=False|True|Notofexpr|Andof(expr*expr)|Orof(expr*expr)|BinRelof(expr_binary_relation*expr_operand)(* LH operand is the expr's value *)(*
val cond_expr : expr -> expr -> expr -> expr
let cond_expr expr1 expr2 expr3 = (Or((And(expr1, expr2)), (And((Not(expr1)), expr3))))
*)(* Memory image elements all have identities. For convenience
* we make the identities strings. The string contents are arbitrary,
* and only their equality is relevant, but choosing friendly names
* like "ELF header" is good practice.*)typememory_image=(string,element)Pmap.maptyperange=Nat_big_num.num*Nat_big_num.num(* start, length *)typeelement_range=string*range(* An "element" of an ELF image, in the linking phase, is either a section,
* the ELF header, the section header table or the program header table.
*
* PROBLEM: We'd like to use section names as the identifiers
* for those elements that are sections.
* but we can't, because they are not guaranteed to be unique.
*
* SOLUTION: Names that are unique in the file are used as keys.
* If not unique, the sections are treated as anonymous and given
* gensym'd string ids (FIXME: implement this).
*)(* Currently, our elements have unique names, which are strings.
* We *don't* want to encode any meaning onto these strings.
* All meaning should be encoded into labelled ranges.
* We want to be able to look up
*
* - elements
* - ranges within elements
*
* ... by their *labels* -- or sometimes just *part* of their labels.
*)(* ELF file features with which we can label ranges of the memory image. *)typeelf_file_feature=ElfHeaderofelf64_header|ElfSectionHeaderTableofelf64_section_header_table(* do we want to expand these? *)|ElfProgramHeaderTableofelf64_program_header_table|ElfSectionof(Nat_big_num.num*elf64_interpreted_section)(* SHT idx *)|ElfSegmentof(Nat_big_num.num*elf64_interpreted_segment)(* PHT idx *)typesymbol_definition={def_symname:string;def_syment:elf64_symbol_table_entry(* definition's symtab entry *);def_sym_scn:Nat_big_num.num(* symtab section index, to disamiguate dynsym *);def_sym_idx:Nat_big_num.num(* index of symbol into the symtab *);def_linkable_idx:Nat_big_num.num(* used to propagate origin linkable information to linked image *)}letsymDefComparex1x2:int=(quintupleComparecompareelf64_symbol_table_entry_compareNat_big_num.compareNat_big_num.compareNat_big_num.compare(x1.def_symname,x1.def_syment,x1.def_sym_scn,x1.def_sym_idx,x1.def_linkable_idx)(x2.def_symname,x2.def_syment,x2.def_sym_scn,x2.def_sym_idx,x2.def_linkable_idx))letinstance_Basic_classes_Ord_Memory_image_symbol_definition_dict:(symbol_definition)ord_class=({compare_method=symDefCompare;isLess_method=(funf1->(funf2->(Lem.orderingEqual(symDefComparef1f2)(-1))));isLessEqual_method=(funf1->(funf2->Pset.mem(symDefComparef1f2)(Pset.from_listcompare[(-1);0])));isGreater_method=(funf1->(funf2->(Lem.orderingEqual(symDefComparef1f2)1)));isGreaterEqual_method=(funf1->(funf2->Pset.mem(symDefComparef1f2)(Pset.from_listcompare[1;0])))})typesymbol_reference={ref_symname:string(* symbol name *);ref_syment:elf64_symbol_table_entry(* likely-undefined (referencing) symbol *);ref_sym_scn:Nat_big_num.num(* symtab section idx *);ref_sym_idx:Nat_big_num.num(* index into symbol table *)}letsymRefComparex1x2:int=(quadrupleComparecompareelf64_symbol_table_entry_compareNat_big_num.compareNat_big_num.compare(x1.ref_symname,x1.ref_syment,x1.ref_sym_scn,x1.ref_sym_idx)(x2.ref_symname,x2.ref_syment,x2.ref_sym_scn,x2.ref_sym_idx))letinstance_Basic_classes_Ord_Memory_image_symbol_reference_dict:(symbol_reference)ord_class=({compare_method=symRefCompare;isLess_method=(funf1->(funf2->(Lem.orderingEqual(symRefComparef1f2)(-1))));isLessEqual_method=(funf1->(funf2->Pset.mem(symRefComparef1f2)(Pset.from_listcompare[(-1);0])));isGreater_method=(funf1->(funf2->(Lem.orderingEqual(symRefComparef1f2)1)));isGreaterEqual_method=(funf1->(funf2->Pset.mem(symRefComparef1f2)(Pset.from_listcompare[1;0])))})typereloc_site={ref_relent:elf64_relocation_a;ref_rel_scn:Nat_big_num.num(* the relocation section idx *);ref_rel_idx:Nat_big_num.num(* the index of the relocation rec *);ref_src_scn:Nat_big_num.num(* the section *from which* the reference logically comes *)}letrelocSiteComparex1x2:int=(quadrupleCompareelf64_relocation_a_compareNat_big_num.compareNat_big_num.compareNat_big_num.compare(x1.ref_relent,x1.ref_rel_scn,x1.ref_rel_idx,x1.ref_src_scn)(x2.ref_relent,x2.ref_rel_scn,x2.ref_rel_idx,x2.ref_src_scn))letinstance_Basic_classes_Ord_Memory_image_reloc_site_dict:(reloc_site)ord_class=({compare_method=relocSiteCompare;isLess_method=(funf1->(funf2->(Lem.orderingEqual(relocSiteComparef1f2)(-1))));isLessEqual_method=(funf1->(funf2->Pset.mem(relocSiteComparef1f2)(Pset.from_listcompare[(-1);0])));isGreater_method=(funf1->(funf2->(Lem.orderingEqual(relocSiteComparef1f2)1)));isGreaterEqual_method=(funf1->(funf2->Pset.mem(relocSiteComparef1f2)(Pset.from_listcompare[1;0])))})typereloc_decision=LeaveReloc|ApplyReloc|ChangeRelocToof(Nat_big_num.num*symbol_reference*reloc_site)(* | MakePIC -- is now a kind of ChangeRelocTo *)letrelocDecisionComparex1x2:int=((match(x1,x2)with|(LeaveReloc,LeaveReloc)->0|(LeaveReloc,_)->(-1)|(ApplyReloc,ApplyReloc)->0|(ApplyReloc,ChangeRelocTo_)->(-1)|(ApplyReloc,LeaveReloc)->1|(ChangeRelocTot1,ChangeRelocTot2)->(tripleCompareNat_big_num.comparesymRefComparerelocSiteComparet1t2)|(ChangeRelocTo_,_)->1))letinstance_Basic_classes_Ord_Memory_image_reloc_decision_dict:(reloc_decision)ord_class=({compare_method=relocDecisionCompare;isLess_method=(funf1->(funf2->(Lem.orderingEqual(relocDecisionComparef1f2)(-1))));isLessEqual_method=(funf1->(funf2->Pset.mem(relocDecisionComparef1f2)(Pset.from_listcompare[(-1);0])));isGreater_method=(funf1->(funf2->(Lem.orderingEqual(relocDecisionComparef1f2)1)));isGreaterEqual_method=(funf1->(funf2->Pset.mem(relocDecisionComparef1f2)(Pset.from_listcompare[1;0])))})typesymbol_reference_and_reloc_site={ref:symbol_reference;maybe_reloc:reloc_siteoption;maybe_def_bound_to:(reloc_decision*symbol_definitionoption)option}letsymRefAndRelocSiteComparex1x2:int=(tripleComparesymRefCompare(maybeComparerelocSiteCompare)(maybeCompare(pairComparerelocDecisionCompare(maybeComparesymDefCompare)))(x1.ref,x1.maybe_reloc,x1.maybe_def_bound_to)(x2.ref,x2.maybe_reloc,x2.maybe_def_bound_to))letinstance_Basic_classes_Ord_Memory_image_symbol_reference_and_reloc_site_dict:(symbol_reference_and_reloc_site)ord_class=({compare_method=symRefAndRelocSiteCompare;isLess_method=(funf1->(funf2->(Lem.orderingEqual(symRefAndRelocSiteComparef1f2)(-1))));isLessEqual_method=(funf1->(funf2->Pset.mem(symRefAndRelocSiteComparef1f2)(Pset.from_listcompare[(-1);0])));isGreater_method=(funf1->(funf2->(Lem.orderingEqual(symRefAndRelocSiteComparef1f2)1)));isGreaterEqual_method=(funf1->(funf2->Pset.mem(symRefAndRelocSiteComparef1f2)(Pset.from_listcompare[1;0])))})(* We can also annotate arbitrary ranges of bytes within an element
* with arbitrary metadata.
*
* Ideally we want to data-abstract this a bit. But it's hard to do
* so without baking in ELF-specific and/or (moreover) per-ABI concepts,
* like PLTs and GOTs. Ideally we would use something like polymorphic
* variants here. For now, this has to be the union of all the concepts
* that we find in the various ABIs we care about. To avoid ELFy things
* creeping in, we parameterise by 'a, and instantiate the 'a with the
* relevant ELFy thing when we use it. OH, but then 'a is different for
* every distinct ELF thing, which is no good. Can we define a mapping
* from an umbrella "ELF" type to the relevant types in each case? *)type'abifeaturerange_tag=(* forall 'abifeature . *)ImageBase|EntryPoint|SymbolDefofsymbol_definition|SymbolRefofsymbol_reference_and_reloc_site|FileFeatureofelf_file_feature(* file feature other than symdef and reloc *)|AbiFeatureof'abifeaturetype'abifeatureannotated_memory_image={elements:memory_image;by_range:((element_rangeoption)*('abifeaturerange_tag))Pset.set;by_tag:(('abifeaturerange_tag),(element_rangeoption))multimap}(*val get_empty_memory_image : forall 'abifeature. unit -> annotated_memory_image 'abifeature*)letget_empty_memory_image:unit->'abifeatureannotated_memory_image=(fun_->{elements=(Pmap.emptycompare);by_range=(Pset.empty(pairCompare(maybeCompare(pairComparecompare(pairCompareNat_big_num.compareNat_big_num.compare)))compare));by_tag=(Pset.empty(pairComparecompare(maybeCompare(pairComparecompare(pairCompareNat_big_num.compareNat_big_num.compare)))))})(* Basic ELFy and ABI-y things. *)(* "Special" sections are those that necessarily require special treatment by the
* linker. Examples include symbol tables and relocation tables. There are some
* grey areas, such as .eh_frame, debug info, and string tables. For us, the rule
* is that if we have special code to create them, i.e. that we don't rely on
* ordinary section concatenation during the linker script interpretation, they
* should be special -- it means strip_metadata_sections will remove them from
* the image, they won't be seen by the linker script, and that it's *our* job
* to reinstate them afterwards (as we do with symtab and strtab, for example). *)(* FIXME: this shouldn't really be here, but needs to be in some low-lying module;
* keeping it out of elf_* for now to avoid duplication into elf64_, elf32_. *)letelf_section_is_specialsf:bool=(not(Nat_big_num.equals.elf64_section_typesht_progbits)&&(not(Nat_big_num.equals.elf64_section_typesht_nobits)&&(not(Nat_big_num.equals.elf64_section_typesht_fini_array)&¬(Nat_big_num.equals.elf64_section_typesht_init_array))))(* This record collects things that ABIs may or must define.
*
* Since we want to put all ABIs in a list and select one at run time,
* we can't maintain a type-level distinction between ABIs; we have to
* use elf_memory_image any_abi_feature. To avoid a reference cycle,
* stay polymorphic in the ABI feature type until we define specific ABIs.
* In practice we'll use only any_abi_feature, because we need to pull
* the ABI out of a list at run time.
*)typenull_abi_feature=unit(* The reloc calculation is complicated, so we split up the big function
* type into smaller ones. *)(* Q. Do we want "existing", or is it a kind of addend?
* A. We do want it -- modelling both separately is necessary,
* because we model relocations bytewise, but some arches
* do bitfield relocations (think ARM). *)typereloc_calculate_fn=Nat_big_num.num->Nat_big_num.num->Nat_big_num.num->Nat_big_num.num(* symaddr -> addend -> existing -> relocated *)type'abifeaturereloc_apply_fn='abifeature(* elf memory image: the context in which the relocation is being applied *)annotated_memory_image->(* the site address *)Nat_big_num.num->(* Typically there are two symbol table entries involved in a relocation.
* One is the reference, and is usually undefined.
* The other is the definition, and is defined (else absent, when we use 0).
* However, sometimes the reference is itself a defined symbol.
* Almost always, if so, *that* symbol *is* "the definition".
* However, copy relocs are an exception.
*
* In the case of copy relocations being fixed up by the dynamic
* linker, the dynamic linker must figure out which definition to
* copy from. This can't be as simple as "the first definition in
* link order", because *our* copy of that symbol is a definition
* (typically in bss). It could be as simple as "the first *after us*
* in link order". FIXME: find the glibc code that does this.
*
* Can we dig this stuff out of the memory image? If we pass the address
* being relocated, we can find the tags. But I don't want to pass
* the symbol address until the very end. It seems better to pass the symbol
* name, since that's the key that the dynamic linker uses to look for
* other definitions.
*
* Do we want to pass a whole symbol_reference? This has not only the
* symbol name but also syment, scn and idx. The syment is usually UND,
* but *could* be defined (and is for copy relocs). The scn and idx are
* not relevant, but it seems cleaner to pass the whole thing anyway.
*)symbol_reference_and_reloc_site->(* Should we pass a symbol_definition too? Implicitly, we pass part of it
* by passing the symaddr argument (below). I'd prefer not to depend on
* others -- relocation calculations should look like "mostly address
* arithmetic", i.e. only the weird ones do something else. *)(* How wide, in bytes, is the relocated field? this may depend on img
* and on the wider image (copy relocs), so it's returned *by* the reloc function. *)(Nat_big_num.num(* width *)*reloc_calculate_fn)(* Some kinds of relocation necessarily give us back a R_*_RELATIVE reloc.
* We don't record this explicitly. Instead, the "bool" is a flag recording whether
* the field represents an absolute address.
* Similarly, some relocations can "fail" according to their ABI manuals.
* This just means that the result can't be represented in the field width.
* We detect this when actually applying the reloc in the memory image content
* (done elsewhere). *)type'abifeaturereloc_fn=Nat_big_num.num->(bool*'abifeaturereloc_apply_fn)(*val noop_reloc_calculate : natural -> integer -> natural -> natural*)letnoop_reloc_calculatesymaddraddendexisting:Nat_big_num.num=existing(*val noop_reloc_apply : forall 'abifeature. reloc_apply_fn 'abifeature*)letnoop_reloc_applyimg2site_addrref1:Nat_big_num.num*(Nat_big_num.num->Nat_big_num.num->Nat_big_num.num->Nat_big_num.num)=((Nat_big_num.of_int0),noop_reloc_calculate)(*val noop_reloc : forall 'abifeature. natural -> (bool (* result is absolute addr *) * reloc_apply_fn 'abifeature)*)letnoop_relock:bool*('abifeatureannotated_memory_image->Nat_big_num.num->symbol_reference_and_reloc_site->Nat_big_num.num*reloc_calculate_fn)=(false,noop_reloc_apply)type'abifeatureabi=(* forall 'abifeature. *){is_valid_elf_header:elf64_header->bool(* doesn't this generalise outrageously? is_valid_elf_file? *);make_elf_header:Nat_big_num.num->Nat_big_num.num->Nat_big_num.num->Nat_big_num.num->Nat_big_num.num->Nat_big_num.num->Nat_big_num.num->elf64_header(* t entry shoff phoff phnum shnum shstrndx *);reloc:'abifeaturereloc_fn;section_is_special:elf64_interpreted_section->'abifeatureannotated_memory_image->bool;section_is_large:elf64_interpreted_section->'abifeatureannotated_memory_image->bool;maxpagesize:Nat_big_num.num;minpagesize:Nat_big_num.num;commonpagesize:Nat_big_num.num;symbol_is_generated_by_linker:string->bool(*; link_inputs_tap :
; link_output_sections_tap :
; link_output_image_tap : *);make_phdrs:Nat_big_num.num->Nat_big_num.num->Nat_big_num.num(* file type *)->'abifeatureannotated_memory_image->elf64_interpreted_sectionlist->elf64_program_header_table_entrylist;max_phnum:Nat_big_num.num;guess_entry_point:'abifeatureannotated_memory_image->Nat_big_num.numoption;pad_data:Nat_big_num.num->charlist;pad_code:Nat_big_num.num->charlist;generate_support:(string*'abifeatureannotated_memory_image)(* list (list reloc_site_resolution) -> *)list->'abifeatureannotated_memory_image;concretise_support:'abifeatureannotated_memory_image->'abifeatureannotated_memory_image;get_reloc_symaddr:symbol_definition->'abifeatureannotated_memory_image->(element_rangeoption*symbol_definition)list->reloc_siteoption->Nat_big_num.num;parse_reloc_info:Uint64_wrapper.uint64->(Nat_big_num.num(* type *)*Nat_big_num.num(* symbol *))}(*val align_up_to : natural -> natural -> natural*)letalign_up_toalignaddr:Nat_big_num.num=(letquot=(Nat_big_num.divaddralign)inifNat_big_num.equal(Nat_big_num.mulquotalign)addrthenaddrelseNat_big_num.mul(Nat_big_num.addquot((Nat_big_num.of_int1)))align)(*val round_down_to : natural -> natural -> natural*)letround_down_toalignaddr:Nat_big_num.num=(letquot=(Nat_big_num.divaddralign)inNat_big_num.mulquotalign)(*val uint32_max : natural*)letuint32_max:Nat_big_num.num=(Nat_big_num.sub_nat(Nat_big_num.pow_int((Nat_big_num.of_int2))32)((Nat_big_num.of_int1)))(*val uint64_max : natural*)letuint64_max:Nat_big_num.num=(Nat_big_num.add(Nat_big_num.sub_nat(Nat_big_num.mul(* HACK around Lem's inability to parse 18446744073709551615:
* the square of uint32_max is
* (2**32 - 1) (2**32 - 1)
* i.e. 2**64 - 2**32 - 2**32 + 1
* So
* 2**64 - 1 = uint32_max * uint32_max + 2**32 + 2**32 - 2
*)uint32_maxuint32_max)((Nat_big_num.of_int2)))(Nat_big_num.pow_int((Nat_big_num.of_int2))33))(* 18446744073709551615 *)(* i.e. 0x ffff ffff ffff ffff *)(* HMM. This still overflows int64 *)(* The 2's complement of a value, at 64-bit width *)(*val compl64 : natural -> natural*)letcompl64v:Nat_big_num.num=(Nat_big_num.add((Nat_big_num.of_int1))(Nat_big_num.bitwise_xorvuint64_max))(*val gcd : natural -> natural -> natural*)letrecgcdab:Nat_big_num.num=(ifNat_big_num.equalb((Nat_big_num.of_int0))thenaelsegcdb(Nat_big_num.modulusab))(*val lcm : natural -> natural -> natural*)letlcmab:Nat_big_num.num=(Nat_big_num.div(* let _ = errln ("lcm of " ^ (show a) ^ " and " ^ (show b) ^ "?")
in *)(Nat_big_num.mulab)(gcdab))(*val address_of_range : forall 'abifeature. element_range -> annotated_memory_image 'abifeature -> natural*)letaddress_of_rangeel_rangeimg2:Nat_big_num.num=(let(el_name,(start,len))=el_rangein(matchPmap.lookupel_nameimg2.elementswithSomeel->(matchel.startposwithSomeaddr->Nat_big_num.addaddrstart|None->failwith"address_of_range called for element with no address")|None->failwith"address_of_range called on nonexistent element"))(*val range_contains : (natural * natural) -> (natural * natural) -> bool*)letrange_contains(r1begin,r1len)(r2begin,r2len):bool=(Nat_big_num.greater_equal(* r1 is at least as big as r2 *)r2beginr1begin&&Nat_big_num.less_equal(Nat_big_num.addr2beginr2len)(Nat_big_num.addr1beginr1len))(*val range_overlaps : (natural * natural) -> (natural * natural) -> bool*)letrange_overlaps(r1begin,r1len)(r2begin,r2len):bool=((Nat_big_num.lessr1begin(Nat_big_num.addr2beginr2len)&&Nat_big_num.greater(Nat_big_num.addr1beginr1len)r2begin)||(Nat_big_num.lessr2begin(Nat_big_num.addr1beginr1len)&&Nat_big_num.greater(Nat_big_num.addr2beginr2len)r1begin))(*val is_partition : list (natural * natural) -> list (natural * natural) -> bool*)letis_partitionrsranges:bool=((* 1. each element of the first list falls entirely within some element
* from the second list. *)letr_is_contained_by_some_range=(funr->List.fold_left(||)false(Lem_list.map(funrange1->range_containsrange1r)ranges))inList.for_all(funr->r_is_contained_by_some_ranger)rs&&(* 2. elements of the first list do not overlap *)List.for_all(funr->List.for_all(funr2->((Lem.pair_equalNat_big_num.equalNat_big_num.equalr(* should be "=="? *)r2))||(not(range_overlapsrr2)))rs)rs)(*val nat_range : natural -> natural -> list natural*)letrecnat_rangebaselen:(Nat_big_num.num)list=(if(Nat_big_num.equallen((Nat_big_num.of_int0)))then([])else(base::(nat_range(Nat_big_num.addbase((Nat_big_num.of_int1)))(Nat_big_num.sub_natlen((Nat_big_num.of_int1))))))(* Expand a sorted list of ranges into a list of bool, where the list contains
* true if its index is included in one or more ranges, else false. *)(*val expand_sorted_ranges : list (natural * natural) -> natural -> list bool -> list bool*)letrecexpand_sorted_rangessorted_rangesmin_lengthaccum:(bool)list=((matchsorted_rangeswith[]->List.rev_append(List.revaccum)(letpad_length=(Nat_big_num.max((Nat_big_num.of_int0))(Nat_big_num.sub_natmin_length(Missing_pervasives.lengthaccum)))in(* let _ = Missing_pervasives.errln (
"padding ranges cares list with " ^ (show pad_length) ^
" cares (accumulated " ^ (show (Missing_pervasives.length accum)) ^
", min length " ^ (show min_length) ^ ")")
in *)Missing_pervasives.replicate0pad_lengthtrue)|(base,len)::more->(* pad the accum so that it reaches up to base *)letup_to_base=(Missing_pervasives.replicate0(Nat_big_num.sub_natbase(Missing_pervasives.lengthaccum))true)inletup_to_end_of_range=(List.rev_append(List.revup_to_base)(Missing_pervasives.replicate0lenfalse))inexpand_sorted_rangesmoremin_length(List.rev_append(List.revaccum)up_to_end_of_range)))(*val expand_unsorted_ranges : list (natural * natural) -> natural -> list bool -> list bool*)letrecexpand_unsorted_rangesunsorted_rangesmin_lengthaccum:(bool)list=(expand_sorted_ranges(insertSortBy(fun(base1,len1)->(fun(base2,len2)->Nat_big_num.lessbase1base2))unsorted_ranges)min_lengthaccum)letswap_pairsdict_Basic_classes_SetType_adict_Basic_classes_SetType_bs:('a*'b)Pset.set=(letx2=(Pset.from_list(pairComparedict_Basic_classes_SetType_a.setElemCompare_methoddict_Basic_classes_SetType_b.setElemCompare_method)[])inPset.fold(fun(k,v)x2->iftruethenPset.add(v,k)x2elsex2)sx2)letby_range_from_by_tagdict_Basic_classes_SetType_adict_Basic_classes_SetType_b:('a*'b)Pset.set->('b*'a)Pset.set=(swap_pairsdict_Basic_classes_SetType_bdict_Basic_classes_SetType_a)letby_tag_from_by_rangedict_Basic_classes_SetType_adict_Basic_classes_SetType_b:('a*'b)Pset.set->('b*'a)Pset.set=(swap_pairsdict_Basic_classes_SetType_bdict_Basic_classes_SetType_a)(*val filter_elements : forall 'abifeature. ((string * element) -> bool) ->
annotated_memory_image 'abifeature -> annotated_memory_image 'abifeature*)letfilter_elementspredimg2:'abifeatureannotated_memory_image=(letnew_elements=(Lem_map.fromList(instance_Map_MapKeyType_var_dictinstance_Basic_classes_SetType_var_dict)(letx2=([])inList.fold_right(fun(n,r)x2->ifletresult=(pred(n,r))inifnotresultthen(*let _ = Missing_pervasives.outln ("Discarding element named " ^ n) in*)resultelseresultthen(n,r)::x2elsex2)(Pset.elements((Pmap.bindings(pairComparecomparecompare)img2.elements)))x2))inletnew_by_range=(Pset.filter(fun(maybe_range,tag)->(matchmaybe_rangewithNone->true|Some(el_name,el_range)->Pset.memel_name(Pmap.domainnew_elements)))img2.by_range)inletnew_by_tag=(letx2=(Pset.from_list(pairComparecompare(maybeCompare(pairComparecompare(pairCompareNat_big_num.compareNat_big_num.compare))))[])inPset.fold(fun(k,v)x2->iftruethenPset.add(v,k)x2elsex2)new_by_rangex2)in{elements=new_elements;by_range=new_by_range;by_tag=new_by_tag})(*val tag_image : forall 'abifeature. range_tag 'abifeature -> string -> natural -> natural -> annotated_memory_image 'abifeature
-> annotated_memory_image 'abifeature*)lettag_imagetel_nameel_offsettag_lenimg2:'abifeatureannotated_memory_image=(let(k,v)=(Some(el_name,(el_offset,tag_len)),t)inletnew_by_range=(Pset.add(k,v)img2.by_range)inletnew_by_tag=(Pset.add(v,k)img2.by_tag)in{elements=(img2.elements);by_range=new_by_range;by_tag=new_by_tag})(*val address_to_element_and_offset : forall 'abifeature. natural -> annotated_memory_image 'abifeature -> maybe (string * natural)*)letaddress_to_element_and_offsetquery_addrimg2:(string*Nat_big_num.num)option=((* Find the element with the highest address <= addr.
* What about zero-length elements?
* Break ties on the bigger size. *)let(maybe_highest_le:(Nat_big_num.num*string*element)option)=(List.fold_left(funmaybe_current_max_le->(fun(el_name,el_rec)->(*let _ = errln ("Saw element named `" ^ el_name ^ " with startpos " ^ (
(match el_rec.startpos with Just addr -> ("0x" ^ (hex_string_of_natural addr)) | Nothing -> "(none)" end)
^ " and length " ^
(match el_rec.length with Just len -> ("0x" ^ (hex_string_of_natural len)) | Nothing -> "(none)" end)
))
in*)(match(maybe_current_max_le,el_rec.startpos)with(None,None)->None|(None,Somethis_element_pos)->ifNat_big_num.less_equalthis_element_posquery_addrthenSome(this_element_pos,el_name,el_rec)elseNone|(Some(cur_max_le,cur_el_name,cur_el_rec),None)->maybe_current_max_le|(Some(cur_max_le,cur_el_name,cur_el_rec),Somethis_element_pos)->ifNat_big_num.less_equalthis_element_posquery_addr&&(Nat_big_num.greaterthis_element_poscur_max_le||(Nat_big_num.equalthis_element_poscur_max_le&&((Lem.option_equalNat_big_num.equalcur_el_rec.length1(Some((Nat_big_num.of_int0)))))))thenSome(this_element_pos,el_name,el_rec)elsemaybe_current_max_le)))None(Pmap.bindings_listimg2.elements))in(matchmaybe_highest_lewithSome(el_def_startpos,el_name,el_rec)->(* final sanity check: is the length definite, and if so, does the
* element span far enough? *)(matchel_rec.length1withSomel->ifNat_big_num.greater_equal(Nat_big_num.addel_def_startposl)query_addrthenSome(el_name,Nat_big_num.sub_natquery_addrel_def_startpos)else(*let _ = errln ("Discounting " ^ el_name ^ " because length is too short") in*)None|None->(*let _ = errln ("Gave up because element has unknown length") in*)None)|None->(* no elements with a low enough assigned address, so nothing *)(*let _ = errln ("Found no elements with low enough address") in*)None))(*val element_and_offset_to_address : forall 'abifeature. (string * natural) -> annotated_memory_image 'abifeature -> maybe natural*)letelement_and_offset_to_address(el_name,el_off)img2:(Nat_big_num.num)option=((matchPmap.lookupel_nameimg2.elementswithSomeel->(matchel.startposwithSomeaddr->Some(Nat_big_num.addaddrel_off)|None->None)|None->failwith("error: nonexistent element: "^el_name)))letnull_symbol_reference:symbol_reference=({ref_symname="";ref_syment=elf64_null_symbol_table_entry;ref_sym_scn=((Nat_big_num.of_int0));ref_sym_idx=((Nat_big_num.of_int0))})letnull_elf_relocation_a:elf64_relocation_a=({elf64_ra_offset=(Uint64_wrapper.of_bigint((Nat_big_num.of_int0)));elf64_ra_info=(Uint64_wrapper.of_bigint((Nat_big_num.of_int0)));elf64_ra_addend=(Nat_big_num.to_int64((Nat_big_num.of_int0)))})letnull_symbol_reference_and_reloc_site:symbol_reference_and_reloc_site=({ref=null_symbol_reference;maybe_reloc=(Some{ref_relent=null_elf_relocation_a;ref_rel_scn=((Nat_big_num.of_int0));ref_rel_idx=((Nat_big_num.of_int0));ref_src_scn=((Nat_big_num.of_int0))});maybe_def_bound_to=None})letnull_symbol_definition:symbol_definition=({def_symname="";def_syment=elf64_null_symbol_table_entry;def_sym_scn=((Nat_big_num.of_int0));def_sym_idx=((Nat_big_num.of_int0));def_linkable_idx=((Nat_big_num.of_int0))})(*val pattern_possible_starts_in_one_byte_sequence : byte_pattern -> list byte -> natural -> list natural*)letpattern_possible_starts_in_one_byte_sequencepatternseqoffset:(Nat_big_num.num)list=((* let _ = Missing_pervasives.errs ("Looking for matches of " ^
(show (List.length pattern)) ^ "-byte pattern in " ^ (show (List.length seq)) ^ "-byte region\n")
in *)accum_pattern_possible_starts_in_one_byte_sequencepattern(Nat_big_num.to_int(byte_pattern_lengthpattern))seq(List.lengthseq)offset[])(*val compute_virtual_address_adjustment : natural -> natural -> natural -> natural*)letcompute_virtual_address_adjustmentmax_page_sizeoffsetvaddr:Nat_big_num.num=(Nat_big_num.modulus(Nat_big_num.sub_natvaddroffset)max_page_size)(*val natural_of_be_byte_list : list byte -> natural*)letnatural_of_be_byte_listbytes:Nat_big_num.num=(List.fold_left(funaccb->Nat_big_num.add(Nat_big_num.mulacc((Nat_big_num.of_int256)))(Nat_big_num.of_int(Char.codeb)))((Nat_big_num.of_int0))bytes)(*val natural_of_le_byte_list : list byte -> natural*)letnatural_of_le_byte_listbytes:Nat_big_num.num=(natural_of_be_byte_list(List.revbytes))(*val natural_of_byte_list : endianness -> list byte -> natural*)letnatural_of_byte_listendianbytes:Nat_big_num.num=((matchendianwith|Big->natural_of_be_byte_listbytes|Little->natural_of_le_byte_listbytes))(*val extract_natural_field : natural -> element -> natural -> natural*)letextract_natural_fieldwidthelement1offset:Nat_big_num.num=((* Read n bytes from the contents *)letmaybe_bytes=(take0width(drop0offsetelement1.contents))inletbytes=(Lem_list.map(funmb->(matchmbwithNone->Char.chr(Nat_big_num.to_int((Nat_big_num.of_int0)))|Somemb->mb))maybe_bytes)in(* FIXME: do we want little- or big-endian? *)natural_of_le_byte_listbytes)(*val natural_to_le_byte_list : natural -> list byte*)letrecnatural_to_le_byte_listn:(char)list=((Char.chr(Nat_big_num.to_int(Nat_big_num.modulusn((Nat_big_num.of_int256)))))::(letd=(Nat_big_num.divn((Nat_big_num.of_int256)))inifNat_big_num.equald((Nat_big_num.of_int0))then[]elsenatural_to_le_byte_list(Nat_big_num.divn((Nat_big_num.of_int256)))))(*val natural_to_be_byte_list : natural -> list byte*)letnatural_to_be_byte_listn:(char)list=(List.rev(natural_to_le_byte_listn))(*val natural_to_byte_list : endianness -> natural -> list byte*)letnatural_to_byte_listendiann:(char)list=((matchendianwith|Big->natural_to_be_byte_listn|Little->natural_to_le_byte_listn))(*val natural_to_le_byte_list_padded_to : natural -> natural -> list byte*)letrecnatural_to_le_byte_list_padded_towidthn:(char)list=(letbytes=(natural_to_le_byte_listn)inList.rev_append(List.revbytes)(replicate0(Nat_big_num.sub_natwidth(lengthbytes))(Char.chr(Nat_big_num.to_int((Nat_big_num.of_int0))))))(*val natural_to_be_byte_list_padded_to : natural -> natural -> list byte*)letnatural_to_be_byte_list_padded_towidthn:(char)list=(List.rev(natural_to_le_byte_list_padded_towidthn))(*val natural_to_byte_list_padded_to : endianness -> natural -> natural -> list byte*)letnatural_to_byte_list_padded_toendianwidthn:(char)list=((matchendianwith|Big->natural_to_be_byte_list_padded_towidthn|Little->natural_to_le_byte_list_padded_towidthn))(*val n2i : natural -> integer*)letn2i:Nat_big_num.num->Nat_big_num.num=(funn->n)(*val i2n: integer -> natural*)leti2n:Nat_big_num.num->Nat_big_num.num=Nat_big_num.abs(*val i2n_signed : nat -> integer -> natural*)leti2n_signedwidthi:Nat_big_num.num=(ifNat_big_num.greater_equali((Nat_big_num.of_int0))thenifNat_big_num.greater_equali(Nat_big_num.pow_int((Nat_big_num.of_int2))(Nat_num.nat_monuswidth1))thenfailwith"overflow"elseNat_big_num.absielse(* We manually encode the 2's complement of the negated value *)letnegated=(Nat_big_num.abs(Nat_big_num.sub((Nat_big_num.of_int0))i))inlet(xormask:Nat_big_num.num)=(Nat_big_num.sub_nat(Nat_big_num.pow_int((Nat_big_num.of_int2))width)((Nat_big_num.of_int1)))inletcompl=(Nat_big_num.add((Nat_big_num.of_int1))(Nat_big_num.bitwise_xornegatedxormask))in(*let _ = errln ("Signed value " ^ (show i) ^ " is 2's-compl'd to 0x" ^ (hex_string_of_natural compl))
in*)compl)(*val to_le_signed_bytes : natural -> integer -> list byte*)letto_le_signed_bytesbytewidthi:(char)list=(natural_to_le_byte_list_padded_tobytewidth(i2n_signed(Nat_big_num.to_int(Nat_big_num.mul((Nat_big_num.of_int8))bytewidth))i))(*val to_le_unsigned_bytes : natural -> integer -> list byte*)letto_le_unsigned_bytesbytewidthi:(char)list=(natural_to_le_byte_list_padded_tobytewidth(Nat_big_num.absi))(*val write_natural_field : natural -> natural -> element -> natural -> element*)letwrite_natural_fieldnew_field_valuewidthelement1offset:element=(letpre_bytes=(take0offsetelement1.contents)inletpost_bytes=(drop0(Nat_big_num.addoffsetwidth)element1.contents)in(* FIXME: avoid hard-coding little-endian *)letfield_bytes=(natural_to_le_byte_listnew_field_value)inifNat_big_num.greater(lengthfield_bytes)widththenfailwith"internal error: relocation output unrepresentable"else{contents=(List.rev_append(List.rev(List.rev_append(List.rev(List.rev_append(List.revpre_bytes)(letx2=([])inList.fold_right(funbx2->iftruethenSomeb::x2elsex2)field_bytesx2)))(replicate0(Nat_big_num.sub_natwidth(lengthfield_bytes))(Some(Char.chr(Nat_big_num.to_int((Nat_big_num.of_int0))))))))post_bytes);startpos=(element1.startpos);length1=(element1.length1)})(*val read_memory_image : forall 'abifeature. annotated_memory_image 'abifeature -> natural -> natural -> maybe (list byte)*)letread_memory_imageimg2startlen:((char)list)option=(letstop=(Nat_big_num.addstartlen)inletelements1=(Pmap.bindings_listimg2.elements)inList.fold_left(funmaybe_field(_,el)->letel_start=(assert_unwrap_maybeel.startpos)in(* let el_len = assert_unwrap_maybe el.length in *)letel_len=(Nat_big_num.of_int(List.lengthel.contents))in(* TODO? *)letel_stop=(Nat_big_num.addel_startel_len)in(* Do not allow reading fields across elements *)ifNat_big_num.greater_equalstartel_start&&Nat_big_num.less_equalstopel_stopthen(* TODO: check consistency if maybe_field is not Nothing *)letoffset=(Nat_big_num.sub_natstartel_start)inletbp=(read_byte_patternel.contentsoffsetlen)inletl=(byte_pattern_to_byte_listbp)inSomelelsemaybe_field)Noneelements1)(*val read_memory_image_byte_sequence : forall 'abifeature. annotated_memory_image 'abifeature -> natural -> natural -> maybe byte_sequence*)letread_memory_image_byte_sequenceimg2startlen:(Byte_sequence_wrapper.byte_sequence)option=(letmaybe_bl=(read_memory_imageimg2startlen)inLem.option_mapbyte_sequence_of_byte_listmaybe_bl)(*val write_memory_image : forall 'abifeature. annotated_memory_image 'abifeature -> natural -> byte_pattern -> annotated_memory_image 'abifeature*)letwrite_memory_imageimg2startbp:'abifeatureannotated_memory_image=(if(listEqualBy(Lem.option_equal(=))bp[])thenimg2elseletlen=(Nat_big_num.of_int(List.lengthbp))inletstop=(Nat_big_num.addstartlen)inletelements1=(Pmap.map(funel->letel_start=(assert_unwrap_maybeel.startpos)in(* let el_len = assert_unwrap_maybe el.length in *)letel_len=(Nat_big_num.of_int(List.lengthel.contents))in(* TODO? *)letel_stop=(Nat_big_num.addel_startel_len)inletcontents1=(ifNat_big_num.greater_equalstartel_start&&Nat_big_num.lessstartel_stopthenletwrite_start=(Nat_big_num.sub_natstartel_start)inletwrite_max_len=(Nat_big_num.sub_natel_stopstart)inletwrite_bp=(Lem_list.take(Nat_big_num.to_intwrite_max_len)bp)in(* let _ = Missing_pervasives.errln (" Masking at 0x" ^ (hex_string_of_natural el_start) ^ "+0x" ^ (hex_string_of_natural write_start) ^ " max_len=0x" ^ (hex_string_of_natural write_max_len) ^ " len=0x" ^ (hex_string_of_natural (naturalFromNat (List.length write_bp)))) in *)write_byte_patternel.contentswrite_startwrite_bpelseifNat_big_num.greater_equalstopel_start&&Nat_big_num.lessstopel_stopthen(* Case el_start < start is handled above *)let_=(Lem_assert_extra.ensure(Nat_big_num.greater_equalel_startstart)"write_memory_image: internal failure")inletwrite_bp=(Lem_list.drop(Nat_big_num.to_int(Nat_big_num.sub_natel_startstart))bp)in(* let _ = Missing_pervasives.errln (" Masking at 0x" ^ (hex_string_of_natural el_start) ^ "+0 len=0x" ^ (hex_string_of_natural (naturalFromNat (List.length write_bp)))) in *)write_byte_patternel.contents((Nat_big_num.of_int0))write_bpelseel.contents)in{startpos=(Someel_start);length1=(Someel_len);contents=contents1})img2.elements)in{elements=elements1;by_range=(img2.by_range);by_tag=(img2.by_tag)})letmask_memory_imageimg2startlen:'aannotated_memory_image=(ifNat_big_num.equallen((Nat_big_num.of_int0))thenimg2elseletbp=(Lem_list.replicate(Nat_big_num.to_intlen)None)inwrite_memory_imageimg2startbp)letmemory_image_element_atimg2addr:(element)option=(letelements1=(Pmap.bindings_listimg2.elements)inletmaybe_tuple=(Lem_list.list_find_opt(fun(_,e)->letstart=(assert_unwrap_maybee.startpos)inletlen=(assert_unwrap_maybee.length1)inNat_big_num.greater_equaladdrstart&&Nat_big_num.lessaddr(Nat_big_num.addstartlen))elements1)inLem.option_map(fun(_,e)->e)maybe_tuple)