package ocaml-probes
USDT probes for OCaml: command line tool
Install
Dune Dependency
Authors
Maintainers
Sources
ocaml-probes-v0.15.0.tar.gz
sha256=6d154b2f67b6ddd3a501c08b481f5946a02b886554f949a29e7091f6c74f5a90
doc/src/ocaml-probes.probes_lib/elf.ml.html
Source file elf.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
type section = { name : string ; addr : int64 ; offset : int64 ; size : int64 } (** Currently, arguments of probes are not used by probes_lib. Each site may have different arguments. *) type probe_info = { name : string ; semaphores : int64 array (** address of the semaphore corresponding to the probe *) ; sites : int64 array (** addresses of all the probe sites with the given name and semaphore. *) } type t = { filename : string ; pie : bool (** is this a position independent executable? *) ; probes : (string, probe_info) Hashtbl.t ; text_section : section ; data_section : section ; semaphores_section : section option (** semaphores live in ".probes" section *) } let mk_section (section : Owee_elf.section) : section = { name = section.sh_name_str ; addr = section.sh_addr ; offset = section.sh_offset ; size = section.sh_size } ;; exception Invalid_format of string let verbose = ref false let set_verbose b = verbose := b (** Depends on the compiler version. *) module Config = struct type t = { unique_semaphore_per_name : bool ; separate_semaphore_for_ocaml_handlers : bool } let versions = let tbl = Hashtbl.create 2 in Hashtbl.add tbl "ocaml" { unique_semaphore_per_name = false; separate_semaphore_for_ocaml_handlers = false }; Hashtbl.add tbl "ocaml.1" { unique_semaphore_per_name = true; separate_semaphore_for_ocaml_handlers = true }; tbl ;; let get provider = Hashtbl.find_opt versions provider end module Int64_set = Set.Make (Int64) type tmp_probe_info = { mutable semaphores : Int64_set.t ; mutable sites : Int64_set.t } let check_or_set_provider current new_provider = match !current with | None -> current := Some new_provider | Some cur_provider -> if not (String.equal cur_provider new_provider) then raise (Invalid_format (Printf.sprintf "Executable contains probe notes of different versions %s %s" cur_provider new_provider)) ;; let add (note : Owee_elf_notes.Stapsdt.t) ~acc ~provider ~filename = match Config.get note.provider with | None -> () | Some config -> check_or_set_provider provider note.provider; let semaphore = match note.semaphore with | None -> (* OCaml compiler will always generate a semaphore. This assumption slightly simplifies the code for enabling/disabling probes, and makes it slightly more efficient. *) raise (Invalid_format (Printf.sprintf "Semaphore not found for OCaml probe %s at %Lx in %s.\n" note.name note.addr filename)) | Some s -> (* The semaphore address in probe notes points to semaphore that is used by SystemTap and early versions of ocaml-probes. Newer compiler version allocates additional space immediately after the existing semaphore, i.e., at offset 2 bytes from the semaphore address, providing a separate semaphore for ocaml-probes, because these two mechnisms control different handlers. *) if config.separate_semaphore_for_ocaml_handlers then Int64.add s 2L else s in (match Hashtbl.find_opt acc note.name with | None -> let tmp_probe_info = { semaphores = Int64_set.singleton semaphore ; sites = Int64_set.singleton note.addr } in Hashtbl.add acc note.name tmp_probe_info | Some ({ semaphores; sites } as tmp_probe_info : tmp_probe_info) -> (* probe name and semaphore addresses must be the same for all probe sites associated with that name. *) if config.unique_semaphore_per_name && not (Int64_set.mem semaphore semaphores) then raise (Invalid_format (Printf.sprintf "Mismatch between probe sites in %s:\n\ adding probe %s at %Lx with semaphore at %Lx\n\ previously found at %Lx with semaphore at %Lx\n" filename note.name note.addr semaphore (Int64_set.min_elt sites) (Int64_set.min_elt semaphores))); (* args are currently ignored *) (* Here we lose the order in which notes are listed in .stapsdt notes section *) tmp_probe_info.sites <- Int64_set.add note.addr sites; tmp_probe_info.semaphores <- Int64_set.add semaphore semaphores) ;; let read_notes ~filename map sections = let acc = Hashtbl.create 13 in let provider = ref None in (try Owee_elf_notes.Stapsdt.iter map sections ~f:(add ~acc ~provider ~filename) with | Owee_elf_notes.Section_not_found _ -> (* do nothing *) ()); let n = Hashtbl.length acc in let notes = Hashtbl.create n in Hashtbl.iter (fun name { semaphores; sites } -> let new_note = { name ; sites = sites |> Int64_set.to_seq |> Array.of_seq ; semaphores = semaphores |> Int64_set.to_seq |> Array.of_seq } in Hashtbl.add notes name new_note) acc; notes ;; let create ~filename = let fd = Unix.openfile filename [ Unix.O_RDONLY ] 0 in let len = Unix.lseek fd 0 Unix.SEEK_END in let map = Bigarray.array1_of_genarray (Unix.map_file fd Bigarray.int8_unsigned Bigarray.c_layout false [| len |]) in Unix.close fd; let header, sections = Owee_elf.read_elf map in let find_section_exn name = match Owee_elf.find_section sections name with | None -> raise (Invalid_format (Printf.sprintf "Cannot find ELF section %s in %s\n" name filename)) | Some s -> mk_section s in let is_pie = function | 2 (* ET_EXEC 2 Executable file *) -> false | 3 (* ET_DYN 3 Shared object file *) -> true | e_type -> raise (Invalid_format (Printf.sprintf "unexpected type %d of elf executable %s\n" e_type filename)) in if !verbose then Printf.printf "header.e_type=%d pie=%b\n" header.e_type (is_pie header.e_type); { filename ; pie = is_pie header.e_type ; probes = read_notes ~filename map sections ; text_section = find_section_exn ".text" ; data_section = find_section_exn ".data" ; semaphores_section = Option.map mk_section (Owee_elf.find_section sections ".probes") } ;; let find_probe_note t name = match Hashtbl.find_opt t.probes name with | Some p -> p | None -> raise (Failure (Printf.sprintf "Probe %s not found" name)) ;;
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>