Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file read_symbols_main.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213letprovides=["rooter";"symbolizer"]letdoc="
Provides functions addresses and (optionally) names from a
user specified file(s). The file format is a list of entries, where
each entry is either an address or a delimited with parentheses
tuple. The tuple must have at least two fields separated with space,
with the first field denoting the name of the function and the second
field denoting its start, e.g., $(b,(main 0xDEADBEEF)) or $(b,(main
0xDEADBEEF some other fields)). The function name can be delimited
with double quotes, which is useful if it contains or can contain
whitespaces or special characters. Both kinds of entries can occur in
the same file. The nameless entries will be registered only as function
starts in the knowledge base. And named entries will be both
registered as function starts and as named labels.
If the same name occurs in several entries with different addresses
then the minimal address is chosen as the starting address. If the same
address occurs in entries with different names then a warning is
reported and inconsistent names and addresses are ignored.
If more than one file is specified then the information will be provided
only for units (binaries) that has paths that match with the file
names. In matching only basenames are compared, i.e., directory
names and extensions (if present) are removed. If the file itself is a
directory, then it is expanded to its context. If more than one file
matches with the unit name then all files will be used.
To enable the same behavior when only one file is present, use the
$(b,--read-symbols-when-matches) flag. This flag also accepts an
optional argument that denotes the name of the unit (binary). If the
argument is provided then the information from the file will be
provided only for units with names that match the specified
argument. The same rules of matching are applied (i.e., basenames
without extension). When the flag is used with an argument and more
than one files are provided, then both the unit names and the names
of the files with function information shall match.
When the $(b,--read-symbols-when-matches) flag is not set or only file
is provided, then the information from this file will be promised as a
rule in the knowledge base for each unit (binary).
# EXAMPLES
The input that denotes only function starts:
```
;; use semicolon to denote comments
;; file mv.scm
0xf00 0xba1
0xDEADBEEF
;; end of file
```
The input that denotes both function names and starts:
```
;; file ls.scm
(main 0x4000100)
(foo 0x400200 0x400300) ; anything past the second element is ignored
0x400500 0x400600 0x400700
0x400700 ; any whitespace works as a separator
(bar 0x400900)
;; end of file
```
Passing the files to bap, with a single file
```
bap /bin/mv --read-symbols-from=mv.scm
```
For two files at once,
```
bap compare /bin/{mv,ls} --read-symbols-from={mv,ls}.scm
```
For one file, but use symbols only if the match the filename
of the binary,
```
bap \\$binary --read-symbols-from=mv.scm --read-symbols-when-matches
```
"openCore_kernelopenBap_mainopenBap_core_theoryopenKB.SyntaxincludeBap_main.Loggers()letanonymous_prefix="__anonymous_sub%"letis_anonymous=String.is_prefix~prefix:anonymous_prefixletparse_entry=function|Sexp.List(Atomname::Atomaddr::_)->name,Bitvec.of_stringaddr|Sexp.Atomaddr->sprintf"%s%s"anonymous_prefixaddr,Bitvec.of_stringaddr|_->invalid_arg"failed to read symbols, expects (<name> <addr> ...)"letempty=Bap_relation.emptyBitvec.compareString.compareletbuild_relationrels=List.fold~f:(funrel(name,start)->Bap_relation.addrelstartname)~init:relsletread_relationsrelsfile=Sexp.load_sexps_conv_exnfileparse_entry|>build_relationrelsletbuild_functionsrelation=letfunctions=Hashtbl.create(modulestructincludeBitvecletsexp_of_tx=Sexp.Atom(Bitvec.to_stringx)end)inBap_relation.matchingrelation()~saturated:(funaddrname()->Hashtbl.add_exnfunctionsaddrname)~unmatched:(funproblem()->matchproblemwith|Non_injective_bwd(names,addr)->error"skipping names (%s) that has the same address %a"(String.concat~sep:", "names)Bitvec.ppaddr|Non_injective_fwd(addrs,name)->matchList.min_eltaddrs~compare:Bitvec.comparewith|None->assertfalse|Someaddr->Hashtbl.setfunctionsaddrname);functionsletchop_suffixp=tryFilename.chop_extensionpwith_->pletnormalizep=chop_suffix@@Filename.basenamepletname_matchesp1p2=String.equal(normalizep1)(normalizep2)letdata=KB.Class.propertyTheory.Unit.cls"read-symbols-data"~package:"bap"@@KB.Domain.optional"functions"~equal:(Hashtbl.equalString.equal)letreaddirpath=Sys.readdirpath|>Array.to_list|>List.map~f:(Filename.concatpath)letcollectpathfilesfilter=letalways_matches=matchfiles,filterwith|[_],None->true|_->falseinletmatchesfile=always_matches||name_matchesfilepath&&matchfilterwith|Some(Someother)->name_matchesotherpath|_->trueinletpaths=List.concat_mapfiles~f:(funfile->ifSys.file_existsfilethenifSys.is_directoryfilethenreaddirpathelse[file]else[])|>List.filter~f:matchesinList.foldpaths~init:empty~f:read_relations|>build_functionsletprovide_datafilesmatches=KB.promisedata@@fununit->KB.collectTheory.Unit.pathunit>>|?funpath->Some(collectpathfilesmatches)letagent=letreliability=KB.Agent.authorativeinKB.Agent.register~package:"bap"~reliability"user-symbolizer"~desc:"reads symbols from the user provided file"letget_entrylabel=KB.collectTheory.Label.addrlabel>>=?funaddr->KB.collectTheory.Label.unitlabel>>=?fununit->KB.collectdataunit>>|?fundata->Hashtbl.finddataaddrletprovide_starts()=KB.promiseTheory.Label.is_subroutine@@funlabel->get_entrylabel>>|?fun_->Sometrueletprovide_names()=KB.proposeagentTheory.Label.possible_name@@funlabel->get_entrylabel>>|?funname->Option.some_if(not(is_anonymousname))nameletfiles=Extension.Configuration.parametersExtension.Type.(liststring)"from"letenable_matches=Extension.Configuration.parameter~as_flag:(SomeNone)Extension.Type.(some(somestring))"when-matches"let()=Extension.declare~doc~provides@@functxt->letopenExtension.SyntaxinmatchList.concat(ctxt-->files)with|[]->Ok()|files->provide_datafiles(ctxt-->enable_matches);provide_starts();provide_names();Ok()