Bug Summary

File:lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp
Warning:line 639, column 9
Value stored to 'is_actual_breakpoint' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name StopInfoMachException.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/llvm-toolchain-snapshot-14~++20220125101009+ceec4383681c/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-14/lib/clang/14.0.0 -isystem /usr/include/libxml2 -D HAVE_ROUND -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I tools/lldb/source/Plugins/Process/Utility -I /build/llvm-toolchain-snapshot-14~++20220125101009+ceec4383681c/lldb/source/Plugins/Process/Utility -I /build/llvm-toolchain-snapshot-14~++20220125101009+ceec4383681c/lldb/include -I tools/lldb/include -I include -I /build/llvm-toolchain-snapshot-14~++20220125101009+ceec4383681c/llvm/include -I /usr/include/python3.9 -I /build/llvm-toolchain-snapshot-14~++20220125101009+ceec4383681c/clang/include -I tools/lldb/../clang/include -I /build/llvm-toolchain-snapshot-14~++20220125101009+ceec4383681c/lldb/source -I tools/lldb/source -D _FORTIFY_SOURCE=2 -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/llvm-toolchain-snapshot-14~++20220125101009+ceec4383681c/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/llvm-toolchain-snapshot-14~++20220125101009+ceec4383681c/= -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-14~++20220125101009+ceec4383681c/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-14~++20220125101009+ceec4383681c/= -O3 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -Wno-deprecated-declarations -Wno-unknown-pragmas -Wno-strict-aliasing -Wno-deprecated-register -Wno-vla-extension -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-14~++20220125101009+ceec4383681c/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-14~++20220125101009+ceec4383681c/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-14~++20220125101009+ceec4383681c/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-01-25-232935-20746-1 -x c++ /build/llvm-toolchain-snapshot-14~++20220125101009+ceec4383681c/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp
1//===-- StopInfoMachException.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 "StopInfoMachException.h"
10
11#include "lldb/lldb-forward.h"
12
13#if defined(__APPLE__)
14// Needed for the EXC_RESOURCE interpretation macros
15#include <kern/exc_resource.h>
16#endif
17
18#include "lldb/Breakpoint/Watchpoint.h"
19#include "lldb/Symbol/Symbol.h"
20#include "lldb/Target/ABI.h"
21#include "lldb/Target/DynamicLoader.h"
22#include "lldb/Target/ExecutionContext.h"
23#include "lldb/Target/Process.h"
24#include "lldb/Target/RegisterContext.h"
25#include "lldb/Target/Target.h"
26#include "lldb/Target/Thread.h"
27#include "lldb/Target/ThreadPlan.h"
28#include "lldb/Target/UnixSignals.h"
29#include "lldb/Utility/StreamString.h"
30
31using namespace lldb;
32using namespace lldb_private;
33
34/// Information about a pointer-authentication related instruction.
35struct PtrauthInstructionInfo {
36 bool IsAuthenticated;
37 bool IsLoad;
38 bool DoesBranch;
39};
40
41/// Get any pointer-authentication related information about the instruction
42/// at address \p at_addr.
43static llvm::Optional<PtrauthInstructionInfo>
44GetPtrauthInstructionInfo(Target &target, const ArchSpec &arch,
45 const Address &at_addr) {
46 const char *plugin_name = nullptr;
47 const char *flavor = nullptr;
48 AddressRange range_bounds(at_addr, 4);
49 const bool prefer_file_cache = true;
50 DisassemblerSP disassembler_sp = Disassembler::DisassembleRange(
51 arch, plugin_name, flavor, target, range_bounds, prefer_file_cache);
52 if (!disassembler_sp)
53 return llvm::None;
54
55 InstructionList &insn_list = disassembler_sp->GetInstructionList();
56 InstructionSP insn = insn_list.GetInstructionAtIndex(0);
57 if (!insn)
58 return llvm::None;
59
60 return PtrauthInstructionInfo{insn->IsAuthenticated(), insn->IsLoad(),
61 insn->DoesBranch()};
62}
63
64/// Describe the load address of \p addr using the format filename:line:col.
65static void DescribeAddressBriefly(Stream &strm, const Address &addr,
66 Target &target) {
67 strm.Printf("at address=0x%" PRIx64"l" "x", addr.GetLoadAddress(&target));
68 StreamString s;
69 if (addr.GetDescription(s, target, eDescriptionLevelBrief))
70 strm.Printf(" %s", s.GetString().data());
71 strm.Printf(".\n");
72}
73
74bool StopInfoMachException::DeterminePtrauthFailure(ExecutionContext &exe_ctx) {
75 bool IsBreakpoint = m_value == 6; // EXC_BREAKPOINT
76 bool IsBadAccess = m_value == 1; // EXC_BAD_ACCESS
77 if (!IsBreakpoint && !IsBadAccess)
78 return false;
79
80 // Check that we have a live process.
81 if (!exe_ctx.HasProcessScope() || !exe_ctx.HasThreadScope() ||
82 !exe_ctx.HasTargetScope())
83 return false;
84
85 Thread &thread = *exe_ctx.GetThreadPtr();
86 StackFrameSP current_frame = thread.GetStackFrameAtIndex(0);
87 if (!current_frame)
88 return false;
89
90 Target &target = *exe_ctx.GetTargetPtr();
91 Process &process = *exe_ctx.GetProcessPtr();
92 ABISP abi_sp = process.GetABI();
93 const ArchSpec &arch = target.GetArchitecture();
94 assert(abi_sp && "Missing ABI info")(static_cast <bool> (abi_sp && "Missing ABI info"
) ? void (0) : __assert_fail ("abi_sp && \"Missing ABI info\""
, "lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp"
, 94, __extension__ __PRETTY_FUNCTION__))
;
95
96 // Check for a ptrauth-enabled target.
97 const bool ptrauth_enabled_target =
98 arch.GetCore() == ArchSpec::eCore_arm_arm64e;
99 if (!ptrauth_enabled_target)
100 return false;
101
102 // Set up a stream we can write a diagnostic into.
103 StreamString strm;
104 auto emit_ptrauth_prologue = [&](uint64_t at_address) {
105 strm.Printf("EXC_BAD_ACCESS (code=%" PRIu64"l" "u" ", address=0x%" PRIx64"l" "x" ")\n",
106 m_exc_code, at_address);
107 strm.Printf("Note: Possible pointer authentication failure detected.\n");
108 };
109
110 // Check if we have a "brk 0xc47x" trap, where the value that failed to
111 // authenticate is in x16.
112 Address current_address = current_frame->GetFrameCodeAddress();
113 if (IsBreakpoint) {
114 RegisterContext *reg_ctx = exe_ctx.GetRegisterContext();
115 if (!reg_ctx)
116 return false;
117
118 const RegisterInfo *X16Info = reg_ctx->GetRegisterInfoByName("x16");
119 RegisterValue X16Val;
120 if (!reg_ctx->ReadRegister(X16Info, X16Val))
121 return false;
122 uint64_t bad_address = X16Val.GetAsUInt64();
123
124 uint64_t fixed_bad_address = abi_sp->FixCodeAddress(bad_address);
125 Address brk_address;
126 if (!target.ResolveLoadAddress(fixed_bad_address, brk_address))
127 return false;
128
129 auto brk_ptrauth_info =
130 GetPtrauthInstructionInfo(target, arch, current_address);
131 if (brk_ptrauth_info && brk_ptrauth_info->IsAuthenticated) {
132 emit_ptrauth_prologue(bad_address);
133 strm.Printf("Found value that failed to authenticate ");
134 DescribeAddressBriefly(strm, brk_address, target);
135 m_description = std::string(strm.GetString());
136 return true;
137 }
138 return false;
139 }
140
141 assert(IsBadAccess && "Handle EXC_BAD_ACCESS only after this point")(static_cast <bool> (IsBadAccess && "Handle EXC_BAD_ACCESS only after this point"
) ? void (0) : __assert_fail ("IsBadAccess && \"Handle EXC_BAD_ACCESS only after this point\""
, "lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp"
, 141, __extension__ __PRETTY_FUNCTION__))
;
142
143 // Check that we have the "bad address" from an EXC_BAD_ACCESS.
144 if (m_exc_data_count < 2)
145 return false;
146
147 // Ok, we know the Target is valid and that it describes a ptrauth-enabled
148 // device. Now, we need to determine whether this exception was caused by a
149 // ptrauth failure.
150
151 uint64_t bad_address = m_exc_subcode;
152 uint64_t fixed_bad_address = abi_sp->FixCodeAddress(bad_address);
153 uint64_t current_pc = current_address.GetLoadAddress(&target);
154
155 // Detect: LDRAA, LDRAB (Load Register, with pointer authentication).
156 //
157 // If an authenticated load results in an exception, the instruction at the
158 // current PC should be one of LDRAx.
159 if (bad_address != current_pc && fixed_bad_address != current_pc) {
160 auto ptrauth_info =
161 GetPtrauthInstructionInfo(target, arch, current_address);
162 if (ptrauth_info && ptrauth_info->IsAuthenticated && ptrauth_info->IsLoad) {
163 emit_ptrauth_prologue(bad_address);
164 strm.Printf("Found authenticated load instruction ");
165 DescribeAddressBriefly(strm, current_address, target);
166 m_description = std::string(strm.GetString());
167 return true;
168 }
169 }
170
171 // Detect: BLRAA, BLRAAZ, BLRAB, BLRABZ (Branch with Link to Register, with
172 // pointer authentication).
173 //
174 // TODO: Detect: BRAA, BRAAZ, BRAB, BRABZ (Branch to Register, with pointer
175 // authentication). At a minimum, this requires call site info support for
176 // indirect calls.
177 //
178 // If an authenticated call or tail call results in an exception, stripping
179 // the bad address should give the current PC, which points to the address
180 // we tried to branch to.
181 if (bad_address != current_pc && fixed_bad_address == current_pc) {
182 if (StackFrameSP parent_frame = thread.GetStackFrameAtIndex(1)) {
183 addr_t return_pc =
184 parent_frame->GetFrameCodeAddress().GetLoadAddress(&target);
185 Address blr_address;
186 if (!target.ResolveLoadAddress(return_pc - 4, blr_address))
187 return false;
188
189 auto blr_ptrauth_info =
190 GetPtrauthInstructionInfo(target, arch, blr_address);
191 if (blr_ptrauth_info && blr_ptrauth_info->IsAuthenticated &&
192 blr_ptrauth_info->DoesBranch) {
193 emit_ptrauth_prologue(bad_address);
194 strm.Printf("Found authenticated indirect branch ");
195 DescribeAddressBriefly(strm, blr_address, target);
196 m_description = std::string(strm.GetString());
197 return true;
198 }
199 }
200 }
201
202 // TODO: Detect: RETAA, RETAB (Return from subroutine, with pointer
203 // authentication).
204 //
205 // Is there a motivating, non-malicious code snippet that corrupts LR?
206
207 return false;
208}
209
210const char *StopInfoMachException::GetDescription() {
211 if (!m_description.empty())
212 return m_description.c_str();
213 if (GetValue() == eStopReasonInvalid)
214 return "invalid stop reason!";
215
216 ExecutionContext exe_ctx(m_thread_wp.lock());
217 Target *target = exe_ctx.GetTargetPtr();
218 const llvm::Triple::ArchType cpu =
219 target ? target->GetArchitecture().GetMachine()
220 : llvm::Triple::UnknownArch;
221
222 const char *exc_desc = nullptr;
223 const char *code_label = "code";
224 const char *code_desc = nullptr;
225 const char *subcode_label = "subcode";
226 const char *subcode_desc = nullptr;
227
228#if defined(__APPLE__)
229 char code_desc_buf[32];
230 char subcode_desc_buf[32];
231#endif
232
233 switch (m_value) {
234 case 1: // EXC_BAD_ACCESS
235 exc_desc = "EXC_BAD_ACCESS";
236 subcode_label = "address";
237 switch (cpu) {
238 case llvm::Triple::x86:
239 case llvm::Triple::x86_64:
240 switch (m_exc_code) {
241 case 0xd:
242 code_desc = "EXC_I386_GPFLT";
243 m_exc_data_count = 1;
244 break;
245 }
246 break;
247 case llvm::Triple::arm:
248 case llvm::Triple::thumb:
249 switch (m_exc_code) {
250 case 0x101:
251 code_desc = "EXC_ARM_DA_ALIGN";
252 break;
253 case 0x102:
254 code_desc = "EXC_ARM_DA_DEBUG";
255 break;
256 }
257 break;
258
259 case llvm::Triple::aarch64:
260 if (DeterminePtrauthFailure(exe_ctx))
261 return m_description.c_str();
262 break;
263
264 default:
265 break;
266 }
267 break;
268
269 case 2: // EXC_BAD_INSTRUCTION
270 exc_desc = "EXC_BAD_INSTRUCTION";
271 switch (cpu) {
272 case llvm::Triple::x86:
273 case llvm::Triple::x86_64:
274 if (m_exc_code == 1)
275 code_desc = "EXC_I386_INVOP";
276 break;
277
278 case llvm::Triple::arm:
279 case llvm::Triple::thumb:
280 if (m_exc_code == 1)
281 code_desc = "EXC_ARM_UNDEFINED";
282 break;
283
284 default:
285 break;
286 }
287 break;
288
289 case 3: // EXC_ARITHMETIC
290 exc_desc = "EXC_ARITHMETIC";
291 switch (cpu) {
292 case llvm::Triple::x86:
293 case llvm::Triple::x86_64:
294 switch (m_exc_code) {
295 case 1:
296 code_desc = "EXC_I386_DIV";
297 break;
298 case 2:
299 code_desc = "EXC_I386_INTO";
300 break;
301 case 3:
302 code_desc = "EXC_I386_NOEXT";
303 break;
304 case 4:
305 code_desc = "EXC_I386_EXTOVR";
306 break;
307 case 5:
308 code_desc = "EXC_I386_EXTERR";
309 break;
310 case 6:
311 code_desc = "EXC_I386_EMERR";
312 break;
313 case 7:
314 code_desc = "EXC_I386_BOUND";
315 break;
316 case 8:
317 code_desc = "EXC_I386_SSEEXTERR";
318 break;
319 }
320 break;
321
322 default:
323 break;
324 }
325 break;
326
327 case 4: // EXC_EMULATION
328 exc_desc = "EXC_EMULATION";
329 break;
330
331 case 5: // EXC_SOFTWARE
332 exc_desc = "EXC_SOFTWARE";
333 if (m_exc_code == 0x10003) {
334 subcode_desc = "EXC_SOFT_SIGNAL";
335 subcode_label = "signo";
336 }
337 break;
338
339 case 6: // EXC_BREAKPOINT
340 {
341 exc_desc = "EXC_BREAKPOINT";
342 switch (cpu) {
343 case llvm::Triple::x86:
344 case llvm::Triple::x86_64:
345 switch (m_exc_code) {
346 case 1:
347 code_desc = "EXC_I386_SGL";
348 break;
349 case 2:
350 code_desc = "EXC_I386_BPT";
351 break;
352 }
353 break;
354
355 case llvm::Triple::arm:
356 case llvm::Triple::thumb:
357 switch (m_exc_code) {
358 case 0x101:
359 code_desc = "EXC_ARM_DA_ALIGN";
360 break;
361 case 0x102:
362 code_desc = "EXC_ARM_DA_DEBUG";
363 break;
364 case 1:
365 code_desc = "EXC_ARM_BREAKPOINT";
366 break;
367 // FIXME temporary workaround, exc_code 0 does not really mean
368 // EXC_ARM_BREAKPOINT
369 case 0:
370 code_desc = "EXC_ARM_BREAKPOINT";
371 break;
372 }
373 break;
374
375 case llvm::Triple::aarch64:
376 if (DeterminePtrauthFailure(exe_ctx))
377 return m_description.c_str();
378 break;
379
380 default:
381 break;
382 }
383 } break;
384
385 case 7:
386 exc_desc = "EXC_SYSCALL";
387 break;
388
389 case 8:
390 exc_desc = "EXC_MACH_SYSCALL";
391 break;
392
393 case 9:
394 exc_desc = "EXC_RPC_ALERT";
395 break;
396
397 case 10:
398 exc_desc = "EXC_CRASH";
399 break;
400 case 11:
401 exc_desc = "EXC_RESOURCE";
402#if defined(__APPLE__)
403 {
404 int resource_type = EXC_RESOURCE_DECODE_RESOURCE_TYPE(m_exc_code);
405
406 code_label = "limit";
407 code_desc = code_desc_buf;
408 subcode_label = "observed";
409 subcode_desc = subcode_desc_buf;
410
411 switch (resource_type) {
412 case RESOURCE_TYPE_CPU:
413 exc_desc = "EXC_RESOURCE RESOURCE_TYPE_CPU";
414 snprintf(code_desc_buf, sizeof(code_desc_buf), "%d%%",
415 (int)EXC_RESOURCE_CPUMONITOR_DECODE_PERCENTAGE(m_exc_code));
416 snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d%%",
417 (int)EXC_RESOURCE_CPUMONITOR_DECODE_PERCENTAGE_OBSERVED(
418 m_exc_subcode));
419 break;
420 case RESOURCE_TYPE_WAKEUPS:
421 exc_desc = "EXC_RESOURCE RESOURCE_TYPE_WAKEUPS";
422 snprintf(
423 code_desc_buf, sizeof(code_desc_buf), "%d w/s",
424 (int)EXC_RESOURCE_CPUMONITOR_DECODE_WAKEUPS_PERMITTED(m_exc_code));
425 snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d w/s",
426 (int)EXC_RESOURCE_CPUMONITOR_DECODE_WAKEUPS_OBSERVED(
427 m_exc_subcode));
428 break;
429 case RESOURCE_TYPE_MEMORY:
430 exc_desc = "EXC_RESOURCE RESOURCE_TYPE_MEMORY";
431 snprintf(code_desc_buf, sizeof(code_desc_buf), "%d MB",
432 (int)EXC_RESOURCE_HWM_DECODE_LIMIT(m_exc_code));
433 subcode_desc = nullptr;
434 subcode_label = "unused";
435 break;
436#if defined(RESOURCE_TYPE_IO)
437 // RESOURCE_TYPE_IO is introduced in macOS SDK 10.12.
438 case RESOURCE_TYPE_IO:
439 exc_desc = "EXC_RESOURCE RESOURCE_TYPE_IO";
440 snprintf(code_desc_buf, sizeof(code_desc_buf), "%d MB",
441 (int)EXC_RESOURCE_IO_DECODE_LIMIT(m_exc_code));
442 snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d MB",
443 (int)EXC_RESOURCE_IO_OBSERVED(m_exc_subcode));
444 ;
445 break;
446#endif
447 }
448 }
449#endif
450 break;
451 case 12:
452 exc_desc = "EXC_GUARD";
453 break;
454 }
455
456 StreamString strm;
457
458 if (exc_desc)
459 strm.PutCString(exc_desc);
460 else
461 strm.Printf("EXC_??? (%" PRIu64"l" "u" ")", m_value);
462
463 if (m_exc_data_count >= 1) {
464 if (code_desc)
465 strm.Printf(" (%s=%s", code_label, code_desc);
466 else
467 strm.Printf(" (%s=%" PRIu64"l" "u", code_label, m_exc_code);
468 }
469
470 if (m_exc_data_count >= 2) {
471 if (subcode_desc)
472 strm.Printf(", %s=%s", subcode_label, subcode_desc);
473 else
474 strm.Printf(", %s=0x%" PRIx64"l" "x", subcode_label, m_exc_subcode);
475 }
476
477 if (m_exc_data_count > 0)
478 strm.PutChar(')');
479
480 m_description = std::string(strm.GetString());
481 return m_description.c_str();
482}
483
484static StopInfoSP GetStopInfoForHardwareBP(Thread &thread, Target *target,
485 uint32_t exc_data_count,
486 uint64_t exc_sub_code,
487 uint64_t exc_sub_sub_code) {
488 // Try hardware watchpoint.
489 if (target) {
490 // The exc_sub_code indicates the data break address.
491 lldb::WatchpointSP wp_sp =
492 target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code);
493 if (wp_sp && wp_sp->IsEnabled()) {
494 // Debugserver may piggyback the hardware index of the fired watchpoint
495 // in the exception data. Set the hardware index if that's the case.
496 if (exc_data_count >= 3)
497 wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
498 return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID());
499 }
500 }
501
502 // Try hardware breakpoint.
503 ProcessSP process_sp(thread.GetProcess());
504 if (process_sp) {
505 // The exc_sub_code indicates the data break address.
506 lldb::BreakpointSiteSP bp_sp =
507 process_sp->GetBreakpointSiteList().FindByAddress(
508 (lldb::addr_t)exc_sub_code);
509 if (bp_sp && bp_sp->IsEnabled()) {
510 // Debugserver may piggyback the hardware index of the fired breakpoint
511 // in the exception data. Set the hardware index if that's the case.
512 if (exc_data_count >= 3)
513 bp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
514 return StopInfo::CreateStopReasonWithBreakpointSiteID(thread,
515 bp_sp->GetID());
516 }
517 }
518
519 return nullptr;
520}
521
522StopInfoSP StopInfoMachException::CreateStopReasonWithMachException(
523 Thread &thread, uint32_t exc_type, uint32_t exc_data_count,
524 uint64_t exc_code, uint64_t exc_sub_code, uint64_t exc_sub_sub_code,
525 bool pc_already_adjusted, bool adjust_pc_if_needed) {
526 if (exc_type == 0)
527 return StopInfoSP();
528
529 uint32_t pc_decrement = 0;
530 ExecutionContext exe_ctx(thread.shared_from_this());
531 Target *target = exe_ctx.GetTargetPtr();
532 const llvm::Triple::ArchType cpu =
533 target ? target->GetArchitecture().GetMachine()
534 : llvm::Triple::UnknownArch;
535
536 switch (exc_type) {
537 case 1: // EXC_BAD_ACCESS
538 case 2: // EXC_BAD_INSTRUCTION
539 case 3: // EXC_ARITHMETIC
540 case 4: // EXC_EMULATION
541 break;
542
543 case 5: // EXC_SOFTWARE
544 if (exc_code == 0x10003) // EXC_SOFT_SIGNAL
545 {
546 if (exc_sub_code == 5) {
547 // On MacOSX, a SIGTRAP can signify that a process has called exec,
548 // so we should check with our dynamic loader to verify.
549 ProcessSP process_sp(thread.GetProcess());
550 if (process_sp) {
551 DynamicLoader *dynamic_loader = process_sp->GetDynamicLoader();
552 if (dynamic_loader && dynamic_loader->ProcessDidExec()) {
553 // The program was re-exec'ed
554 return StopInfo::CreateStopReasonWithExec(thread);
555 }
556 }
557 }
558 return StopInfo::CreateStopReasonWithSignal(thread, exc_sub_code);
559 }
560 break;
561
562 case 6: // EXC_BREAKPOINT
563 {
564 bool is_actual_breakpoint = false;
565 bool is_trace_if_actual_breakpoint_missing = false;
566 switch (cpu) {
567 case llvm::Triple::x86:
568 case llvm::Triple::x86_64:
569 if (exc_code == 1) // EXC_I386_SGL
570 {
571 if (!exc_sub_code) {
572 // This looks like a plain trap.
573 // Have to check if there is a breakpoint here as well. When you
574 // single-step onto a trap, the single step stops you not to trap.
575 // Since we also do that check below, let's just use that logic.
576 is_actual_breakpoint = true;
577 is_trace_if_actual_breakpoint_missing = true;
578 } else {
579 if (StopInfoSP stop_info =
580 GetStopInfoForHardwareBP(thread, target, exc_data_count,
581 exc_sub_code, exc_sub_sub_code))
582 return stop_info;
583 }
584 } else if (exc_code == 2 || // EXC_I386_BPT
585 exc_code == 3) // EXC_I386_BPTFLT
586 {
587 // KDP returns EXC_I386_BPTFLT for trace breakpoints
588 if (exc_code == 3)
589 is_trace_if_actual_breakpoint_missing = true;
590
591 is_actual_breakpoint = true;
592 if (!pc_already_adjusted)
593 pc_decrement = 1;
594 }
595 break;
596
597 case llvm::Triple::arm:
598 case llvm::Triple::thumb:
599 if (exc_code == 0x102) // EXC_ARM_DA_DEBUG
600 {
601 // It's a watchpoint, then, if the exc_sub_code indicates a
602 // known/enabled data break address from our watchpoint list.
603 lldb::WatchpointSP wp_sp;
604 if (target)
605 wp_sp = target->GetWatchpointList().FindByAddress(
606 (lldb::addr_t)exc_sub_code);
607 if (wp_sp && wp_sp->IsEnabled()) {
608 // Debugserver may piggyback the hardware index of the fired
609 // watchpoint in the exception data. Set the hardware index if
610 // that's the case.
611 if (exc_data_count >= 3)
612 wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
613 return StopInfo::CreateStopReasonWithWatchpointID(thread,
614 wp_sp->GetID());
615 } else {
616 is_actual_breakpoint = true;
617 is_trace_if_actual_breakpoint_missing = true;
618 }
619 } else if (exc_code == 1) // EXC_ARM_BREAKPOINT
620 {
621 is_actual_breakpoint = true;
622 is_trace_if_actual_breakpoint_missing = true;
623 } else if (exc_code == 0) // FIXME not EXC_ARM_BREAKPOINT but a kernel
624 // is currently returning this so accept it
625 // as indicating a breakpoint until the
626 // kernel is fixed
627 {
628 is_actual_breakpoint = true;
629 is_trace_if_actual_breakpoint_missing = true;
630 }
631 break;
632
633 case llvm::Triple::aarch64_32:
634 case llvm::Triple::aarch64: {
635 if (exc_code == 1 && exc_sub_code == 0) // EXC_ARM_BREAKPOINT
636 {
637 // This is hit when we single instruction step aka MDSCR_EL1 SS bit 0
638 // is set
639 is_actual_breakpoint = false;
Value stored to 'is_actual_breakpoint' is never read
640 is_trace_if_actual_breakpoint_missing = true;
641 }
642 if (exc_code == 0x102) // EXC_ARM_DA_DEBUG
643 {
644 // It's a watchpoint, then, if the exc_sub_code indicates a
645 // known/enabled data break address from our watchpoint list.
646 lldb::WatchpointSP wp_sp;
647 if (target)
648 wp_sp = target->GetWatchpointList().FindByAddress(
649 (lldb::addr_t)exc_sub_code);
650 if (wp_sp && wp_sp->IsEnabled()) {
651 // Debugserver may piggyback the hardware index of the fired
652 // watchpoint in the exception data. Set the hardware index if
653 // that's the case.
654 if (exc_data_count >= 3)
655 wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
656 return StopInfo::CreateStopReasonWithWatchpointID(thread,
657 wp_sp->GetID());
658 }
659 // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as
660 // EXC_BAD_ACCESS
661 if (thread.GetTemporaryResumeState() == eStateStepping)
662 return StopInfo::CreateStopReasonToTrace(thread);
663 }
664 // It looks like exc_sub_code has the 4 bytes of the instruction that
665 // triggered the exception, i.e. our breakpoint opcode
666 is_actual_breakpoint = exc_code == 1;
667 break;
668 }
669
670 default:
671 break;
672 }
673
674 if (is_actual_breakpoint) {
675 RegisterContextSP reg_ctx_sp(thread.GetRegisterContext());
676 addr_t pc = reg_ctx_sp->GetPC() - pc_decrement;
677
678 ProcessSP process_sp(thread.CalculateProcess());
679
680 lldb::BreakpointSiteSP bp_site_sp;
681 if (process_sp)
682 bp_site_sp = process_sp->GetBreakpointSiteList().FindByAddress(pc);
683 if (bp_site_sp && bp_site_sp->IsEnabled()) {
684 // Update the PC if we were asked to do so, but only do so if we find
685 // a breakpoint that we know about cause this could be a trap
686 // instruction in the code
687 if (pc_decrement > 0 && adjust_pc_if_needed)
688 reg_ctx_sp->SetPC(pc);
689
690 // If the breakpoint is for this thread, then we'll report the hit,
691 // but if it is for another thread, we can just report no reason. We
692 // don't need to worry about stepping over the breakpoint here, that
693 // will be taken care of when the thread resumes and notices that
694 // there's a breakpoint under the pc. If we have an operating system
695 // plug-in, we might have set a thread specific breakpoint using the
696 // operating system thread ID, so we can't make any assumptions about
697 // the thread ID so we must always report the breakpoint regardless
698 // of the thread.
699 if (bp_site_sp->ValidForThisThread(thread) ||
700 thread.GetProcess()->GetOperatingSystem() != nullptr)
701 return StopInfo::CreateStopReasonWithBreakpointSiteID(
702 thread, bp_site_sp->GetID());
703 else if (is_trace_if_actual_breakpoint_missing)
704 return StopInfo::CreateStopReasonToTrace(thread);
705 else
706 return StopInfoSP();
707 }
708
709 // Don't call this a trace if we weren't single stepping this thread.
710 if (is_trace_if_actual_breakpoint_missing &&
711 thread.GetTemporaryResumeState() == eStateStepping) {
712 return StopInfo::CreateStopReasonToTrace(thread);
713 }
714 }
715 } break;
716
717 case 7: // EXC_SYSCALL
718 case 8: // EXC_MACH_SYSCALL
719 case 9: // EXC_RPC_ALERT
720 case 10: // EXC_CRASH
721 break;
722 }
723
724 return StopInfoSP(new StopInfoMachException(thread, exc_type, exc_data_count,
725 exc_code, exc_sub_code));
726}