123 lines
3.6 KiB
OCaml
123 lines
3.6 KiB
OCaml
(** Basic Pre-DWARF generation, only for unwinding data. Tracks only CFA,
|
|
and RA. *)
|
|
|
|
open Std
|
|
module CFG = BStd.Graphs.Ir
|
|
|
|
module BlkMap = Map.Make(BStd.Blk)
|
|
|
|
(** Add a new row (ie. register change) to a PreDwarf.reg_data table *)
|
|
let add_fde_row reg row (data: PreDwarf.reg_data) =
|
|
let prev_data = match Regs.RegMap.find_opt reg data with
|
|
| None -> []
|
|
| Some l -> l
|
|
in
|
|
let new_data = row :: prev_data in
|
|
Regs.RegMap.add reg new_data data
|
|
|
|
let fold_sub init fct_phi fct_def fct_jmp term =
|
|
(** Fold over the addresses of encountered subterms in `term`, a `sub` *)
|
|
let fold_term cls init fct cterm =
|
|
BStd.Seq.fold ~init:init ~f:fct @@ BStd.Term.enum cls cterm
|
|
in
|
|
|
|
fold_term BStd.blk_t init (fun accu -> fun blk ->
|
|
let accu_phi = fold_term BStd.phi_t accu fct_phi blk in
|
|
let accu_def = fold_term BStd.def_t accu_phi fct_def blk in
|
|
let accu_jmp = fold_term BStd.jmp_t accu_def fct_jmp blk in
|
|
accu_jmp) term
|
|
|
|
exception No_address
|
|
|
|
let get_term_addr term = match (BStd.Term.get_attr term BStd.address) with
|
|
(** Get the address of a given term *)
|
|
| None -> raise No_address
|
|
| Some addr -> addr
|
|
|
|
let extract_addr extractor term =
|
|
let examine_addr paddr cterm =
|
|
let naddr = get_term_addr cterm in extractor paddr naddr
|
|
in
|
|
let start_addr = get_term_addr term in
|
|
fold_sub start_addr examine_addr examine_addr examine_addr term
|
|
|
|
let low_addr term =
|
|
(** Find the low addr of some `BStd.term` *)
|
|
extract_addr min term
|
|
|
|
let high_addr term =
|
|
(** Find the high addr of some `BStd.term` (inclusive) *)
|
|
extract_addr max term
|
|
|
|
let addr_to_int addr =
|
|
(** Transforms an address (BStd.addr) into an int *)
|
|
try CKStd.Or_error.ok_exn @@ BStd.Word.to_int addr
|
|
with _ -> raise No_address
|
|
|
|
let fde_of_subroutine (sub: BStd.sub BStd.term): PreDwarf.fde =
|
|
PreDwarf.({
|
|
start_pc = addr_to_int @@ low_addr sub;
|
|
end_pc = addr_to_int @@ high_addr sub;
|
|
name = BStd.Term.name sub
|
|
})
|
|
|
|
let symbolic_predwarf_of_blk (blk: BStd.blk BStd.term) =
|
|
(** Analyze a block of code, and return its predwarf based on RSP, assuming
|
|
that at the beginning of the block, CFA = %rsp.
|
|
|
|
This will be then adjusted to be offseted by the actual CFA value upon
|
|
entrance in this block.
|
|
|
|
This function returns its offset by the end of its block.
|
|
*)
|
|
|
|
let fold_def accu elt =
|
|
let var = BStd.Def.lhs elt in
|
|
|
|
match Regs.X86_64.get_register var with
|
|
| None -> accu
|
|
| Some reg ->
|
|
accu (* TODO *)
|
|
in
|
|
|
|
let fold_elt accu elt = match elt with
|
|
| `Def(def) -> fold_def accu def
|
|
| _ -> accu
|
|
in
|
|
|
|
BStd.Seq.fold (BStd.Blk.elts blk)
|
|
~init:Regs.RegMap.empty
|
|
~f:fold_elt
|
|
|
|
let predwarf_of_sub
|
|
(fde:PreDwarf.fde)
|
|
(sub: BStd.sub BStd.term)
|
|
: PreDwarf.reg_data =
|
|
(** Compute the pre-dwarf data for a single subroutine/FDE *)
|
|
|
|
(* A `call` always result in %rsp pointing to the RA *)
|
|
let init_cfa =
|
|
[(PreDwarf.(fde.start_pc), Regs.(RegOffset(X86_64.rsp, 8)))] in
|
|
let init_ra =
|
|
[(PreDwarf.(fde.start_pc), Regs.(RegOffset(DwRegCFA, -8)))] in
|
|
let init_reg_data = Regs.(RegMap.(
|
|
add DwRegRA init_ra
|
|
@@ add DwRegCFA init_cfa
|
|
@@ empty
|
|
))
|
|
in
|
|
|
|
let sub_cfg = BStd.Sub.to_cfg sub in
|
|
|
|
assert false
|
|
|
|
let compute_pre_dwarf proj: PreDwarf.pre_dwarf_data =
|
|
let prog = BStd.Project.program proj in
|
|
let subroutines = BStd.Term.enum BStd.sub_t prog in
|
|
let subdwarf = BStd.Seq.fold subroutines
|
|
~init:PreDwarf.FdeMap.empty
|
|
~f:(fun accu sub ->
|
|
let fde = fde_of_subroutine sub in
|
|
let predwarf = predwarf_of_sub fde sub in
|
|
PreDwarf.FdeMap.add fde predwarf accu) in
|
|
subdwarf
|