Branch data Line data Source code
1 : : // $Id: DbgBreakpoint.cc 1345 2005-09-08 07:42:11Z vern $
2 : :
3 : : // Implementation of breakpoints.
4 : :
5 : : #include "config.h"
6 : :
7 : : #include <assert.h>
8 : :
9 : : #include "ID.h"
10 : : #include "Queue.h"
11 : : #include "Debug.h"
12 : : #include "Scope.h"
13 : : #include "Func.h"
14 : : #include "Stmt.h"
15 : : #include "DbgBreakpoint.h"
16 : : #include "Timer.h"
17 : :
18 : :
19 : : // BreakpointTimer used for time-based breakpoints
20 [ # # ][ # # ]: 0 : class BreakpointTimer : public Timer {
21 : : public:
22 : : BreakpointTimer(DbgBreakpoint* arg_bp, double arg_t)
23 : : : Timer(arg_t, TIMER_BREAKPOINT)
24 : : { bp = arg_bp; }
25 : :
26 : : void Dispatch(double t, int is_expire);
27 : :
28 : : protected:
29 : : DbgBreakpoint* bp;
30 : : };
31 : :
32 : 0 : void BreakpointTimer::Dispatch(double t, int is_expire)
33 : : {
34 [ # # ]: 0 : if ( is_expire )
35 : 0 : return;
36 : :
37 : 0 : bp->ShouldBreak(t);
38 : : }
39 : :
40 : :
41 : 0 : DbgBreakpoint::DbgBreakpoint()
42 : : {
43 : 0 : kind = BP_STMT;
44 : :
45 : 0 : enabled = temporary = false;
46 : 0 : BPID = -1;
47 : :
48 : 0 : at_stmt = 0;
49 : 0 : at_time = -1.0;
50 : :
51 : 0 : repeat_count = hit_count = 0;
52 : :
53 : 0 : description[0] = 0;
54 : 0 : }
55 : :
56 : 0 : DbgBreakpoint::~DbgBreakpoint()
57 : : {
58 : 0 : SetEnable(false); // clean up any active state
59 : 0 : RemoveFromGlobalMap();
60 : 0 : }
61 : :
62 : 0 : bool DbgBreakpoint::SetEnable(bool do_enable)
63 : : {
64 : 0 : bool old_value = enabled;
65 : 0 : enabled = do_enable;
66 : :
67 : : // Update statement counts.
68 [ # # ][ # # ]: 0 : if ( do_enable && ! old_value )
69 : 0 : AddToStmt();
70 : :
71 [ # # ][ # # ]: 0 : else if ( ! do_enable && old_value )
72 : 0 : RemoveFromStmt();
73 : :
74 : 0 : return old_value;
75 : : }
76 : :
77 : 0 : void DbgBreakpoint::AddToGlobalMap()
78 : : {
79 : : // Make sure it's not there already.
80 : 0 : RemoveFromGlobalMap();
81 : :
82 : 0 : g_debugger_state.breakpoint_map.insert(BPMapType::value_type(at_stmt, this));
83 : 0 : }
84 : :
85 : 0 : void DbgBreakpoint::RemoveFromGlobalMap()
86 : : {
87 : 0 : pair<BPMapType::iterator, BPMapType::iterator> p;
88 : 0 : p = g_debugger_state.breakpoint_map.equal_range(at_stmt);
89 : :
90 [ # # ]: 0 : for ( BPMapType::iterator i = p.first; i != p.second; ++i )
91 : : {
92 [ # # ]: 0 : if ( i->second == this )
93 : 0 : g_debugger_state.breakpoint_map.erase(i);
94 : : }
95 : 0 : }
96 : :
97 : 0 : void DbgBreakpoint::AddToStmt()
98 : : {
99 [ # # ]: 0 : if ( at_stmt )
100 : 0 : at_stmt->IncrBPCount();
101 : 0 : }
102 : :
103 : 0 : void DbgBreakpoint::RemoveFromStmt()
104 : : {
105 [ # # ]: 0 : if ( at_stmt )
106 : 0 : at_stmt->DecrBPCount();
107 : 0 : }
108 : :
109 : :
110 : 0 : bool DbgBreakpoint::SetLocation(ParseLocationRec plr, string loc_str)
111 : : {
112 [ # # ]: 0 : if ( plr.type == plrUnknown )
113 : : {
114 : 0 : debug_msg("Breakpoint specifier invalid or operation canceled.\n");
115 : 0 : return false;
116 : : }
117 : :
118 [ # # ]: 0 : if ( plr.type == plrFileAndLine )
119 : : {
120 : 0 : kind = BP_LINE;
121 : 0 : source_filename = plr.filename;
122 : 0 : source_line = plr.line;
123 : :
124 [ # # ]: 0 : if ( ! plr.stmt )
125 : : {
126 : 0 : debug_msg("No statement at that line.\n");
127 : 0 : return false;
128 : : }
129 : :
130 : 0 : at_stmt = plr.stmt;
131 : : safe_snprintf(description, sizeof(description), "%s:%d",
132 : 0 : source_filename, source_line);
133 : :
134 : 0 : debug_msg("Breakpoint %d set at %s\n", GetID(), Description());
135 : : }
136 : :
137 [ # # ]: 0 : else if ( plr.type == plrFunction )
138 : : {
139 : 0 : kind = BP_FUNC;
140 : : function_name = make_full_var_name(current_module.c_str(),
141 : 0 : loc_str.c_str());
142 : 0 : at_stmt = plr.stmt;
143 : 0 : const Location* loc = at_stmt->GetLocationInfo();
144 : : safe_snprintf(description, sizeof(description), "%s at %s:%d",
145 : 0 : function_name.c_str(), loc->filename, loc->last_line);
146 : :
147 : 0 : debug_msg("Breakpoint %d set at %s\n", GetID(), Description());
148 : : }
149 : :
150 : 0 : SetEnable(true);
151 : 0 : AddToGlobalMap();
152 : 0 : return true;
153 : : }
154 : :
155 : 0 : bool DbgBreakpoint::SetLocation(Stmt* stmt)
156 : : {
157 [ # # ]: 0 : if ( ! stmt )
158 : 0 : return false;
159 : :
160 : 0 : kind = BP_STMT;
161 : 0 : at_stmt = stmt;
162 : :
163 : 0 : SetEnable(true);
164 : 0 : AddToGlobalMap();
165 : :
166 : 0 : const Location* loc = stmt->GetLocationInfo();
167 : : safe_snprintf(description, sizeof(description), "%s:%d",
168 : 0 : loc->filename, loc->last_line);
169 : :
170 : 0 : debug_msg("Breakpoint %d set at %s\n", GetID(), Description());
171 : :
172 : 0 : return true;
173 : : }
174 : :
175 : 0 : bool DbgBreakpoint::SetLocation(double t)
176 : : {
177 : 0 : debug_msg("SetLocation(time) has not been debugged.");
178 : 0 : return false;
179 : :
180 : : kind = BP_TIME;
181 : : at_time = t;
182 : :
183 : : timer_mgr->Add(new BreakpointTimer(this, t));
184 : :
185 : : debug_msg("Time-based breakpoints not yet supported.\n");
186 : : return false;
187 : : }
188 : :
189 : 0 : bool DbgBreakpoint::Reset()
190 : : {
191 : : ParseLocationRec plr;
192 : :
193 [ # # # ]: 0 : switch ( kind ) {
194 : : case BP_TIME:
195 : 0 : debug_msg("Time-based breakpoints not yet supported.\n");
196 : 0 : break;
197 : :
198 : : case BP_FUNC:
199 : : case BP_STMT:
200 : : case BP_LINE:
201 : 0 : plr.type = plrFunction;
202 : : //### How to deal with wildcards?
203 : : //### perhaps save user choices?--tough...
204 : : break;
205 : : }
206 : :
207 : 0 : internal_error("DbgBreakpoint::Reset function incomplete.");
208 : : }
209 : :
210 : 0 : bool DbgBreakpoint::SetCondition(const string& new_condition)
211 : : {
212 : 0 : condition = new_condition;
213 : 0 : return true;
214 : : }
215 : :
216 : 0 : bool DbgBreakpoint::SetRepeatCount(int count)
217 : : {
218 : 0 : repeat_count = count;
219 : 0 : return true;
220 : : }
221 : :
222 : 0 : BreakCode DbgBreakpoint::HasHit()
223 : : {
224 [ # # ]: 0 : if ( temporary )
225 : : {
226 : 0 : SetEnable(false);
227 : 0 : return bcHitAndDelete;
228 : : }
229 : :
230 [ # # ]: 0 : if ( condition.size() )
231 : : {
232 : : // TODO: ### evaluate using debugger frame too
233 : 0 : Val* yes = dbg_eval_expr(condition.c_str());
234 : :
235 [ # # ]: 0 : if ( ! yes )
236 : : {
237 : : debug_msg("Breakpoint condition '%s' invalid, removing condition.\n",
238 : 0 : condition.c_str());
239 : 0 : SetCondition("");
240 : 0 : PrintHitMsg();
241 : 0 : return bcHit;
242 : : }
243 : :
244 [ # # ][ # # ]: 0 : if ( ! IsIntegral(yes->Type()->Tag()) &&
[ # # ][ # # ]
[ # # ]
245 : : ! IsBool(yes->Type()->Tag()) )
246 : : {
247 : 0 : PrintHitMsg();
248 : 0 : debug_msg("Breakpoint condition should return an integral type");
249 : 0 : return bcHitAndDelete;
250 : : }
251 : :
252 : 0 : yes->CoerceToInt();
253 [ # # ]: 0 : if ( yes->IsZero() )
254 : 0 : return bcNoHit;
255 : : }
256 : :
257 : 0 : int repcount = GetRepeatCount();
258 [ # # ]: 0 : if ( repcount )
259 : : {
260 [ # # ]: 0 : if ( ++hit_count == repcount )
261 : : {
262 : 0 : hit_count = 0;
263 : 0 : PrintHitMsg();
264 : 0 : return bcHit;
265 : : }
266 : :
267 : 0 : return bcNoHit;
268 : : }
269 : :
270 : 0 : PrintHitMsg();
271 : 0 : return bcHit;
272 : : }
273 : :
274 : 0 : BreakCode DbgBreakpoint::ShouldBreak(Stmt* s)
275 : : {
276 [ # # ]: 0 : if ( ! IsEnabled() )
277 : 0 : return bcNoHit;
278 : :
279 [ # # # # ]: 0 : switch ( kind ) {
280 : : case BP_STMT:
281 : : case BP_FUNC:
282 [ # # ]: 0 : if ( at_stmt != s )
283 : 0 : return bcNoHit;
284 : 0 : break;
285 : :
286 : : case BP_LINE:
287 [ # # ][ # # ]: 0 : assert(s->GetLocationInfo()->first_line <= source_line &&
[ # # ]
288 : : s->GetLocationInfo()->last_line >= source_line);
289 : 0 : break;
290 : :
291 : : case BP_TIME:
292 : 0 : assert(false);
293 : :
294 : : default:
295 : 0 : internal_error("Invalid breakpoint type in DbgBreakpoint::ShouldBreak");
296 : : }
297 : :
298 : : // If we got here, that means that the breakpoint could hit,
299 : : // except potentially if it has a special condition or a repeat count.
300 : :
301 : 0 : BreakCode code = HasHit();
302 [ # # ]: 0 : if ( code )
303 : 0 : g_debugger_state.BreakBeforeNextStmt(true);
304 : :
305 : 0 : return code;
306 : : }
307 : :
308 : :
309 : 0 : BreakCode DbgBreakpoint::ShouldBreak(double t)
310 : : {
311 [ # # ]: 0 : if ( kind != BP_TIME )
312 : 0 : internal_error("Calling ShouldBreak(time) on a non-time breakpoint");
313 : :
314 [ # # ]: 0 : if ( t < at_time )
315 : 0 : return bcNoHit;
316 : :
317 [ # # ]: 0 : if ( ! IsEnabled() )
318 : 0 : return bcNoHit;
319 : :
320 : 0 : BreakCode code = HasHit();
321 [ # # ]: 0 : if ( code )
322 : 0 : g_debugger_state.BreakBeforeNextStmt(true);
323 : :
324 : 0 : return code;
325 : : }
326 : :
327 : 0 : void DbgBreakpoint::PrintHitMsg()
328 : : {
329 [ # # # ]: 0 : switch ( kind ) {
330 : : case BP_STMT:
331 : : case BP_FUNC:
332 : : case BP_LINE:
333 : : {
334 : 0 : ODesc d;
335 : 0 : Frame* f = g_frame_stack.back();
336 : 0 : const BroFunc* func = f->GetFunction();
337 : :
338 [ # # ]: 0 : if ( func )
339 : 0 : func->DescribeDebug (&d, f->GetFuncArgs());
340 : :
341 : 0 : const Location* loc = at_stmt->GetLocationInfo();
342 : :
343 : : debug_msg("Breakpoint %d, %s at %s:%d\n",
344 : : GetID(), d.Description(),
345 : 0 : loc->filename, loc->first_line);
346 : : }
347 : : return;
348 : :
349 : : case BP_TIME:
350 : 0 : assert(false);
351 : :
352 : : default:
353 : 0 : internal_error("Missed a case in DbgBreakpoint::PrintHitMsg\n");
354 : : }
355 [ + - ][ + - ]: 6 : }
|