Bug Summary

File:build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp
Warning:line 714, 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-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-16~++20221003111214+1fa2019828ca/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-16/lib/clang/16.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-16~++20221003111214+1fa2019828ca/lldb/source/Plugins/Process/Utility -I /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/lldb/include -I tools/lldb/include -I include -I /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/llvm/include -I /usr/include/python3.9 -I /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/clang/include -I tools/lldb/../clang/include -I /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/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-16/lib/clang/16.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-16~++20221003111214+1fa2019828ca/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/= -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/= -O2 -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-misleading-indentation -Wno-deprecated-declarations -Wno-unknown-pragmas -Wno-strict-aliasing -Wno-stringop-truncation -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/= -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-10-03-140002-15933-1 -x c++ /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/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 =
414 "EXC_RESOURCE (RESOURCE_TYPE_CPU: CPU usage monitor tripped)";
415 snprintf(code_desc_buf, sizeof(code_desc_buf), "%d%%",
416 (int)EXC_RESOURCE_CPUMONITOR_DECODE_PERCENTAGE(m_exc_code));
417 snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d%%",
418 (int)EXC_RESOURCE_CPUMONITOR_DECODE_PERCENTAGE_OBSERVED(
419 m_exc_subcode));
420 break;
421 case RESOURCE_TYPE_WAKEUPS:
422 exc_desc = "EXC_RESOURCE (RESOURCE_TYPE_WAKEUPS: idle wakeups monitor "
423 "tripped)";
424 snprintf(
425 code_desc_buf, sizeof(code_desc_buf), "%d w/s",
426 (int)EXC_RESOURCE_CPUMONITOR_DECODE_WAKEUPS_PERMITTED(m_exc_code));
427 snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d w/s",
428 (int)EXC_RESOURCE_CPUMONITOR_DECODE_WAKEUPS_OBSERVED(
429 m_exc_subcode));
430 break;
431 case RESOURCE_TYPE_MEMORY:
432 exc_desc = "EXC_RESOURCE (RESOURCE_TYPE_MEMORY: high watermark memory "
433 "limit exceeded)";
434 snprintf(code_desc_buf, sizeof(code_desc_buf), "%d MB",
435 (int)EXC_RESOURCE_HWM_DECODE_LIMIT(m_exc_code));
436 subcode_desc = nullptr;
437 subcode_label = nullptr;
438 break;
439#if defined(RESOURCE_TYPE_IO)
440 // RESOURCE_TYPE_IO is introduced in macOS SDK 10.12.
441 case RESOURCE_TYPE_IO:
442 exc_desc = "EXC_RESOURCE RESOURCE_TYPE_IO";
443 snprintf(code_desc_buf, sizeof(code_desc_buf), "%d MB",
444 (int)EXC_RESOURCE_IO_DECODE_LIMIT(m_exc_code));
445 snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d MB",
446 (int)EXC_RESOURCE_IO_OBSERVED(m_exc_subcode));
447 ;
448 break;
449#endif
450 }
451 }
452#endif
453 break;
454 case 12:
455 exc_desc = "EXC_GUARD";
456 break;
457 }
458
459 StreamString strm;
460
461 if (exc_desc)
462 strm.PutCString(exc_desc);
463 else
464 strm.Printf("EXC_??? (%" PRIu64"l" "u" ")", m_value);
465
466 if (m_exc_data_count >= 1) {
467 if (code_desc)
468 strm.Printf(" (%s=%s", code_label, code_desc);
469 else
470 strm.Printf(" (%s=%" PRIu64"l" "u", code_label, m_exc_code);
471 }
472
473 if (m_exc_data_count >= 2) {
474 if (subcode_label && subcode_desc)
475 strm.Printf(", %s=%s", subcode_label, subcode_desc);
476 else if (subcode_label)
477 strm.Printf(", %s=0x%" PRIx64"l" "x", subcode_label, m_exc_subcode);
478 }
479
480 if (m_exc_data_count > 0)
481 strm.PutChar(')');
482
483 m_description = std::string(strm.GetString());
484 return m_description.c_str();
485}
486
487static StopInfoSP GetStopInfoForHardwareBP(Thread &thread, Target *target,
488 uint32_t exc_data_count,
489 uint64_t exc_sub_code,
490 uint64_t exc_sub_sub_code) {
491 // Try hardware watchpoint.
492 if (target) {
493 // The exc_sub_code indicates the data break address.
494 lldb::WatchpointSP wp_sp =
495 target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code);
496 if (wp_sp && wp_sp->IsEnabled()) {
497 // Debugserver may piggyback the hardware index of the fired watchpoint
498 // in the exception data. Set the hardware index if that's the case.
499 if (exc_data_count >= 3)
500 wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
501 return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID());
502 }
503 }
504
505 // Try hardware breakpoint.
506 ProcessSP process_sp(thread.GetProcess());
507 if (process_sp) {
508 // The exc_sub_code indicates the data break address.
509 lldb::BreakpointSiteSP bp_sp =
510 process_sp->GetBreakpointSiteList().FindByAddress(
511 (lldb::addr_t)exc_sub_code);
512 if (bp_sp && bp_sp->IsEnabled()) {
513 // Debugserver may piggyback the hardware index of the fired breakpoint
514 // in the exception data. Set the hardware index if that's the case.
515 if (exc_data_count >= 3)
516 bp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
517 return StopInfo::CreateStopReasonWithBreakpointSiteID(thread,
518 bp_sp->GetID());
519 }
520 }
521
522 return nullptr;
523}
524
525#if defined(__APPLE__)
526const char *
527StopInfoMachException::MachException::Name(exception_type_t exc_type) {
528 switch (exc_type) {
529 case EXC_BAD_ACCESS:
530 return "EXC_BAD_ACCESS";
531 case EXC_BAD_INSTRUCTION:
532 return "EXC_BAD_INSTRUCTION";
533 case EXC_ARITHMETIC:
534 return "EXC_ARITHMETIC";
535 case EXC_EMULATION:
536 return "EXC_EMULATION";
537 case EXC_SOFTWARE:
538 return "EXC_SOFTWARE";
539 case EXC_BREAKPOINT:
540 return "EXC_BREAKPOINT";
541 case EXC_SYSCALL:
542 return "EXC_SYSCALL";
543 case EXC_MACH_SYSCALL:
544 return "EXC_MACH_SYSCALL";
545 case EXC_RPC_ALERT:
546 return "EXC_RPC_ALERT";
547#ifdef EXC_CRASH
548 case EXC_CRASH:
549 return "EXC_CRASH";
550#endif
551 case EXC_RESOURCE:
552 return "EXC_RESOURCE";
553#ifdef EXC_GUARD
554 case EXC_GUARD:
555 return "EXC_GUARD";
556#endif
557#ifdef EXC_CORPSE_NOTIFY
558 case EXC_CORPSE_NOTIFY:
559 return "EXC_CORPSE_NOTIFY";
560#endif
561#ifdef EXC_CORPSE_VARIANT_BIT
562 case EXC_CORPSE_VARIANT_BIT:
563 return "EXC_CORPSE_VARIANT_BIT";
564#endif
565 default:
566 break;
567 }
568 return NULL__null;
569}
570
571llvm::Optional<exception_type_t>
572StopInfoMachException::MachException::ExceptionCode(const char *name) {
573 return llvm::StringSwitch<llvm::Optional<exception_type_t>>(name)
574 .Case("EXC_BAD_ACCESS", EXC_BAD_ACCESS)
575 .Case("EXC_BAD_INSTRUCTION", EXC_BAD_INSTRUCTION)
576 .Case("EXC_ARITHMETIC", EXC_ARITHMETIC)
577 .Case("EXC_EMULATION", EXC_EMULATION)
578 .Case("EXC_SOFTWARE", EXC_SOFTWARE)
579 .Case("EXC_BREAKPOINT", EXC_BREAKPOINT)
580 .Case("EXC_SYSCALL", EXC_SYSCALL)
581 .Case("EXC_MACH_SYSCALL", EXC_MACH_SYSCALL)
582 .Case("EXC_RPC_ALERT", EXC_RPC_ALERT)
583#ifdef EXC_CRASH
584 .Case("EXC_CRASH", EXC_CRASH)
585#endif
586 .Case("EXC_RESOURCE", EXC_RESOURCE)
587#ifdef EXC_GUARD
588 .Case("EXC_GUARD", EXC_GUARD)
589#endif
590#ifdef EXC_CORPSE_NOTIFY
591 .Case("EXC_CORPSE_NOTIFY", EXC_CORPSE_NOTIFY)
592#endif
593 .Default(llvm::None);
594}
595#endif
596
597StopInfoSP StopInfoMachException::CreateStopReasonWithMachException(
598 Thread &thread, uint32_t exc_type, uint32_t exc_data_count,
599 uint64_t exc_code, uint64_t exc_sub_code, uint64_t exc_sub_sub_code,
600 bool pc_already_adjusted, bool adjust_pc_if_needed) {
601 if (exc_type == 0)
602 return StopInfoSP();
603
604 uint32_t pc_decrement = 0;
605 ExecutionContext exe_ctx(thread.shared_from_this());
606 Target *target = exe_ctx.GetTargetPtr();
607 const llvm::Triple::ArchType cpu =
608 target ? target->GetArchitecture().GetMachine()
609 : llvm::Triple::UnknownArch;
610
611 switch (exc_type) {
612 case 1: // EXC_BAD_ACCESS
613 case 2: // EXC_BAD_INSTRUCTION
614 case 3: // EXC_ARITHMETIC
615 case 4: // EXC_EMULATION
616 break;
617
618 case 5: // EXC_SOFTWARE
619 if (exc_code == 0x10003) // EXC_SOFT_SIGNAL
620 {
621 if (exc_sub_code == 5) {
622 // On MacOSX, a SIGTRAP can signify that a process has called exec,
623 // so we should check with our dynamic loader to verify.
624 ProcessSP process_sp(thread.GetProcess());
625 if (process_sp) {
626 DynamicLoader *dynamic_loader = process_sp->GetDynamicLoader();
627 if (dynamic_loader && dynamic_loader->ProcessDidExec()) {
628 // The program was re-exec'ed
629 return StopInfo::CreateStopReasonWithExec(thread);
630 }
631 }
632 }
633 return StopInfo::CreateStopReasonWithSignal(thread, exc_sub_code);
634 }
635 break;
636
637 case 6: // EXC_BREAKPOINT
638 {
639 bool is_actual_breakpoint = false;
640 bool is_trace_if_actual_breakpoint_missing = false;
641 switch (cpu) {
642 case llvm::Triple::x86:
643 case llvm::Triple::x86_64:
644 if (exc_code == 1) // EXC_I386_SGL
645 {
646 if (!exc_sub_code) {
647 // This looks like a plain trap.
648 // Have to check if there is a breakpoint here as well. When you
649 // single-step onto a trap, the single step stops you not to trap.
650 // Since we also do that check below, let's just use that logic.
651 is_actual_breakpoint = true;
652 is_trace_if_actual_breakpoint_missing = true;
653 } else {
654 if (StopInfoSP stop_info =
655 GetStopInfoForHardwareBP(thread, target, exc_data_count,
656 exc_sub_code, exc_sub_sub_code))
657 return stop_info;
658 }
659 } else if (exc_code == 2 || // EXC_I386_BPT
660 exc_code == 3) // EXC_I386_BPTFLT
661 {
662 // KDP returns EXC_I386_BPTFLT for trace breakpoints
663 if (exc_code == 3)
664 is_trace_if_actual_breakpoint_missing = true;
665
666 is_actual_breakpoint = true;
667 if (!pc_already_adjusted)
668 pc_decrement = 1;
669 }
670 break;
671
672 case llvm::Triple::arm:
673 case llvm::Triple::thumb:
674 if (exc_code == 0x102) // EXC_ARM_DA_DEBUG
675 {
676 // It's a watchpoint, then, if the exc_sub_code indicates a
677 // known/enabled data break address from our watchpoint list.
678 lldb::WatchpointSP wp_sp;
679 if (target)
680 wp_sp = target->GetWatchpointList().FindByAddress(
681 (lldb::addr_t)exc_sub_code);
682 if (wp_sp && wp_sp->IsEnabled()) {
683 // Debugserver may piggyback the hardware index of the fired
684 // watchpoint in the exception data. Set the hardware index if
685 // that's the case.
686 if (exc_data_count >= 3)
687 wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
688 return StopInfo::CreateStopReasonWithWatchpointID(thread,
689 wp_sp->GetID());
690 } else {
691 is_actual_breakpoint = true;
692 is_trace_if_actual_breakpoint_missing = true;
693 }
694 } else if (exc_code == 1) // EXC_ARM_BREAKPOINT
695 {
696 is_actual_breakpoint = true;
697 is_trace_if_actual_breakpoint_missing = true;
698 } else if (exc_code == 0) // FIXME not EXC_ARM_BREAKPOINT but a kernel
699 // is currently returning this so accept it
700 // as indicating a breakpoint until the
701 // kernel is fixed
702 {
703 is_actual_breakpoint = true;
704 is_trace_if_actual_breakpoint_missing = true;
705 }
706 break;
707
708 case llvm::Triple::aarch64_32:
709 case llvm::Triple::aarch64: {
710 if (exc_code == 1 && exc_sub_code == 0) // EXC_ARM_BREAKPOINT
711 {
712 // This is hit when we single instruction step aka MDSCR_EL1 SS bit 0
713 // is set
714 is_actual_breakpoint = false;
Value stored to 'is_actual_breakpoint' is never read
715 is_trace_if_actual_breakpoint_missing = true;
716 }
717 if (exc_code == 0x102) // EXC_ARM_DA_DEBUG
718 {
719 // It's a watchpoint, then, if the exc_sub_code indicates a
720 // known/enabled data break address from our watchpoint list.
721 lldb::WatchpointSP wp_sp;
722 if (target)
723 wp_sp = target->GetWatchpointList().FindByAddress(
724 (lldb::addr_t)exc_sub_code);
725 if (wp_sp && wp_sp->IsEnabled()) {
726 // Debugserver may piggyback the hardware index of the fired
727 // watchpoint in the exception data. Set the hardware index if
728 // that's the case.
729 if (exc_data_count >= 3)
730 wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
731 return StopInfo::CreateStopReasonWithWatchpointID(thread,
732 wp_sp->GetID());
733 }
734 // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as
735 // EXC_BAD_ACCESS
736 if (thread.GetTemporaryResumeState() == eStateStepping)
737 return StopInfo::CreateStopReasonToTrace(thread);
738 }
739 // It looks like exc_sub_code has the 4 bytes of the instruction that
740 // triggered the exception, i.e. our breakpoint opcode
741 is_actual_breakpoint = exc_code == 1;
742 break;
743 }
744
745 default:
746 break;
747 }
748
749 if (is_actual_breakpoint) {
750 RegisterContextSP reg_ctx_sp(thread.GetRegisterContext());
751 addr_t pc = reg_ctx_sp->GetPC() - pc_decrement;
752
753 ProcessSP process_sp(thread.CalculateProcess());
754
755 lldb::BreakpointSiteSP bp_site_sp;
756 if (process_sp)
757 bp_site_sp = process_sp->GetBreakpointSiteList().FindByAddress(pc);
758 if (bp_site_sp && bp_site_sp->IsEnabled()) {
759 // Update the PC if we were asked to do so, but only do so if we find
760 // a breakpoint that we know about cause this could be a trap
761 // instruction in the code
762 if (pc_decrement > 0 && adjust_pc_if_needed)
763 reg_ctx_sp->SetPC(pc);
764
765 // If the breakpoint is for this thread, then we'll report the hit,
766 // but if it is for another thread, we can just report no reason. We
767 // don't need to worry about stepping over the breakpoint here, that
768 // will be taken care of when the thread resumes and notices that
769 // there's a breakpoint under the pc. If we have an operating system
770 // plug-in, we might have set a thread specific breakpoint using the
771 // operating system thread ID, so we can't make any assumptions about
772 // the thread ID so we must always report the breakpoint regardless
773 // of the thread.
774 if (bp_site_sp->ValidForThisThread(thread) ||
775 thread.GetProcess()->GetOperatingSystem() != nullptr)
776 return StopInfo::CreateStopReasonWithBreakpointSiteID(
777 thread, bp_site_sp->GetID());
778 else if (is_trace_if_actual_breakpoint_missing)
779 return StopInfo::CreateStopReasonToTrace(thread);
780 else
781 return StopInfoSP();
782 }
783
784 // Don't call this a trace if we weren't single stepping this thread.
785 if (is_trace_if_actual_breakpoint_missing &&
786 thread.GetTemporaryResumeState() == eStateStepping) {
787 return StopInfo::CreateStopReasonToTrace(thread);
788 }
789 }
790 } break;
791
792 case 7: // EXC_SYSCALL
793 case 8: // EXC_MACH_SYSCALL
794 case 9: // EXC_RPC_ALERT
795 case 10: // EXC_CRASH
796 break;
797 }
798
799 return StopInfoSP(new StopInfoMachException(thread, exc_type, exc_data_count,
800 exc_code, exc_sub_code));
801}