1 | //===-- StopInfo.cpp ------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include <string> |
10 | |
11 | #include "lldb/Breakpoint/Breakpoint.h" |
12 | #include "lldb/Breakpoint/BreakpointLocation.h" |
13 | #include "lldb/Breakpoint/StoppointCallbackContext.h" |
14 | #include "lldb/Breakpoint/Watchpoint.h" |
15 | #include "lldb/Breakpoint/WatchpointResource.h" |
16 | #include "lldb/Core/Debugger.h" |
17 | #include "lldb/Core/ValueObject.h" |
18 | #include "lldb/Expression/UserExpression.h" |
19 | #include "lldb/Target/Process.h" |
20 | #include "lldb/Target/StopInfo.h" |
21 | #include "lldb/Target/Target.h" |
22 | #include "lldb/Target/Thread.h" |
23 | #include "lldb/Target/ThreadPlan.h" |
24 | #include "lldb/Target/ThreadPlanStepInstruction.h" |
25 | #include "lldb/Target/UnixSignals.h" |
26 | #include "lldb/Utility/LLDBLog.h" |
27 | #include "lldb/Utility/Log.h" |
28 | #include "lldb/Utility/StreamString.h" |
29 | |
30 | using namespace lldb; |
31 | using namespace lldb_private; |
32 | |
33 | StopInfo::StopInfo(Thread &thread, uint64_t value) |
34 | : m_thread_wp(thread.shared_from_this()), |
35 | m_stop_id(thread.GetProcess()->GetStopID()), |
36 | m_resume_id(thread.GetProcess()->GetResumeID()), m_value(value), |
37 | m_description(), m_override_should_notify(eLazyBoolCalculate), |
38 | m_override_should_stop(eLazyBoolCalculate), m_extended_info() {} |
39 | |
40 | bool StopInfo::IsValid() const { |
41 | ThreadSP thread_sp(m_thread_wp.lock()); |
42 | if (thread_sp) |
43 | return thread_sp->GetProcess()->GetStopID() == m_stop_id; |
44 | return false; |
45 | } |
46 | |
47 | void StopInfo::MakeStopInfoValid() { |
48 | ThreadSP thread_sp(m_thread_wp.lock()); |
49 | if (thread_sp) { |
50 | m_stop_id = thread_sp->GetProcess()->GetStopID(); |
51 | m_resume_id = thread_sp->GetProcess()->GetResumeID(); |
52 | } |
53 | } |
54 | |
55 | bool StopInfo::HasTargetRunSinceMe() { |
56 | ThreadSP thread_sp(m_thread_wp.lock()); |
57 | |
58 | if (thread_sp) { |
59 | lldb::StateType ret_type = thread_sp->GetProcess()->GetPrivateState(); |
60 | if (ret_type == eStateRunning) { |
61 | return true; |
62 | } else if (ret_type == eStateStopped) { |
63 | // This is a little tricky. We want to count "run and stopped again |
64 | // before you could ask this question as a "TRUE" answer to |
65 | // HasTargetRunSinceMe. But we don't want to include any running of the |
66 | // target done for expressions. So we track both resumes, and resumes |
67 | // caused by expressions, and check if there are any resumes |
68 | // NOT caused |
69 | // by expressions. |
70 | |
71 | uint32_t curr_resume_id = thread_sp->GetProcess()->GetResumeID(); |
72 | uint32_t last_user_expression_id = |
73 | thread_sp->GetProcess()->GetLastUserExpressionResumeID(); |
74 | if (curr_resume_id == m_resume_id) { |
75 | return false; |
76 | } else if (curr_resume_id > last_user_expression_id) { |
77 | return true; |
78 | } |
79 | } |
80 | } |
81 | return false; |
82 | } |
83 | |
84 | // StopInfoBreakpoint |
85 | |
86 | namespace lldb_private { |
87 | class StopInfoBreakpoint : public StopInfo { |
88 | public: |
89 | StopInfoBreakpoint(Thread &thread, break_id_t break_id) |
90 | : StopInfo(thread, break_id), m_should_stop(false), |
91 | m_should_stop_is_valid(false), m_should_perform_action(true), |
92 | m_address(LLDB_INVALID_ADDRESS), m_break_id(LLDB_INVALID_BREAK_ID), |
93 | m_was_all_internal(false), m_was_one_shot(false) { |
94 | StoreBPInfo(); |
95 | } |
96 | |
97 | StopInfoBreakpoint(Thread &thread, break_id_t break_id, bool should_stop) |
98 | : StopInfo(thread, break_id), m_should_stop(should_stop), |
99 | m_should_stop_is_valid(true), m_should_perform_action(true), |
100 | m_address(LLDB_INVALID_ADDRESS), m_break_id(LLDB_INVALID_BREAK_ID), |
101 | m_was_all_internal(false), m_was_one_shot(false) { |
102 | StoreBPInfo(); |
103 | } |
104 | |
105 | ~StopInfoBreakpoint() override = default; |
106 | |
107 | void StoreBPInfo() { |
108 | ThreadSP thread_sp(m_thread_wp.lock()); |
109 | if (thread_sp) { |
110 | BreakpointSiteSP bp_site_sp( |
111 | thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(site_id: m_value)); |
112 | if (bp_site_sp) { |
113 | uint32_t num_constituents = bp_site_sp->GetNumberOfConstituents(); |
114 | if (num_constituents == 1) { |
115 | BreakpointLocationSP bp_loc_sp = bp_site_sp->GetConstituentAtIndex(idx: 0); |
116 | if (bp_loc_sp) { |
117 | Breakpoint & bkpt = bp_loc_sp->GetBreakpoint(); |
118 | m_break_id = bkpt.GetID(); |
119 | m_was_one_shot = bkpt.IsOneShot(); |
120 | m_was_all_internal = bkpt.IsInternal(); |
121 | } |
122 | } else { |
123 | m_was_all_internal = true; |
124 | for (uint32_t i = 0; i < num_constituents; i++) { |
125 | if (!bp_site_sp->GetConstituentAtIndex(idx: i) |
126 | ->GetBreakpoint() |
127 | .IsInternal()) { |
128 | m_was_all_internal = false; |
129 | break; |
130 | } |
131 | } |
132 | } |
133 | m_address = bp_site_sp->GetLoadAddress(); |
134 | } |
135 | } |
136 | } |
137 | |
138 | bool IsValidForOperatingSystemThread(Thread &thread) override { |
139 | ProcessSP process_sp(thread.GetProcess()); |
140 | if (process_sp) { |
141 | BreakpointSiteSP bp_site_sp( |
142 | process_sp->GetBreakpointSiteList().FindByID(site_id: m_value)); |
143 | if (bp_site_sp) |
144 | return bp_site_sp->ValidForThisThread(thread); |
145 | } |
146 | return false; |
147 | } |
148 | |
149 | StopReason GetStopReason() const override { return eStopReasonBreakpoint; } |
150 | |
151 | bool ShouldStopSynchronous(Event *event_ptr) override { |
152 | ThreadSP thread_sp(m_thread_wp.lock()); |
153 | if (thread_sp) { |
154 | if (!m_should_stop_is_valid) { |
155 | // Only check once if we should stop at a breakpoint |
156 | BreakpointSiteSP bp_site_sp( |
157 | thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(site_id: m_value)); |
158 | if (bp_site_sp) { |
159 | ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(idx: 0)); |
160 | StoppointCallbackContext context(event_ptr, exe_ctx, true); |
161 | bp_site_sp->BumpHitCounts(); |
162 | m_should_stop = bp_site_sp->ShouldStop(context: &context); |
163 | } else { |
164 | Log *log = GetLog(mask: LLDBLog::Process); |
165 | |
166 | LLDB_LOGF(log, |
167 | "Process::%s could not find breakpoint site id: %" PRId64 |
168 | "..." , |
169 | __FUNCTION__, m_value); |
170 | |
171 | m_should_stop = true; |
172 | } |
173 | m_should_stop_is_valid = true; |
174 | } |
175 | return m_should_stop; |
176 | } |
177 | return false; |
178 | } |
179 | |
180 | bool DoShouldNotify(Event *event_ptr) override { |
181 | return !m_was_all_internal; |
182 | } |
183 | |
184 | const char *GetDescription() override { |
185 | if (m_description.empty()) { |
186 | ThreadSP thread_sp(m_thread_wp.lock()); |
187 | if (thread_sp) { |
188 | BreakpointSiteSP bp_site_sp( |
189 | thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(site_id: m_value)); |
190 | if (bp_site_sp) { |
191 | StreamString strm; |
192 | // If we have just hit an internal breakpoint, and it has a kind |
193 | // description, print that instead of the full breakpoint printing: |
194 | if (bp_site_sp->IsInternal()) { |
195 | size_t num_constituents = bp_site_sp->GetNumberOfConstituents(); |
196 | for (size_t idx = 0; idx < num_constituents; idx++) { |
197 | const char *kind = bp_site_sp->GetConstituentAtIndex(idx) |
198 | ->GetBreakpoint() |
199 | .GetBreakpointKind(); |
200 | if (kind != nullptr) { |
201 | m_description.assign(s: kind); |
202 | return kind; |
203 | } |
204 | } |
205 | } |
206 | |
207 | strm.Printf(format: "breakpoint " ); |
208 | bp_site_sp->GetDescription(s: &strm, level: eDescriptionLevelBrief); |
209 | m_description = std::string(strm.GetString()); |
210 | } else { |
211 | StreamString strm; |
212 | if (m_break_id != LLDB_INVALID_BREAK_ID) { |
213 | BreakpointSP break_sp = |
214 | thread_sp->GetProcess()->GetTarget().GetBreakpointByID( |
215 | break_id: m_break_id); |
216 | if (break_sp) { |
217 | if (break_sp->IsInternal()) { |
218 | const char *kind = break_sp->GetBreakpointKind(); |
219 | if (kind) |
220 | strm.Printf(format: "internal %s breakpoint(%d)." , kind, m_break_id); |
221 | else |
222 | strm.Printf(format: "internal breakpoint(%d)." , m_break_id); |
223 | } else { |
224 | strm.Printf(format: "breakpoint %d." , m_break_id); |
225 | } |
226 | } else { |
227 | if (m_was_one_shot) |
228 | strm.Printf(format: "one-shot breakpoint %d" , m_break_id); |
229 | else |
230 | strm.Printf(format: "breakpoint %d which has been deleted." , |
231 | m_break_id); |
232 | } |
233 | } else if (m_address == LLDB_INVALID_ADDRESS) |
234 | strm.Printf(format: "breakpoint site %" PRIi64 |
235 | " which has been deleted - unknown address" , |
236 | m_value); |
237 | else |
238 | strm.Printf(format: "breakpoint site %" PRIi64 |
239 | " which has been deleted - was at 0x%" PRIx64, |
240 | m_value, m_address); |
241 | |
242 | m_description = std::string(strm.GetString()); |
243 | } |
244 | } |
245 | } |
246 | return m_description.c_str(); |
247 | } |
248 | |
249 | protected: |
250 | bool ShouldStop(Event *event_ptr) override { |
251 | // This just reports the work done by PerformAction or the synchronous |
252 | // stop. It should only ever get called after they have had a chance to |
253 | // run. |
254 | assert(m_should_stop_is_valid); |
255 | return m_should_stop; |
256 | } |
257 | |
258 | void PerformAction(Event *event_ptr) override { |
259 | if (!m_should_perform_action) |
260 | return; |
261 | m_should_perform_action = false; |
262 | bool all_stopping_locs_internal = true; |
263 | |
264 | ThreadSP thread_sp(m_thread_wp.lock()); |
265 | |
266 | if (thread_sp) { |
267 | Log *log = GetLog(mask: LLDBLog::Breakpoints | LLDBLog::Step); |
268 | |
269 | if (!thread_sp->IsValid()) { |
270 | // This shouldn't ever happen, but just in case, don't do more harm. |
271 | if (log) { |
272 | LLDB_LOGF(log, "PerformAction got called with an invalid thread." ); |
273 | } |
274 | m_should_stop = true; |
275 | m_should_stop_is_valid = true; |
276 | return; |
277 | } |
278 | |
279 | BreakpointSiteSP bp_site_sp( |
280 | thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(site_id: m_value)); |
281 | std::unordered_set<break_id_t> precondition_breakpoints; |
282 | // Breakpoints that fail their condition check are not considered to |
283 | // have been hit. If the only locations at this site have failed their |
284 | // conditions, we should change the stop-info to none. Otherwise, if we |
285 | // hit another breakpoint on a different thread which does stop, users |
286 | // will see a breakpont hit with a failed condition, which is wrong. |
287 | // Use this variable to tell us if that is true. |
288 | bool actually_hit_any_locations = false; |
289 | if (bp_site_sp) { |
290 | // Let's copy the constituents list out of the site and store them in a |
291 | // local list. That way if one of the breakpoint actions changes the |
292 | // site, then we won't be operating on a bad list. |
293 | BreakpointLocationCollection site_locations; |
294 | size_t num_constituents = |
295 | bp_site_sp->CopyConstituentsList(out_collection&: site_locations); |
296 | |
297 | if (num_constituents == 0) { |
298 | m_should_stop = true; |
299 | actually_hit_any_locations = true; // We're going to stop, don't |
300 | // change the stop info. |
301 | } else { |
302 | // We go through each location, and test first its precondition - |
303 | // this overrides everything. Note, we only do this once per |
304 | // breakpoint - not once per location... Then check the condition. |
305 | // If the condition says to stop, then we run the callback for that |
306 | // location. If that callback says to stop as well, then we set |
307 | // m_should_stop to true; we are going to stop. But we still want to |
308 | // give all the breakpoints whose conditions say we are going to stop |
309 | // a chance to run their callbacks. Of course if any callback |
310 | // restarts the target by putting "continue" in the callback, then |
311 | // we're going to restart, without running the rest of the callbacks. |
312 | // And in this case we will end up not stopping even if another |
313 | // location said we should stop. But that's better than not running |
314 | // all the callbacks. |
315 | |
316 | // There's one other complication here. We may have run an async |
317 | // breakpoint callback that said we should stop. We only want to |
318 | // override that if another breakpoint action says we shouldn't |
319 | // stop. If nobody else has an opinion, then we should stop if the |
320 | // async callback says we should. An example of this is the async |
321 | // shared library load notification breakpoint and the setting |
322 | // stop-on-sharedlibrary-events. |
323 | // We'll keep the async value in async_should_stop, and track whether |
324 | // anyone said we should NOT stop in actually_said_continue. |
325 | bool async_should_stop = false; |
326 | if (m_should_stop_is_valid) |
327 | async_should_stop = m_should_stop; |
328 | bool actually_said_continue = false; |
329 | |
330 | m_should_stop = false; |
331 | |
332 | // We don't select threads as we go through them testing breakpoint |
333 | // conditions and running commands. So we need to set the thread for |
334 | // expression evaluation here: |
335 | ThreadList::ExpressionExecutionThreadPusher thread_pusher(thread_sp); |
336 | |
337 | ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(idx: 0)); |
338 | Process *process = exe_ctx.GetProcessPtr(); |
339 | if (process->GetModIDRef().IsRunningExpression()) { |
340 | // If we are in the middle of evaluating an expression, don't run |
341 | // asynchronous breakpoint commands or expressions. That could |
342 | // lead to infinite recursion if the command or condition re-calls |
343 | // the function with this breakpoint. |
344 | // TODO: We can keep a list of the breakpoints we've seen while |
345 | // running expressions in the nested |
346 | // PerformAction calls that can arise when the action runs a |
347 | // function that hits another breakpoint, and only stop running |
348 | // commands when we see the same breakpoint hit a second time. |
349 | |
350 | m_should_stop_is_valid = true; |
351 | |
352 | // It is possible that the user has a breakpoint at the same site |
353 | // as the completed plan had (e.g. user has a breakpoint |
354 | // on a module entry point, and `ThreadPlanCallFunction` ends |
355 | // also there). We can't find an internal breakpoint in the loop |
356 | // later because it was already removed on the plan completion. |
357 | // So check if the plan was completed, and stop if so. |
358 | if (thread_sp->CompletedPlanOverridesBreakpoint()) { |
359 | m_should_stop = true; |
360 | thread_sp->ResetStopInfo(); |
361 | return; |
362 | } |
363 | |
364 | LLDB_LOGF(log, "StopInfoBreakpoint::PerformAction - Hit a " |
365 | "breakpoint while running an expression," |
366 | " not running commands to avoid recursion." ); |
367 | bool ignoring_breakpoints = |
368 | process->GetIgnoreBreakpointsInExpressions(); |
369 | // Internal breakpoints should be allowed to do their job, we |
370 | // can make sure they don't do anything that would cause recursive |
371 | // command execution: |
372 | if (!m_was_all_internal) { |
373 | m_should_stop = !ignoring_breakpoints; |
374 | LLDB_LOGF(log, |
375 | "StopInfoBreakpoint::PerformAction - in expression, " |
376 | "continuing: %s." , |
377 | m_should_stop ? "true" : "false" ); |
378 | Debugger::ReportWarning( |
379 | message: "hit breakpoint while running function, skipping commands " |
380 | "and conditions to prevent recursion" , |
381 | debugger_id: process->GetTarget().GetDebugger().GetID()); |
382 | return; |
383 | } |
384 | } |
385 | |
386 | StoppointCallbackContext context(event_ptr, exe_ctx, false); |
387 | |
388 | // For safety's sake let's also grab an extra reference to the |
389 | // breakpoint constituents of the locations we're going to examine, |
390 | // since the locations are going to have to get back to their |
391 | // breakpoints, and the locations don't keep their constituents alive. |
392 | // I'm just sticking the BreakpointSP's in a vector since I'm only |
393 | // using it to locally increment their retain counts. |
394 | |
395 | std::vector<lldb::BreakpointSP> location_constituents; |
396 | |
397 | for (size_t j = 0; j < num_constituents; j++) { |
398 | BreakpointLocationSP loc(site_locations.GetByIndex(i: j)); |
399 | location_constituents.push_back( |
400 | x: loc->GetBreakpoint().shared_from_this()); |
401 | } |
402 | |
403 | for (size_t j = 0; j < num_constituents; j++) { |
404 | lldb::BreakpointLocationSP bp_loc_sp = site_locations.GetByIndex(i: j); |
405 | StreamString loc_desc; |
406 | if (log) { |
407 | bp_loc_sp->GetDescription(s: &loc_desc, level: eDescriptionLevelBrief); |
408 | } |
409 | // If another action disabled this breakpoint or its location, then |
410 | // don't run the actions. |
411 | if (!bp_loc_sp->IsEnabled() || |
412 | !bp_loc_sp->GetBreakpoint().IsEnabled()) |
413 | continue; |
414 | |
415 | // The breakpoint site may have many locations associated with it, |
416 | // not all of them valid for this thread. Skip the ones that |
417 | // aren't: |
418 | if (!bp_loc_sp->ValidForThisThread(thread&: *thread_sp)) { |
419 | if (log) { |
420 | LLDB_LOGF(log, |
421 | "Breakpoint %s hit on thread 0x%llx but it was not " |
422 | "for this thread, continuing." , |
423 | loc_desc.GetData(), |
424 | static_cast<unsigned long long>(thread_sp->GetID())); |
425 | } |
426 | continue; |
427 | } |
428 | |
429 | // First run the precondition, but since the precondition is per |
430 | // breakpoint, only run it once per breakpoint. |
431 | std::pair<std::unordered_set<break_id_t>::iterator, bool> result = |
432 | precondition_breakpoints.insert( |
433 | x: bp_loc_sp->GetBreakpoint().GetID()); |
434 | if (!result.second) |
435 | continue; |
436 | |
437 | bool precondition_result = |
438 | bp_loc_sp->GetBreakpoint().EvaluatePrecondition(context); |
439 | if (!precondition_result) { |
440 | actually_said_continue = true; |
441 | continue; |
442 | } |
443 | // Next run the condition for the breakpoint. If that says we |
444 | // should stop, then we'll run the callback for the breakpoint. If |
445 | // the callback says we shouldn't stop that will win. |
446 | |
447 | if (bp_loc_sp->GetConditionText() == nullptr) |
448 | actually_hit_any_locations = true; |
449 | else { |
450 | Status condition_error; |
451 | bool condition_says_stop = |
452 | bp_loc_sp->ConditionSaysStop(exe_ctx, error&: condition_error); |
453 | |
454 | if (!condition_error.Success()) { |
455 | // If the condition fails to evaluate, we are going to stop |
456 | // at it, so the location was hit. |
457 | actually_hit_any_locations = true; |
458 | const char *err_str = |
459 | condition_error.AsCString(default_error_str: "<unknown error>" ); |
460 | LLDB_LOGF(log, "Error evaluating condition: \"%s\"\n" , err_str); |
461 | |
462 | StreamString strm; |
463 | strm << "stopped due to an error evaluating condition of " |
464 | "breakpoint " ; |
465 | bp_loc_sp->GetDescription(s: &strm, level: eDescriptionLevelBrief); |
466 | strm << ": \"" << bp_loc_sp->GetConditionText() << "\"\n" ; |
467 | strm << err_str; |
468 | |
469 | Debugger::ReportError( |
470 | message: strm.GetString().str(), |
471 | debugger_id: exe_ctx.GetTargetRef().GetDebugger().GetID()); |
472 | } else { |
473 | LLDB_LOGF(log, |
474 | "Condition evaluated for breakpoint %s on thread " |
475 | "0x%llx condition_says_stop: %i." , |
476 | loc_desc.GetData(), |
477 | static_cast<unsigned long long>(thread_sp->GetID()), |
478 | condition_says_stop); |
479 | if (condition_says_stop) |
480 | actually_hit_any_locations = true; |
481 | else { |
482 | // We don't want to increment the hit count of breakpoints if |
483 | // the condition fails. We've already bumped it by the time |
484 | // we get here, so undo the bump: |
485 | bp_loc_sp->UndoBumpHitCount(); |
486 | actually_said_continue = true; |
487 | continue; |
488 | } |
489 | } |
490 | } |
491 | |
492 | // We've done all the checks whose failure means "we consider lldb |
493 | // not to have hit the breakpoint". Now we're going to check for |
494 | // conditions that might continue after hitting. Start with the |
495 | // ignore count: |
496 | if (!bp_loc_sp->IgnoreCountShouldStop()) { |
497 | actually_said_continue = true; |
498 | continue; |
499 | } |
500 | |
501 | // Check the auto-continue bit on the location, do this before the |
502 | // callback since it may change this, but that would be for the |
503 | // NEXT hit. Note, you might think you could check auto-continue |
504 | // before the condition, and not evaluate the condition if it says |
505 | // to continue. But failing the condition means the breakpoint was |
506 | // effectively NOT HIT. So these two states are different. |
507 | bool auto_continue_says_stop = true; |
508 | if (bp_loc_sp->IsAutoContinue()) |
509 | { |
510 | LLDB_LOGF(log, |
511 | "Continuing breakpoint %s as AutoContinue was set." , |
512 | loc_desc.GetData()); |
513 | // We want this stop reported, so you will know we auto-continued |
514 | // but only for external breakpoints: |
515 | if (!bp_loc_sp->GetBreakpoint().IsInternal()) |
516 | thread_sp->SetShouldReportStop(eVoteYes); |
517 | auto_continue_says_stop = false; |
518 | } |
519 | |
520 | bool callback_says_stop = true; |
521 | |
522 | // FIXME: For now the callbacks have to run in async mode - the |
523 | // first time we restart we need |
524 | // to get out of there. So set it here. |
525 | // When we figure out how to nest breakpoint hits then this will |
526 | // change. |
527 | |
528 | // Don't run async callbacks in PerformAction. They have already |
529 | // been taken into account with async_should_stop. |
530 | if (!bp_loc_sp->IsCallbackSynchronous()) { |
531 | Debugger &debugger = thread_sp->CalculateTarget()->GetDebugger(); |
532 | bool old_async = debugger.GetAsyncExecution(); |
533 | debugger.SetAsyncExecution(true); |
534 | |
535 | callback_says_stop = bp_loc_sp->InvokeCallback(context: &context); |
536 | |
537 | debugger.SetAsyncExecution(old_async); |
538 | |
539 | if (callback_says_stop && auto_continue_says_stop) |
540 | m_should_stop = true; |
541 | else |
542 | actually_said_continue = true; |
543 | } |
544 | |
545 | if (m_should_stop && !bp_loc_sp->GetBreakpoint().IsInternal()) |
546 | all_stopping_locs_internal = false; |
547 | |
548 | // If we are going to stop for this breakpoint, then remove the |
549 | // breakpoint. |
550 | if (callback_says_stop && bp_loc_sp && |
551 | bp_loc_sp->GetBreakpoint().IsOneShot()) { |
552 | thread_sp->GetProcess()->GetTarget().RemoveBreakpointByID( |
553 | break_id: bp_loc_sp->GetBreakpoint().GetID()); |
554 | } |
555 | // Also make sure that the callback hasn't continued the target. If |
556 | // it did, when we'll set m_should_start to false and get out of |
557 | // here. |
558 | if (HasTargetRunSinceMe()) { |
559 | m_should_stop = false; |
560 | actually_said_continue = true; |
561 | break; |
562 | } |
563 | } |
564 | // At this point if nobody actually told us to continue, we should |
565 | // give the async breakpoint callback a chance to weigh in: |
566 | if (!actually_said_continue && !m_should_stop) { |
567 | m_should_stop = async_should_stop; |
568 | } |
569 | } |
570 | // We've figured out what this stop wants to do, so mark it as valid so |
571 | // we don't compute it again. |
572 | m_should_stop_is_valid = true; |
573 | } else { |
574 | m_should_stop = true; |
575 | m_should_stop_is_valid = true; |
576 | actually_hit_any_locations = true; |
577 | Log *log_process(GetLog(mask: LLDBLog::Process)); |
578 | |
579 | LLDB_LOGF(log_process, |
580 | "Process::%s could not find breakpoint site id: %" PRId64 |
581 | "..." , |
582 | __FUNCTION__, m_value); |
583 | } |
584 | |
585 | if ((!m_should_stop || all_stopping_locs_internal) && |
586 | thread_sp->CompletedPlanOverridesBreakpoint()) { |
587 | |
588 | // Override should_stop decision when we have completed step plan |
589 | // additionally to the breakpoint |
590 | m_should_stop = true; |
591 | |
592 | // We know we're stopping for a completed plan and we don't want to |
593 | // show the breakpoint stop, so compute the public stop info immediately |
594 | // here. |
595 | thread_sp->CalculatePublicStopInfo(); |
596 | } else if (!actually_hit_any_locations) { |
597 | // In the end, we didn't actually have any locations that passed their |
598 | // "was I hit" checks. So say we aren't stopped. |
599 | GetThread()->ResetStopInfo(); |
600 | LLDB_LOGF(log, "Process::%s all locations failed condition checks." , |
601 | __FUNCTION__); |
602 | } |
603 | |
604 | LLDB_LOGF(log, |
605 | "Process::%s returning from action with m_should_stop: %d." , |
606 | __FUNCTION__, m_should_stop); |
607 | } |
608 | } |
609 | |
610 | private: |
611 | bool m_should_stop; |
612 | bool m_should_stop_is_valid; |
613 | bool m_should_perform_action; // Since we are trying to preserve the "state" |
614 | // of the system even if we run functions |
615 | // etc. behind the users backs, we need to make sure we only REALLY perform |
616 | // the action once. |
617 | lldb::addr_t m_address; // We use this to capture the breakpoint site address |
618 | // when we create the StopInfo, |
619 | // in case somebody deletes it between the time the StopInfo is made and the |
620 | // description is asked for. |
621 | lldb::break_id_t m_break_id; |
622 | bool m_was_all_internal; |
623 | bool m_was_one_shot; |
624 | }; |
625 | |
626 | // StopInfoWatchpoint |
627 | |
628 | class StopInfoWatchpoint : public StopInfo { |
629 | public: |
630 | // Make sure watchpoint is properly disabled and subsequently enabled while |
631 | // performing watchpoint actions. |
632 | class WatchpointSentry { |
633 | public: |
634 | WatchpointSentry(ProcessSP p_sp, WatchpointSP w_sp) : process_sp(p_sp), |
635 | watchpoint_sp(w_sp) { |
636 | if (process_sp && watchpoint_sp) { |
637 | const bool notify = false; |
638 | watchpoint_sp->TurnOnEphemeralMode(); |
639 | process_sp->DisableWatchpoint(wp_sp: watchpoint_sp, notify); |
640 | process_sp->AddPreResumeAction(callback: SentryPreResumeAction, baton: this); |
641 | } |
642 | } |
643 | |
644 | void DoReenable() { |
645 | if (process_sp && watchpoint_sp) { |
646 | bool was_disabled = watchpoint_sp->IsDisabledDuringEphemeralMode(); |
647 | watchpoint_sp->TurnOffEphemeralMode(); |
648 | const bool notify = false; |
649 | if (was_disabled) { |
650 | process_sp->DisableWatchpoint(wp_sp: watchpoint_sp, notify); |
651 | } else { |
652 | process_sp->EnableWatchpoint(wp_sp: watchpoint_sp, notify); |
653 | } |
654 | } |
655 | } |
656 | |
657 | ~WatchpointSentry() { |
658 | DoReenable(); |
659 | if (process_sp) |
660 | process_sp->ClearPreResumeAction(callback: SentryPreResumeAction, baton: this); |
661 | } |
662 | |
663 | static bool SentryPreResumeAction(void *sentry_void) { |
664 | WatchpointSentry *sentry = (WatchpointSentry *) sentry_void; |
665 | sentry->DoReenable(); |
666 | return true; |
667 | } |
668 | |
669 | private: |
670 | ProcessSP process_sp; |
671 | WatchpointSP watchpoint_sp; |
672 | }; |
673 | |
674 | StopInfoWatchpoint(Thread &thread, break_id_t watch_id, bool silently_skip_wp) |
675 | : StopInfo(thread, watch_id), m_silently_skip_wp(silently_skip_wp) {} |
676 | |
677 | ~StopInfoWatchpoint() override = default; |
678 | |
679 | StopReason GetStopReason() const override { return eStopReasonWatchpoint; } |
680 | |
681 | const char *GetDescription() override { |
682 | if (m_description.empty()) { |
683 | StreamString strm; |
684 | strm.Printf(format: "watchpoint %" PRIi64, m_value); |
685 | m_description = std::string(strm.GetString()); |
686 | } |
687 | return m_description.c_str(); |
688 | } |
689 | |
690 | protected: |
691 | using StopInfoWatchpointSP = std::shared_ptr<StopInfoWatchpoint>; |
692 | // This plan is used to orchestrate stepping over the watchpoint for |
693 | // architectures (e.g. ARM) that report the watch before running the watched |
694 | // access. This is the sort of job you have to defer to the thread plans, |
695 | // if you try to do it directly in the stop info and there are other threads |
696 | // that needed to process this stop you will have yanked control away from |
697 | // them and they won't behave correctly. |
698 | class ThreadPlanStepOverWatchpoint : public ThreadPlanStepInstruction { |
699 | public: |
700 | ThreadPlanStepOverWatchpoint(Thread &thread, |
701 | StopInfoWatchpointSP stop_info_sp, |
702 | WatchpointSP watch_sp) |
703 | : ThreadPlanStepInstruction(thread, false, true, eVoteNoOpinion, |
704 | eVoteNoOpinion), |
705 | m_stop_info_sp(stop_info_sp), m_watch_sp(watch_sp) { |
706 | assert(watch_sp); |
707 | } |
708 | |
709 | bool DoWillResume(lldb::StateType resume_state, |
710 | bool current_plan) override { |
711 | if (resume_state == eStateSuspended) |
712 | return true; |
713 | |
714 | if (!m_did_disable_wp) { |
715 | GetThread().GetProcess()->DisableWatchpoint(wp_sp: m_watch_sp, notify: false); |
716 | m_did_disable_wp = true; |
717 | } |
718 | return true; |
719 | } |
720 | |
721 | bool DoPlanExplainsStop(Event *event_ptr) override { |
722 | if (ThreadPlanStepInstruction::DoPlanExplainsStop(event_ptr)) |
723 | return true; |
724 | StopInfoSP stop_info_sp = GetThread().GetPrivateStopInfo(); |
725 | // lldb-server resets the stop info for threads that didn't get to run, |
726 | // so we might have not gotten to run, but still have a watchpoint stop |
727 | // reason, in which case this will indeed be for us. |
728 | if (stop_info_sp |
729 | && stop_info_sp->GetStopReason() == eStopReasonWatchpoint) |
730 | return true; |
731 | return false; |
732 | } |
733 | |
734 | void DidPop() override { |
735 | // Don't artifically keep the watchpoint alive. |
736 | m_watch_sp.reset(); |
737 | } |
738 | |
739 | bool ShouldStop(Event *event_ptr) override { |
740 | bool should_stop = ThreadPlanStepInstruction::ShouldStop(event_ptr); |
741 | bool plan_done = MischiefManaged(); |
742 | if (plan_done) { |
743 | m_stop_info_sp->SetStepOverPlanComplete(); |
744 | GetThread().SetStopInfo(m_stop_info_sp); |
745 | ResetWatchpoint(); |
746 | } |
747 | return should_stop; |
748 | } |
749 | |
750 | bool ShouldRunBeforePublicStop() override { |
751 | return true; |
752 | } |
753 | |
754 | protected: |
755 | void ResetWatchpoint() { |
756 | if (!m_did_disable_wp) |
757 | return; |
758 | m_did_disable_wp = true; |
759 | GetThread().GetProcess()->EnableWatchpoint(wp_sp: m_watch_sp, notify: true); |
760 | } |
761 | |
762 | private: |
763 | StopInfoWatchpointSP m_stop_info_sp; |
764 | WatchpointSP m_watch_sp; |
765 | bool m_did_disable_wp = false; |
766 | }; |
767 | |
768 | bool ShouldStopSynchronous(Event *event_ptr) override { |
769 | // If we are running our step-over the watchpoint plan, stop if it's done |
770 | // and continue if it's not: |
771 | if (m_should_stop_is_valid) |
772 | return m_should_stop; |
773 | |
774 | // If we are running our step over plan, then stop here and let the regular |
775 | // ShouldStop figure out what we should do: Otherwise, give our plan |
776 | // more time to get run: |
777 | if (m_using_step_over_plan) |
778 | return m_step_over_plan_complete; |
779 | |
780 | Log *log = GetLog(mask: LLDBLog::Process); |
781 | ThreadSP thread_sp(m_thread_wp.lock()); |
782 | assert(thread_sp); |
783 | |
784 | if (thread_sp->GetTemporaryResumeState() == eStateSuspended) { |
785 | // This is the second firing of a watchpoint so don't process it again. |
786 | LLDB_LOG(log, "We didn't run but stopped with a StopInfoWatchpoint, we " |
787 | "have already handled this one, don't do it again." ); |
788 | m_should_stop = false; |
789 | m_should_stop_is_valid = true; |
790 | return m_should_stop; |
791 | } |
792 | |
793 | WatchpointSP wp_sp( |
794 | thread_sp->CalculateTarget()->GetWatchpointList().FindByID(watchID: GetValue())); |
795 | // If we can no longer find the watchpoint, we just have to stop: |
796 | if (!wp_sp) { |
797 | |
798 | LLDB_LOGF(log, |
799 | "Process::%s could not find watchpoint location id: %" PRId64 |
800 | "..." , |
801 | __FUNCTION__, GetValue()); |
802 | |
803 | m_should_stop = true; |
804 | m_should_stop_is_valid = true; |
805 | return true; |
806 | } |
807 | |
808 | ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(idx: 0)); |
809 | StoppointCallbackContext context(event_ptr, exe_ctx, true); |
810 | m_should_stop = wp_sp->ShouldStop(context: &context); |
811 | if (!m_should_stop) { |
812 | // This won't happen at present because we only allow one watchpoint per |
813 | // watched range. So we won't stop at a watched address with a disabled |
814 | // watchpoint. If we start allowing overlapping watchpoints, then we |
815 | // will have to make watchpoints be real "WatchpointSite" and delegate to |
816 | // all the watchpoints sharing the site. In that case, the code below |
817 | // would be the right thing to do. |
818 | m_should_stop_is_valid = true; |
819 | return m_should_stop; |
820 | } |
821 | // If this is a system where we need to execute the watchpoint by hand |
822 | // after the hit, queue a thread plan to do that, and then say not to stop. |
823 | // Otherwise, let the async action figure out whether the watchpoint should |
824 | // stop |
825 | |
826 | ProcessSP process_sp = exe_ctx.GetProcessSP(); |
827 | bool wp_triggers_after = process_sp->GetWatchpointReportedAfter(); |
828 | |
829 | if (!wp_triggers_after) { |
830 | // We have to step over the watchpoint before we know what to do: |
831 | StopInfoWatchpointSP me_as_siwp_sp |
832 | = std::static_pointer_cast<StopInfoWatchpoint>(r: shared_from_this()); |
833 | ThreadPlanSP step_over_wp_sp(new ThreadPlanStepOverWatchpoint( |
834 | *(thread_sp.get()), me_as_siwp_sp, wp_sp)); |
835 | // When this plan is done we want to stop, so set this as a Controlling |
836 | // plan. |
837 | step_over_wp_sp->SetIsControllingPlan(true); |
838 | step_over_wp_sp->SetOkayToDiscard(false); |
839 | |
840 | Status error; |
841 | error = thread_sp->QueueThreadPlan(plan_sp&: step_over_wp_sp, abort_other_plans: false); |
842 | // If we couldn't push the thread plan, just stop here: |
843 | if (!error.Success()) { |
844 | LLDB_LOGF(log, "Could not push our step over watchpoint plan: %s" , |
845 | error.AsCString()); |
846 | |
847 | m_should_stop = true; |
848 | m_should_stop_is_valid = true; |
849 | return true; |
850 | } else { |
851 | // Otherwise, don't set m_should_stop, we don't know that yet. Just |
852 | // say we should continue, and tell the thread we really should do so: |
853 | thread_sp->SetShouldRunBeforePublicStop(true); |
854 | m_using_step_over_plan = true; |
855 | return false; |
856 | } |
857 | } else { |
858 | // We didn't have to do anything special |
859 | m_should_stop_is_valid = true; |
860 | return m_should_stop; |
861 | } |
862 | |
863 | return m_should_stop; |
864 | } |
865 | |
866 | bool ShouldStop(Event *event_ptr) override { |
867 | // This just reports the work done by PerformAction or the synchronous |
868 | // stop. It should only ever get called after they have had a chance to |
869 | // run. |
870 | assert(m_should_stop_is_valid); |
871 | return m_should_stop; |
872 | } |
873 | |
874 | void PerformAction(Event *event_ptr) override { |
875 | Log *log = GetLog(mask: LLDBLog::Watchpoints); |
876 | // We're going to calculate if we should stop or not in some way during the |
877 | // course of this code. Also by default we're going to stop, so set that |
878 | // here. |
879 | m_should_stop = true; |
880 | |
881 | |
882 | ThreadSP thread_sp(m_thread_wp.lock()); |
883 | if (thread_sp) { |
884 | |
885 | WatchpointSP wp_sp( |
886 | thread_sp->CalculateTarget()->GetWatchpointList().FindByID( |
887 | watchID: GetValue())); |
888 | if (wp_sp) { |
889 | // This sentry object makes sure the current watchpoint is disabled |
890 | // while performing watchpoint actions, and it is then enabled after we |
891 | // are finished. |
892 | ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(idx: 0)); |
893 | ProcessSP process_sp = exe_ctx.GetProcessSP(); |
894 | |
895 | WatchpointSentry sentry(process_sp, wp_sp); |
896 | |
897 | if (m_silently_skip_wp) { |
898 | m_should_stop = false; |
899 | wp_sp->UndoHitCount(); |
900 | } |
901 | |
902 | if (wp_sp->GetHitCount() <= wp_sp->GetIgnoreCount()) { |
903 | m_should_stop = false; |
904 | m_should_stop_is_valid = true; |
905 | } |
906 | |
907 | Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger(); |
908 | |
909 | if (m_should_stop && wp_sp->GetConditionText() != nullptr) { |
910 | // We need to make sure the user sees any parse errors in their |
911 | // condition, so we'll hook the constructor errors up to the |
912 | // debugger's Async I/O. |
913 | ExpressionResults result_code; |
914 | EvaluateExpressionOptions expr_options; |
915 | expr_options.SetUnwindOnError(true); |
916 | expr_options.SetIgnoreBreakpoints(true); |
917 | ValueObjectSP result_value_sp; |
918 | Status error; |
919 | result_code = UserExpression::Evaluate( |
920 | exe_ctx, options: expr_options, expr_cstr: wp_sp->GetConditionText(), |
921 | expr_prefix: llvm::StringRef(), result_valobj_sp&: result_value_sp, error); |
922 | |
923 | if (result_code == eExpressionCompleted) { |
924 | if (result_value_sp) { |
925 | Scalar scalar_value; |
926 | if (result_value_sp->ResolveValue(scalar&: scalar_value)) { |
927 | if (scalar_value.ULongLong(fail_value: 1) == 0) { |
928 | // The condition failed, which we consider "not having hit |
929 | // the watchpoint" so undo the hit count here. |
930 | wp_sp->UndoHitCount(); |
931 | m_should_stop = false; |
932 | } else |
933 | m_should_stop = true; |
934 | LLDB_LOGF(log, |
935 | "Condition successfully evaluated, result is %s.\n" , |
936 | m_should_stop ? "true" : "false" ); |
937 | } else { |
938 | m_should_stop = true; |
939 | LLDB_LOGF( |
940 | log, |
941 | "Failed to get an integer result from the expression." ); |
942 | } |
943 | } |
944 | } else { |
945 | const char *err_str = error.AsCString(default_error_str: "<unknown error>" ); |
946 | LLDB_LOGF(log, "Error evaluating condition: \"%s\"\n" , err_str); |
947 | |
948 | StreamString strm; |
949 | strm << "stopped due to an error evaluating condition of " |
950 | "watchpoint " ; |
951 | wp_sp->GetDescription(s: &strm, level: eDescriptionLevelBrief); |
952 | strm << ": \"" << wp_sp->GetConditionText() << "\"\n" ; |
953 | strm << err_str; |
954 | |
955 | Debugger::ReportError(message: strm.GetString().str(), |
956 | debugger_id: exe_ctx.GetTargetRef().GetDebugger().GetID()); |
957 | } |
958 | } |
959 | |
960 | // If the condition says to stop, we run the callback to further decide |
961 | // whether to stop. |
962 | if (m_should_stop) { |
963 | // FIXME: For now the callbacks have to run in async mode - the |
964 | // first time we restart we need |
965 | // to get out of there. So set it here. |
966 | // When we figure out how to nest watchpoint hits then this will |
967 | // change. |
968 | |
969 | bool old_async = debugger.GetAsyncExecution(); |
970 | debugger.SetAsyncExecution(true); |
971 | |
972 | StoppointCallbackContext context(event_ptr, exe_ctx, false); |
973 | bool stop_requested = wp_sp->InvokeCallback(context: &context); |
974 | |
975 | debugger.SetAsyncExecution(old_async); |
976 | |
977 | // Also make sure that the callback hasn't continued the target. If |
978 | // it did, when we'll set m_should_stop to false and get out of here. |
979 | if (HasTargetRunSinceMe()) |
980 | m_should_stop = false; |
981 | |
982 | if (m_should_stop && !stop_requested) { |
983 | // We have been vetoed by the callback mechanism. |
984 | m_should_stop = false; |
985 | } |
986 | } |
987 | |
988 | // Don't stop if the watched region value is unmodified, and |
989 | // this is a Modify-type watchpoint. |
990 | if (m_should_stop && !wp_sp->WatchedValueReportable(exe_ctx)) { |
991 | wp_sp->UndoHitCount(); |
992 | m_should_stop = false; |
993 | } |
994 | |
995 | // Finally, if we are going to stop, print out the new & old values: |
996 | if (m_should_stop) { |
997 | wp_sp->CaptureWatchedValue(exe_ctx); |
998 | |
999 | Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger(); |
1000 | StreamSP output_sp = debugger.GetAsyncOutputStream(); |
1001 | if (wp_sp->DumpSnapshots(s: output_sp.get())) { |
1002 | output_sp->EOL(); |
1003 | output_sp->Flush(); |
1004 | } |
1005 | } |
1006 | |
1007 | } else { |
1008 | Log *log_process(GetLog(mask: LLDBLog::Process)); |
1009 | |
1010 | LLDB_LOGF(log_process, |
1011 | "Process::%s could not find watchpoint id: %" PRId64 "..." , |
1012 | __FUNCTION__, m_value); |
1013 | } |
1014 | LLDB_LOGF(log, |
1015 | "Process::%s returning from action with m_should_stop: %d." , |
1016 | __FUNCTION__, m_should_stop); |
1017 | |
1018 | m_should_stop_is_valid = true; |
1019 | } |
1020 | } |
1021 | |
1022 | private: |
1023 | void SetStepOverPlanComplete() { |
1024 | assert(m_using_step_over_plan); |
1025 | m_step_over_plan_complete = true; |
1026 | } |
1027 | |
1028 | bool m_should_stop = false; |
1029 | bool m_should_stop_is_valid = false; |
1030 | // A false watchpoint hit has happened - |
1031 | // the thread stopped with a watchpoint |
1032 | // hit notification, but the watched region |
1033 | // was not actually accessed (as determined |
1034 | // by the gdb stub we're talking to). |
1035 | // Continue past this watchpoint without |
1036 | // notifying the user; on some targets this |
1037 | // may mean disable wp, instruction step, |
1038 | // re-enable wp, continue. |
1039 | // On others, just continue. |
1040 | bool m_silently_skip_wp = false; |
1041 | bool m_step_over_plan_complete = false; |
1042 | bool m_using_step_over_plan = false; |
1043 | }; |
1044 | |
1045 | // StopInfoUnixSignal |
1046 | |
1047 | class StopInfoUnixSignal : public StopInfo { |
1048 | public: |
1049 | StopInfoUnixSignal(Thread &thread, int signo, const char *description, |
1050 | std::optional<int> code) |
1051 | : StopInfo(thread, signo), m_code(code) { |
1052 | SetDescription(description); |
1053 | } |
1054 | |
1055 | ~StopInfoUnixSignal() override = default; |
1056 | |
1057 | StopReason GetStopReason() const override { return eStopReasonSignal; } |
1058 | |
1059 | bool ShouldStopSynchronous(Event *event_ptr) override { |
1060 | ThreadSP thread_sp(m_thread_wp.lock()); |
1061 | if (thread_sp) |
1062 | return thread_sp->GetProcess()->GetUnixSignals()->GetShouldStop(signo: m_value); |
1063 | return false; |
1064 | } |
1065 | |
1066 | bool ShouldStop(Event *event_ptr) override { |
1067 | ThreadSP thread_sp(m_thread_wp.lock()); |
1068 | if (thread_sp) |
1069 | return thread_sp->GetProcess()->GetUnixSignals()->GetShouldStop(signo: m_value); |
1070 | return false; |
1071 | } |
1072 | |
1073 | // If should stop returns false, check if we should notify of this event |
1074 | bool DoShouldNotify(Event *event_ptr) override { |
1075 | ThreadSP thread_sp(m_thread_wp.lock()); |
1076 | if (thread_sp) { |
1077 | bool should_notify = |
1078 | thread_sp->GetProcess()->GetUnixSignals()->GetShouldNotify(signo: m_value); |
1079 | if (should_notify) { |
1080 | StreamString strm; |
1081 | strm.Format( |
1082 | format: "thread {0:d} received signal: {1}" , args: thread_sp->GetIndexID(), |
1083 | args: thread_sp->GetProcess()->GetUnixSignals()->GetSignalAsStringRef( |
1084 | signo: m_value)); |
1085 | Process::ProcessEventData::AddRestartedReason(event_ptr, |
1086 | reason: strm.GetData()); |
1087 | } |
1088 | return should_notify; |
1089 | } |
1090 | return true; |
1091 | } |
1092 | |
1093 | void WillResume(lldb::StateType resume_state) override { |
1094 | ThreadSP thread_sp(m_thread_wp.lock()); |
1095 | if (thread_sp) { |
1096 | if (!thread_sp->GetProcess()->GetUnixSignals()->GetShouldSuppress( |
1097 | signo: m_value)) |
1098 | thread_sp->SetResumeSignal(m_value); |
1099 | } |
1100 | } |
1101 | |
1102 | const char *GetDescription() override { |
1103 | if (m_description.empty()) { |
1104 | ThreadSP thread_sp(m_thread_wp.lock()); |
1105 | if (thread_sp) { |
1106 | UnixSignalsSP unix_signals = thread_sp->GetProcess()->GetUnixSignals(); |
1107 | StreamString strm; |
1108 | strm << "signal " ; |
1109 | |
1110 | std::string signal_name = |
1111 | unix_signals->GetSignalDescription(signo: m_value, code: m_code); |
1112 | if (signal_name.size()) |
1113 | strm << signal_name; |
1114 | else |
1115 | strm.Printf(format: "%" PRIi64, m_value); |
1116 | |
1117 | m_description = std::string(strm.GetString()); |
1118 | } |
1119 | } |
1120 | return m_description.c_str(); |
1121 | } |
1122 | |
1123 | private: |
1124 | // In siginfo_t terms, if m_value is si_signo, m_code is si_code. |
1125 | std::optional<int> m_code; |
1126 | }; |
1127 | |
1128 | // StopInfoTrace |
1129 | |
1130 | class StopInfoTrace : public StopInfo { |
1131 | public: |
1132 | StopInfoTrace(Thread &thread) : StopInfo(thread, LLDB_INVALID_UID) {} |
1133 | |
1134 | ~StopInfoTrace() override = default; |
1135 | |
1136 | StopReason GetStopReason() const override { return eStopReasonTrace; } |
1137 | |
1138 | const char *GetDescription() override { |
1139 | if (m_description.empty()) |
1140 | return "trace" ; |
1141 | else |
1142 | return m_description.c_str(); |
1143 | } |
1144 | }; |
1145 | |
1146 | // StopInfoException |
1147 | |
1148 | class StopInfoException : public StopInfo { |
1149 | public: |
1150 | StopInfoException(Thread &thread, const char *description) |
1151 | : StopInfo(thread, LLDB_INVALID_UID) { |
1152 | if (description) |
1153 | SetDescription(description); |
1154 | } |
1155 | |
1156 | ~StopInfoException() override = default; |
1157 | |
1158 | StopReason GetStopReason() const override { return eStopReasonException; } |
1159 | |
1160 | const char *GetDescription() override { |
1161 | if (m_description.empty()) |
1162 | return "exception" ; |
1163 | else |
1164 | return m_description.c_str(); |
1165 | } |
1166 | }; |
1167 | |
1168 | // StopInfoProcessorTrace |
1169 | |
1170 | class StopInfoProcessorTrace : public StopInfo { |
1171 | public: |
1172 | StopInfoProcessorTrace(Thread &thread, const char *description) |
1173 | : StopInfo(thread, LLDB_INVALID_UID) { |
1174 | if (description) |
1175 | SetDescription(description); |
1176 | } |
1177 | |
1178 | ~StopInfoProcessorTrace() override = default; |
1179 | |
1180 | StopReason GetStopReason() const override { |
1181 | return eStopReasonProcessorTrace; |
1182 | } |
1183 | |
1184 | const char *GetDescription() override { |
1185 | if (m_description.empty()) |
1186 | return "processor trace event" ; |
1187 | else |
1188 | return m_description.c_str(); |
1189 | } |
1190 | }; |
1191 | |
1192 | // StopInfoThreadPlan |
1193 | |
1194 | class StopInfoThreadPlan : public StopInfo { |
1195 | public: |
1196 | StopInfoThreadPlan(ThreadPlanSP &plan_sp, ValueObjectSP &return_valobj_sp, |
1197 | ExpressionVariableSP &expression_variable_sp) |
1198 | : StopInfo(plan_sp->GetThread(), LLDB_INVALID_UID), m_plan_sp(plan_sp), |
1199 | m_return_valobj_sp(return_valobj_sp), |
1200 | m_expression_variable_sp(expression_variable_sp) {} |
1201 | |
1202 | ~StopInfoThreadPlan() override = default; |
1203 | |
1204 | StopReason GetStopReason() const override { return eStopReasonPlanComplete; } |
1205 | |
1206 | const char *GetDescription() override { |
1207 | if (m_description.empty()) { |
1208 | StreamString strm; |
1209 | m_plan_sp->GetDescription(s: &strm, level: eDescriptionLevelBrief); |
1210 | m_description = std::string(strm.GetString()); |
1211 | } |
1212 | return m_description.c_str(); |
1213 | } |
1214 | |
1215 | ValueObjectSP GetReturnValueObject() { return m_return_valobj_sp; } |
1216 | |
1217 | ExpressionVariableSP GetExpressionVariable() { |
1218 | return m_expression_variable_sp; |
1219 | } |
1220 | |
1221 | protected: |
1222 | bool ShouldStop(Event *event_ptr) override { |
1223 | if (m_plan_sp) |
1224 | return m_plan_sp->ShouldStop(event_ptr); |
1225 | else |
1226 | return StopInfo::ShouldStop(event_ptr); |
1227 | } |
1228 | |
1229 | private: |
1230 | ThreadPlanSP m_plan_sp; |
1231 | ValueObjectSP m_return_valobj_sp; |
1232 | ExpressionVariableSP m_expression_variable_sp; |
1233 | }; |
1234 | |
1235 | // StopInfoExec |
1236 | |
1237 | class StopInfoExec : public StopInfo { |
1238 | public: |
1239 | StopInfoExec(Thread &thread) : StopInfo(thread, LLDB_INVALID_UID) {} |
1240 | |
1241 | ~StopInfoExec() override = default; |
1242 | |
1243 | bool ShouldStop(Event *event_ptr) override { |
1244 | ThreadSP thread_sp(m_thread_wp.lock()); |
1245 | if (thread_sp) |
1246 | return thread_sp->GetProcess()->GetStopOnExec(); |
1247 | return false; |
1248 | } |
1249 | |
1250 | StopReason GetStopReason() const override { return eStopReasonExec; } |
1251 | |
1252 | const char *GetDescription() override { return "exec" ; } |
1253 | |
1254 | protected: |
1255 | void PerformAction(Event *event_ptr) override { |
1256 | // Only perform the action once |
1257 | if (m_performed_action) |
1258 | return; |
1259 | m_performed_action = true; |
1260 | ThreadSP thread_sp(m_thread_wp.lock()); |
1261 | if (thread_sp) |
1262 | thread_sp->GetProcess()->DidExec(); |
1263 | } |
1264 | |
1265 | bool m_performed_action = false; |
1266 | }; |
1267 | |
1268 | // StopInfoFork |
1269 | |
1270 | class StopInfoFork : public StopInfo { |
1271 | public: |
1272 | StopInfoFork(Thread &thread, lldb::pid_t child_pid, lldb::tid_t child_tid) |
1273 | : StopInfo(thread, child_pid), m_child_pid(child_pid), |
1274 | m_child_tid(child_tid) {} |
1275 | |
1276 | ~StopInfoFork() override = default; |
1277 | |
1278 | bool ShouldStop(Event *event_ptr) override { return false; } |
1279 | |
1280 | StopReason GetStopReason() const override { return eStopReasonFork; } |
1281 | |
1282 | const char *GetDescription() override { return "fork" ; } |
1283 | |
1284 | protected: |
1285 | void PerformAction(Event *event_ptr) override { |
1286 | // Only perform the action once |
1287 | if (m_performed_action) |
1288 | return; |
1289 | m_performed_action = true; |
1290 | ThreadSP thread_sp(m_thread_wp.lock()); |
1291 | if (thread_sp) |
1292 | thread_sp->GetProcess()->DidFork(child_pid: m_child_pid, child_tid: m_child_tid); |
1293 | } |
1294 | |
1295 | bool m_performed_action = false; |
1296 | |
1297 | private: |
1298 | lldb::pid_t m_child_pid; |
1299 | lldb::tid_t m_child_tid; |
1300 | }; |
1301 | |
1302 | // StopInfoVFork |
1303 | |
1304 | class StopInfoVFork : public StopInfo { |
1305 | public: |
1306 | StopInfoVFork(Thread &thread, lldb::pid_t child_pid, lldb::tid_t child_tid) |
1307 | : StopInfo(thread, child_pid), m_child_pid(child_pid), |
1308 | m_child_tid(child_tid) {} |
1309 | |
1310 | ~StopInfoVFork() override = default; |
1311 | |
1312 | bool ShouldStop(Event *event_ptr) override { return false; } |
1313 | |
1314 | StopReason GetStopReason() const override { return eStopReasonVFork; } |
1315 | |
1316 | const char *GetDescription() override { return "vfork" ; } |
1317 | |
1318 | protected: |
1319 | void PerformAction(Event *event_ptr) override { |
1320 | // Only perform the action once |
1321 | if (m_performed_action) |
1322 | return; |
1323 | m_performed_action = true; |
1324 | ThreadSP thread_sp(m_thread_wp.lock()); |
1325 | if (thread_sp) |
1326 | thread_sp->GetProcess()->DidVFork(child_pid: m_child_pid, child_tid: m_child_tid); |
1327 | } |
1328 | |
1329 | bool m_performed_action = false; |
1330 | |
1331 | private: |
1332 | lldb::pid_t m_child_pid; |
1333 | lldb::tid_t m_child_tid; |
1334 | }; |
1335 | |
1336 | // StopInfoVForkDone |
1337 | |
1338 | class StopInfoVForkDone : public StopInfo { |
1339 | public: |
1340 | StopInfoVForkDone(Thread &thread) : StopInfo(thread, 0) {} |
1341 | |
1342 | ~StopInfoVForkDone() override = default; |
1343 | |
1344 | bool ShouldStop(Event *event_ptr) override { return false; } |
1345 | |
1346 | StopReason GetStopReason() const override { return eStopReasonVForkDone; } |
1347 | |
1348 | const char *GetDescription() override { return "vforkdone" ; } |
1349 | |
1350 | protected: |
1351 | void PerformAction(Event *event_ptr) override { |
1352 | // Only perform the action once |
1353 | if (m_performed_action) |
1354 | return; |
1355 | m_performed_action = true; |
1356 | ThreadSP thread_sp(m_thread_wp.lock()); |
1357 | if (thread_sp) |
1358 | thread_sp->GetProcess()->DidVForkDone(); |
1359 | } |
1360 | |
1361 | bool m_performed_action = false; |
1362 | }; |
1363 | |
1364 | } // namespace lldb_private |
1365 | |
1366 | StopInfoSP StopInfo::CreateStopReasonWithBreakpointSiteID(Thread &thread, |
1367 | break_id_t break_id) { |
1368 | return StopInfoSP(new StopInfoBreakpoint(thread, break_id)); |
1369 | } |
1370 | |
1371 | StopInfoSP StopInfo::CreateStopReasonWithBreakpointSiteID(Thread &thread, |
1372 | break_id_t break_id, |
1373 | bool should_stop) { |
1374 | return StopInfoSP(new StopInfoBreakpoint(thread, break_id, should_stop)); |
1375 | } |
1376 | |
1377 | // LWP_TODO: We'll need a CreateStopReasonWithWatchpointResourceID akin |
1378 | // to CreateStopReasonWithBreakpointSiteID |
1379 | StopInfoSP StopInfo::CreateStopReasonWithWatchpointID(Thread &thread, |
1380 | break_id_t watch_id, |
1381 | bool silently_continue) { |
1382 | return StopInfoSP( |
1383 | new StopInfoWatchpoint(thread, watch_id, silently_continue)); |
1384 | } |
1385 | |
1386 | StopInfoSP StopInfo::CreateStopReasonWithSignal(Thread &thread, int signo, |
1387 | const char *description, |
1388 | std::optional<int> code) { |
1389 | thread.GetProcess()->GetUnixSignals()->IncrementSignalHitCount(signo); |
1390 | return StopInfoSP(new StopInfoUnixSignal(thread, signo, description, code)); |
1391 | } |
1392 | |
1393 | StopInfoSP StopInfo::CreateStopReasonToTrace(Thread &thread) { |
1394 | return StopInfoSP(new StopInfoTrace(thread)); |
1395 | } |
1396 | |
1397 | StopInfoSP StopInfo::CreateStopReasonWithPlan( |
1398 | ThreadPlanSP &plan_sp, ValueObjectSP return_valobj_sp, |
1399 | ExpressionVariableSP expression_variable_sp) { |
1400 | return StopInfoSP(new StopInfoThreadPlan(plan_sp, return_valobj_sp, |
1401 | expression_variable_sp)); |
1402 | } |
1403 | |
1404 | StopInfoSP StopInfo::CreateStopReasonWithException(Thread &thread, |
1405 | const char *description) { |
1406 | return StopInfoSP(new StopInfoException(thread, description)); |
1407 | } |
1408 | |
1409 | StopInfoSP StopInfo::CreateStopReasonProcessorTrace(Thread &thread, |
1410 | const char *description) { |
1411 | return StopInfoSP(new StopInfoProcessorTrace(thread, description)); |
1412 | } |
1413 | |
1414 | StopInfoSP StopInfo::CreateStopReasonWithExec(Thread &thread) { |
1415 | return StopInfoSP(new StopInfoExec(thread)); |
1416 | } |
1417 | |
1418 | StopInfoSP StopInfo::CreateStopReasonFork(Thread &thread, |
1419 | lldb::pid_t child_pid, |
1420 | lldb::tid_t child_tid) { |
1421 | return StopInfoSP(new StopInfoFork(thread, child_pid, child_tid)); |
1422 | } |
1423 | |
1424 | |
1425 | StopInfoSP StopInfo::CreateStopReasonVFork(Thread &thread, |
1426 | lldb::pid_t child_pid, |
1427 | lldb::tid_t child_tid) { |
1428 | return StopInfoSP(new StopInfoVFork(thread, child_pid, child_tid)); |
1429 | } |
1430 | |
1431 | StopInfoSP StopInfo::CreateStopReasonVForkDone(Thread &thread) { |
1432 | return StopInfoSP(new StopInfoVForkDone(thread)); |
1433 | } |
1434 | |
1435 | ValueObjectSP StopInfo::GetReturnValueObject(StopInfoSP &stop_info_sp) { |
1436 | if (stop_info_sp && |
1437 | stop_info_sp->GetStopReason() == eStopReasonPlanComplete) { |
1438 | StopInfoThreadPlan *plan_stop_info = |
1439 | static_cast<StopInfoThreadPlan *>(stop_info_sp.get()); |
1440 | return plan_stop_info->GetReturnValueObject(); |
1441 | } else |
1442 | return ValueObjectSP(); |
1443 | } |
1444 | |
1445 | ExpressionVariableSP StopInfo::GetExpressionVariable(StopInfoSP &stop_info_sp) { |
1446 | if (stop_info_sp && |
1447 | stop_info_sp->GetStopReason() == eStopReasonPlanComplete) { |
1448 | StopInfoThreadPlan *plan_stop_info = |
1449 | static_cast<StopInfoThreadPlan *>(stop_info_sp.get()); |
1450 | return plan_stop_info->GetExpressionVariable(); |
1451 | } else |
1452 | return ExpressionVariableSP(); |
1453 | } |
1454 | |
1455 | lldb::ValueObjectSP |
1456 | StopInfo::GetCrashingDereference(StopInfoSP &stop_info_sp, |
1457 | lldb::addr_t *crashing_address) { |
1458 | if (!stop_info_sp) { |
1459 | return ValueObjectSP(); |
1460 | } |
1461 | |
1462 | const char *description = stop_info_sp->GetDescription(); |
1463 | if (!description) { |
1464 | return ValueObjectSP(); |
1465 | } |
1466 | |
1467 | ThreadSP thread_sp = stop_info_sp->GetThread(); |
1468 | if (!thread_sp) { |
1469 | return ValueObjectSP(); |
1470 | } |
1471 | |
1472 | StackFrameSP frame_sp = |
1473 | thread_sp->GetSelectedFrame(select_most_relevant: DoNoSelectMostRelevantFrame); |
1474 | |
1475 | if (!frame_sp) { |
1476 | return ValueObjectSP(); |
1477 | } |
1478 | |
1479 | const char address_string[] = "address=" ; |
1480 | |
1481 | const char *address_loc = strstr(haystack: description, needle: address_string); |
1482 | if (!address_loc) { |
1483 | return ValueObjectSP(); |
1484 | } |
1485 | |
1486 | address_loc += (sizeof(address_string) - 1); |
1487 | |
1488 | uint64_t address = strtoull(nptr: address_loc, endptr: nullptr, base: 0); |
1489 | if (crashing_address) { |
1490 | *crashing_address = address; |
1491 | } |
1492 | |
1493 | return frame_sp->GuessValueForAddress(addr: address); |
1494 | } |
1495 | |