elf_arrows/src/asm_matcher.ml

112 lines
3.3 KiB
OCaml

(** Matches lines of assembly according to their DWARF line info *)
type blockid_t = int
module BlockidMap = Map.Make(struct
type t = blockid_t
let compare = compare
end)
type asm_block_info = {
asm_bi_dwarfhead : Dwarf.line_number_header ; (* FIXME overkill to carry
around? *)
asm_bi_dwarfline : Dwarf.line_number_registers ;
asm_bi_blockid : blockid_t ;
}
(** Generates a fresh block id *)
let fresh_blockid =
let next_id = ref 0 in
fun () ->
let out = !next_id in
incr next_id ;
out
(** Gets the file path for a given file id and header data *)
let extract_file_name file_id files_list =
let file_data = List.nth files_list (file_id - 1) in
file_data.Dwarf.lnfe_path
|> List.to_seq
|> String.of_seq
(** Gets the file path for the given blk, instead of its id *)
let get_file_name blk = Dwarf.(
let file_id = blk.asm_bi_dwarfline.lnr_file
|> Z.to_int in
extract_file_name file_id blk.asm_bi_dwarfhead.lnh_file_names
)
(** Compares two block infos wrt. class equivalence *)
let asm_bi_compare blk1 blk2 =
let select_file blk = get_file_name blk in
let select_line blk = Dwarf.(blk.asm_bi_dwarfline.lnr_line) in
let select_col blk = Dwarf.(blk.asm_bi_dwarfline.lnr_column) in
match compare (select_file blk1) (select_file blk2) with
| 0 -> (match compare (select_line blk1) (select_line blk2) with
| 0 -> compare (select_col blk1) (select_col blk2)
| n -> n)
| n -> n
module BoxRootSet = Set.Make(struct
type t = asm_block_info
let compare = asm_bi_compare
end)
type matcher_state_t = {
ms_block_infos : asm_block_info BlockidMap.t ;
ms_block_classes : blockid_t BlockidMap.t ;
ms_block_roots : BoxRootSet.t;
}
let empty_state = {
ms_block_infos = BlockidMap.empty ;
ms_block_classes = BlockidMap.empty ;
ms_block_roots = BoxRootSet.empty ;
}
(** Add a new block to the state, returning the new state and the class id of
the added block *)
let add_block_bi state blockinfo =
match BoxRootSet.find_opt blockinfo state.ms_block_roots with
| None ->
{
ms_block_infos = BlockidMap.add
blockinfo.asm_bi_blockid
blockinfo
state.ms_block_infos ;
ms_block_classes = BlockidMap.add
blockinfo.asm_bi_blockid
blockinfo.asm_bi_blockid
state.ms_block_classes ;
ms_block_roots = BoxRootSet.add blockinfo state.ms_block_roots ;
}, blockinfo.asm_bi_blockid
| Some root_block ->
{ state with
ms_block_infos = BlockidMap.add
blockinfo.asm_bi_blockid
blockinfo
state.ms_block_infos ;
ms_block_classes = BlockidMap.add
blockinfo.asm_bi_blockid
root_block.asm_bi_blockid
state.ms_block_classes ;
}, root_block.asm_bi_blockid
(** Same as [add_block_bi], but takes simply a [Dwarf.line_number_registers] as
argument and generates a fresh id by itself.
WARNING! Do not mix automatically and manually generated ids.
*)
let add_block state lnh lnr =
add_block_bi state {
asm_bi_dwarfhead = lnh ;
asm_bi_dwarfline = lnr ;
asm_bi_blockid = fresh_blockid ()
}
(** Gets the class ID of a previously added blockinfo. If the blockinfo was
never added, raises Not_found. *)
let block_class state blockinfo =
BlockidMap.find blockinfo.asm_bi_blockid state.ms_block_classes