elf_arrows/src/asm_matcher.ml
Théophile Bastian e90e51fc2a Match with file names instead of file ids
It seems possible that two runs of eg. gcc at different levels of
optimisation on the same files assigns different IDs to the same files.
To circumvent this, we use the file paths instead of file IDs.
2019-11-22 12:46:47 +01:00

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