elf_arrows/src/html_renderer.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

97 lines
3.5 KiB
OCaml

(** HTML Renderer
Renders the output of computations on a given program as an HTML webpage.
*)
(** Generates a fresh unique identifier *)
let fresh_uuid =
let next = ref 0 in
fun () ->
let out = !next in
incr next ; out
(** Checks whether a submethod is relevant to show, or whether it should be
hidden by default. *)
let is_sub_relevant sub = Renderer.AnnotAsm.(
List.exists
(fun instr -> instr.instr_annot.Renderer.events <> [])
sub.sub_asm
)
(** Box `AnnotAsm.asm_info_t` as a Jingoo tvalue *)
let render_prog_box annotated_prog = Jingoo.Jg_types.(Renderer.AnnotAsm.(
let render_addr addr = (Format.sprintf "%04x" addr) in
List.map (fun render_sub ->
[
("sub_section", box_string render_sub.sub_section);
("sub_name", box_string render_sub.sub_name);
("sub_addr", box_string (Format.sprintf "%016x" render_sub.sub_addr));
("sub_uuid", box_int @@ fresh_uuid ());
("sub_relevant", box_int @@ (match is_sub_relevant render_sub with
| true -> 1
| false -> 0));
("sub_asm", List.map (fun row -> [
("instr_addr", box_string (render_addr row.instr_addr));
("instr_bytes", box_string (
Format.asprintf "%a" Asm_acquire.pp_hex_bytes row.instr_bytes
));
("instr_asm", box_string row.instr_asm);
("instr_events", (List.map (fun event ->
let typ, id, bound, data = Renderer.(match event with
| BoxStart(id, bound, data) -> "start", id, bound, data
| BoxEnd(id, bound, data) -> "end", id, bound, data
) in
[
("typ", box_string typ);
("id", box_int id);
("bound", box_string @@ render_addr bound);
("data", box_string @@ Format.sprintf "[%d] File %s, %d:%d"
data.box_class_id data.box_file data.box_line data.box_col);
("box_eq", box_int data.box_class_id);
] |> box_obj)
row.instr_annot.Renderer.events)
|> box_list);
] |> box_obj) render_sub.sub_asm
|> box_list;
)] |> box_obj
) annotated_prog
|> box_list
))
let render_progs_box annotated_progs = Jingoo.Jg_types.(
List.map (fun (prog_path, annotated_prog) ->
[
("path", box_string prog_path);
("prog", render_prog_box annotated_prog)
] |> box_obj)
annotated_progs
|> box_list
)
module IntSet = Set.Make(struct type t = int let compare = compare end)
let prog_box_classes render_data = Jingoo.Jg_types.(
List.fold_left (fun accu prog ->
List.fold_left (fun accu (Renderer.TaggedRange(_, _, box)) ->
IntSet.add box.box_class_id accu)
accu prog.Renderer.render_boxes)
IntSet.empty render_data
|> IntSet.elements
|> List.map box_int
|> box_list
)
(** [render multi_render_data] renders the given [render_data] to a string. *)
let render multi_render_data = Jingoo.(
let annotated_progs = List.map (fun render_data ->
render_data.Renderer.render_prog_path,
Renderer.render_data_to_annotated_asm render_data) multi_render_data in
let models = [
("progs", render_progs_box annotated_progs);
("box_classes", prog_box_classes multi_render_data);
] in
Jg_template.from_file "src/render_html.jingoo" ~models:models
)