package bap-std
Table.
Tables are used to partition memory region into a set of non-intersecting areas. Each area is associated with arbitrary value of type 'a
bound to the type of the table.
All operations over tables are purely applicative, i.e. there is no observable side-effects. Although, they employ some kind of caching underneath the hood, so that they perform better if they're build once and used many times.
Tables can be also linked. For example, if you have two tables mapping the same memory region to a different sets of values, you can create a mapping from one set of values to another. See link
function for mode details.
type 'a t = 'a table
val sexp_of_t :
('a -> Ppx_sexp_conv_lib.Sexp.t) ->
'a t ->
Ppx_sexp_conv_lib.Sexp.t
val empty : 'a t
creates an empty table
add table mem v
returns a new table with added mapping from a mem region mem
to a data value v
returns a new table with all mappings from the mem region mem
removed
val change :
'a t ->
mem ->
f:
((mem * 'a) seq ->
[ `rebind of mem * 'a | `update of (mem * 'a) -> 'a | `remove | `ignore ]) ->
'a t
change tab mem ~f
function f
is applied to a set of all memory regions that intersects with mem
. If function f
evaluates to `remap (new_mem,y)
then all memory regions that have had intersections with mem
will be removed from the new map and memory region new_mem
will be mapped to y
. If f
evaluates to `remove
, then the regions will be removed, and nothing will be added. If it evaluates to `skip
then the table will be returned unchanged. Intersections are passed sorted in an ascending order.
val length : 'a t -> int
length table
returns a number of entries in the table
find_addr tab addr
finds a memory region that contains a specified addr
intersections table mem
returns all mappings in a table
that have intersections with mem
fold_intersections table mem
folds over all regions intersecting with mem
has_intersections tab mem
is true iff some portion of mem
is is already mapped in tab
.
Table relations
val one : ('a, 'a) r
1..1
val maybe_one : ('a, 'a option) r
0..1
link relation t t1 t2
takes two tables and returns a mapping from elements of one table to elements of other table.
Parameter t
specifies a hashable
typeclass of the type 'a
. If type 'a
implements Hashable
interface, then you can obtain it with hashable
function, e.g. Int.hashable
with return the appropriate type class. If 'a
doesn't implement Hashable
, then it can be implemented manually.
Relation specifies the multiplicity of the relation between entities from table t1
to entities from table t2
, and is summarized below:
one_to_many
means that a particular region from tablet1
can span several memory regions from tablet2
. Example: segments to symbols relation.
one_to_one
means that for each value of type'a
there is exactly one value of type'b
. This relation should be used with caution, since it is quantified over _all_ values of type'a
. Indeed, it should be used only for cases, when it can be guaranteed, that it is impossible to create such value of type'b
, that has no correspondence in tablet2
. Otherwise,one_to_maybe_one
relation should be used. Example: llvm machine code to assembly string relation.
one_to_maybe_one
means that for each value in tablet1
there exists at most one value in tablet2
. Example: function to symbol relation.
Examples
let mc_of_insn = link one_to:one Insn.hashable insns mcs
let syms_of_sec = link one_to:many Sec.hashable secs syms
rev_map arity t tab
creates a reverse mapping from values of typeclass t
stored in table tab
to memory regions.
Note. not every mapping is reversible, for example, trying to obtain a reverse of surjective mapping as a one-to-one mapping will result in an error. But surjective mappings can be reversed using ~one_to:many
mapping. A particular example of surjective mapping is symbol
tables, in a case when functions can occupy several non-contiguous regions of memory.
For example, to create a mapping from a function symbol to sequence of memory regions with it code:
rev_map one_to:many Sym.hashable tab
Iterators
This section provides a common set of iterators. Note: name iterator is used in a functional meaning, i.e., an iterator is a function that takes a data structure and another function, and applies it to all elements in some manner.
All iterators share some common part of interface that was lifted to a 'a ranged
type. When you see
('a t -> f:('a -> bool) -> bool) ranged
just mentally substitute it with:
?start -> ?until -> 'a t -> f:('a -> bool) -> bool
.
In other words 'f ranged
just prepends ?start -> ?until ->
to function with type 'f
(do not forget that 'f
can be an arrow type).
start
and until
parameters narrows iteration to some subset of table. If they are unspecified then iteration would be performed on all table entries in an ascending order of addresses. If they are specified, then if start <= until
, then iteration will be performed in the same order but on a specified subset. In the case, when start > until
, iteration will be performed in a decreasing order.
exists ~start ~until ~f table
checks if at least one element of table
satisfies the predicate f
.
for_all ~start ~until ~f table
checks if all elements of table
satisfies the predicate f
.
existsi ~start ~until ~f table
is like exists
, but also passes the memory as an argument.
for_alli ~start ~until ~f table
is like for_all
, but also passes the memory as an argument.
count ~start ~until ~f table
returns the number of elements table
that satisfy the predicate p
find_if ~start ~until ~f table
returns the first element of table
that satisfies the predicate p
or None if no elements satisfied
find_map ~start ~until ~f table
returns the first evaluation of f
that returns Some
or None if f
always returns None
fold ~start ~until ~init ~f table
returns a fold over table
in form f elt_n ( ... (f elt_2 (f (elt_1 acc))) ... )
iter ~start ~until ~f table
applies function f
in turn to elements of table
find_mapi ~start ~until ~f table
is like find_map
, but also passes the memory as an argument.
foldi ~start ~until ~f table
is like fold
, but also passes the memory as an argument.
ieri ~start ~until ~f table
is like iter
, but also passes the memory as an argument.
map ~start ~until ~f table
applies f
to elements of table
and builds new table with results returned by f
mapi ~start ~until ~f table
is like map
, but also passes the memory as an argument.
filter ~start ~until ~f table
removes all mappings from table
that doesn't satisfies the predicate f
filter_map ~start ~until ~f table
return a subtable of table
containing only elements for which f
returns Some
filteri ~start ~until ~f table
is like filter
, but also passes the memory as an argument.
filter_mapi ~start ~until ~f table
is like filter_map
, but also passes the memory as an argument.
to_sequence ~start ~until table
converts the table
to a sequence of key-value pairs.
regions table
returns in an ascending order of addresses all memory regions mapped in a table
elements table
returns in an ascending order of addresses all elements mapped in a table
val pp :
(Stdlib.Format.formatter -> 'a -> unit) ->
Stdlib.Format.formatter ->
'a t ->
unit
pp printer
- creates a printer for table from value printer