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 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
|
(**************************************************************************)
(* *)
(* OCaml *)
(* *)
(* Jerome Vouillon, projet Cristal, INRIA Rocquencourt *)
(* OCaml port by John Malecki and Xavier Leroy *)
(* *)
(* Copyright 1996 Institut National de Recherche en Informatique et *)
(* en Automatique. *)
(* *)
(* All rights reserved. This file is distributed under the terms of *)
(* the GNU Lesser General Public License version 2.1, with the *)
(* special exception on linking described in the file LICENSE. *)
(* *)
(**************************************************************************)
(* Handling of symbol tables (globals and events) *)
open Instruct
open Debugger_config (* Toplevel *)
open Program_loading
open Debugcom
open Events
module String = Misc.Stdlib.String
let modules =
ref ([] : string list)
let program_source_dirs =
ref ([] : string list)
let events_by_pc =
(Hashtbl.create 257 : (pc, debug_event) Hashtbl.t)
let events_by_module =
(Hashtbl.create 17 : (string, int * debug_event array) Hashtbl.t)
let all_events_by_module =
(Hashtbl.create 17 : (string, int * debug_event list) Hashtbl.t)
let partition_modules evl =
let rec partition_modules' ev evl =
match evl with
[] -> [ev],[]
| ev'::evl ->
let evl,evll = partition_modules' ev' evl in
if ev.ev_module = ev'.ev_module then ev::evl,evll else [ev],evl::evll
in
match evl with
[] -> []
| ev::evl -> let evl,evll = partition_modules' ev evl in evl::evll
let relocate_event orig ev =
ev.ev_pos <- orig + ev.ev_pos;
match ev.ev_repr with
Event_parent repr -> repr := ev.ev_pos
| _ -> ()
let read_symbols' bytecode_file =
let ic = open_in_bin bytecode_file in
let toc =
try
let toc = Bytesections.read_toc ic in
ignore(Bytesections.seek_section toc ic Bytesections.Name.SYMB);
toc
with Bytesections.Bad_magic_number | Not_found ->
prerr_string bytecode_file; prerr_endline " is not a bytecode file.";
raise Toplevel
in
Symtable.restore_state (input_value ic);
begin try
ignore (Bytesections.seek_section toc ic Bytesections.Name.DBUG)
with Not_found ->
prerr_string bytecode_file; prerr_endline " has no debugging info.";
raise Toplevel
end;
let num_eventlists = input_binary_int ic in
let dirs = ref String.Set.empty in
let eventlists = ref [] in
for _i = 1 to num_eventlists do
let orig = input_binary_int ic in
let evl = (input_value ic : debug_event list) in
(* Relocate events in event list *)
List.iter (relocate_event orig) evl;
let evll = partition_modules evl in
eventlists := evll @ !eventlists;
dirs :=
List.fold_left (fun s e -> String.Set.add e s) !dirs (input_value ic)
done;
begin try
ignore (Bytesections.seek_section toc ic Bytesections.Name.CODE)
with Not_found ->
(* The file contains only debugging info,
loading mode is forced to "manual" *)
set_launching_function (List.assoc "manual" loading_modes)
end;
close_in_noerr ic;
!eventlists, !dirs
let clear_symbols () =
modules := [];
program_source_dirs := [];
Hashtbl.clear events_by_pc; Hashtbl.clear events_by_module;
Hashtbl.clear all_events_by_module
let add_symbols frag all_events =
List.iter
(fun evl ->
List.iter
(fun ev ->
Hashtbl.add events_by_pc {frag; pos = ev.ev_pos} ev)
evl)
all_events;
List.iter
(function
[] -> ()
| ev :: _ as evl ->
let md = ev.ev_module in
let cmp ev1 ev2 = compare (Events.get_pos ev1).Lexing.pos_cnum
(Events.get_pos ev2).Lexing.pos_cnum
in
let sorted_evl = List.sort cmp evl in
modules := md :: !modules;
Hashtbl.add all_events_by_module md (frag, sorted_evl);
let real_evl =
List.filter
(function
{ev_kind = Event_pseudo} -> false
| _ -> true)
sorted_evl
in
Hashtbl.add events_by_module md (frag, Array.of_list real_evl))
all_events
let read_symbols frag bytecode_file =
let all_events, all_dirs = read_symbols' bytecode_file in
program_source_dirs := !program_source_dirs @ (String.Set.elements all_dirs);
add_symbols frag all_events
let erase_symbols frag =
let pcs = Hashtbl.fold (fun pc _ pcs ->
if pc.frag = frag then pc :: pcs else pcs)
events_by_pc []
in
List.iter (Hashtbl.remove events_by_pc) pcs;
let mds = Hashtbl.fold (fun md (frag', _) mds ->
if frag' = frag then md :: mds else mds)
events_by_module []
in
List.iter (Hashtbl.remove events_by_module) mds;
List.iter (Hashtbl.remove all_events_by_module) mds;
modules := List.filter (fun md -> not (List.mem md mds)) !modules
let code_fragments () =
let frags =
Hashtbl.fold
(fun _ (frag, _) l -> frag :: l)
all_events_by_module []
in
List.sort_uniq compare frags
let modules_in_code_fragment frag' =
Hashtbl.fold (fun md (frag, _) l ->
if frag' = frag then md :: l else l)
all_events_by_module []
let any_event_at_pc pc =
{ ev_frag = pc.frag; ev_ev = Hashtbl.find events_by_pc pc }
let event_at_pc pc =
match any_event_at_pc pc with
{ ev_ev = { ev_kind = Event_pseudo } } -> raise Not_found
| ev -> ev
let set_event_at_pc pc =
try ignore(event_at_pc pc); set_event pc
with Not_found -> ()
(* List all events in module *)
let events_in_module mdle =
try
Hashtbl.find all_events_by_module mdle
with Not_found ->
0, []
(* Binary search of event at or just after char *)
let find_event ev char =
let rec bsearch lo hi =
if lo >= hi then begin
if (Events.get_pos ev.(hi)).Lexing.pos_cnum < char
then raise Not_found
else hi
end else begin
let pivot = (lo + hi) / 2 in
let e = ev.(pivot) in
if char <= (Events.get_pos e).Lexing.pos_cnum
then bsearch lo pivot
else bsearch (pivot + 1) hi
end
in
if Array.length ev = 0 then
raise Not_found
else
bsearch 0 (Array.length ev - 1)
(* Return first event after the given position. *)
(* Raise [Not_found] if module is unknown or no event is found. *)
let event_at_pos md char =
let ev_frag, ev = Hashtbl.find events_by_module md in
{ ev_frag; ev_ev = ev.(find_event ev char) }
(* Return event closest to given position *)
(* Raise [Not_found] if module is unknown or no event is found. *)
let event_near_pos md char =
let ev_frag, ev = Hashtbl.find events_by_module md in
try
let pos = find_event ev char in
(* Desired event is either ev.(pos) or ev.(pos - 1),
whichever is closest *)
if pos > 0 && char - (Events.get_pos ev.(pos - 1)).Lexing.pos_cnum
<= (Events.get_pos ev.(pos)).Lexing.pos_cnum - char
then { ev_frag; ev_ev = ev.(pos - 1) }
else { ev_frag; ev_ev = ev.(pos) }
with Not_found ->
let pos = Array.length ev - 1 in
if pos < 0 then raise Not_found;
{ ev_frag; ev_ev = ev.(pos) }
(* Flip "event" bit on all instructions *)
let set_all_events frag =
Hashtbl.iter
(fun pc ev ->
match ev.ev_kind with
Event_pseudo -> ()
| _ when pc.frag = frag -> set_event pc
| _ -> ())
events_by_pc
(* Previous `pc'. *)
(* Save time if `update_current_event' is called *)
(* several times at the same point. *)
let old_pc = ref (None : pc option)
(* Recompute the current event *)
let update_current_event () =
match Checkpoints.current_pc () with
None ->
Events.current_event := None;
old_pc := None
| (Some pc) as opt_pc when opt_pc <> !old_pc ->
Events.current_event :=
begin try
Some (event_at_pc pc)
with Not_found ->
None
end;
old_pc := opt_pc
| _ ->
()
|