LLDB  mainline
StopInfoMachException.cpp
Go to the documentation of this file.
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 
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 
19 #include "lldb/Symbol/Symbol.h"
22 #include "lldb/Target/Process.h"
24 #include "lldb/Target/Target.h"
25 #include "lldb/Target/Thread.h"
26 #include "lldb/Target/ThreadPlan.h"
29 
30 using namespace lldb;
31 using namespace lldb_private;
32 
33 const char *StopInfoMachException::GetDescription() {
34  if (!m_description.empty())
35  return m_description.c_str();
36  if (GetValue() == eStopReasonInvalid)
37  return "invalid stop reason!";
38 
39  ExecutionContext exe_ctx(m_thread_wp.lock());
40  Target *target = exe_ctx.GetTargetPtr();
41  const llvm::Triple::ArchType cpu =
42  target ? target->GetArchitecture().GetMachine()
43  : llvm::Triple::UnknownArch;
44 
45  const char *exc_desc = nullptr;
46  const char *code_label = "code";
47  const char *code_desc = nullptr;
48  const char *subcode_label = "subcode";
49  const char *subcode_desc = nullptr;
50 
51 #if defined(__APPLE__)
52  char code_desc_buf[32];
53  char subcode_desc_buf[32];
54 #endif
55 
56  switch (m_value) {
57  case 1: // EXC_BAD_ACCESS
58  exc_desc = "EXC_BAD_ACCESS";
59  subcode_label = "address";
60  switch (cpu) {
61  case llvm::Triple::x86:
62  case llvm::Triple::x86_64:
63  switch (m_exc_code) {
64  case 0xd:
65  code_desc = "EXC_I386_GPFLT";
66  m_exc_data_count = 1;
67  break;
68  }
69  break;
70  case llvm::Triple::arm:
71  case llvm::Triple::thumb:
72  switch (m_exc_code) {
73  case 0x101:
74  code_desc = "EXC_ARM_DA_ALIGN";
75  break;
76  case 0x102:
77  code_desc = "EXC_ARM_DA_DEBUG";
78  break;
79  }
80  break;
81 
82  default:
83  break;
84  }
85  break;
86 
87  case 2: // EXC_BAD_INSTRUCTION
88  exc_desc = "EXC_BAD_INSTRUCTION";
89  switch (cpu) {
90  case llvm::Triple::x86:
91  case llvm::Triple::x86_64:
92  if (m_exc_code == 1)
93  code_desc = "EXC_I386_INVOP";
94  break;
95 
96  case llvm::Triple::arm:
97  case llvm::Triple::thumb:
98  if (m_exc_code == 1)
99  code_desc = "EXC_ARM_UNDEFINED";
100  break;
101 
102  default:
103  break;
104  }
105  break;
106 
107  case 3: // EXC_ARITHMETIC
108  exc_desc = "EXC_ARITHMETIC";
109  switch (cpu) {
110  case llvm::Triple::x86:
111  case llvm::Triple::x86_64:
112  switch (m_exc_code) {
113  case 1:
114  code_desc = "EXC_I386_DIV";
115  break;
116  case 2:
117  code_desc = "EXC_I386_INTO";
118  break;
119  case 3:
120  code_desc = "EXC_I386_NOEXT";
121  break;
122  case 4:
123  code_desc = "EXC_I386_EXTOVR";
124  break;
125  case 5:
126  code_desc = "EXC_I386_EXTERR";
127  break;
128  case 6:
129  code_desc = "EXC_I386_EMERR";
130  break;
131  case 7:
132  code_desc = "EXC_I386_BOUND";
133  break;
134  case 8:
135  code_desc = "EXC_I386_SSEEXTERR";
136  break;
137  }
138  break;
139 
140  default:
141  break;
142  }
143  break;
144 
145  case 4: // EXC_EMULATION
146  exc_desc = "EXC_EMULATION";
147  break;
148 
149  case 5: // EXC_SOFTWARE
150  exc_desc = "EXC_SOFTWARE";
151  if (m_exc_code == 0x10003) {
152  subcode_desc = "EXC_SOFT_SIGNAL";
153  subcode_label = "signo";
154  }
155  break;
156 
157  case 6: // EXC_BREAKPOINT
158  {
159  exc_desc = "EXC_BREAKPOINT";
160  switch (cpu) {
161  case llvm::Triple::x86:
162  case llvm::Triple::x86_64:
163  switch (m_exc_code) {
164  case 1:
165  code_desc = "EXC_I386_SGL";
166  break;
167  case 2:
168  code_desc = "EXC_I386_BPT";
169  break;
170  }
171  break;
172 
173  case llvm::Triple::arm:
174  case llvm::Triple::thumb:
175  switch (m_exc_code) {
176  case 0x101:
177  code_desc = "EXC_ARM_DA_ALIGN";
178  break;
179  case 0x102:
180  code_desc = "EXC_ARM_DA_DEBUG";
181  break;
182  case 1:
183  code_desc = "EXC_ARM_BREAKPOINT";
184  break;
185  // FIXME temporary workaround, exc_code 0 does not really mean
186  // EXC_ARM_BREAKPOINT
187  case 0:
188  code_desc = "EXC_ARM_BREAKPOINT";
189  break;
190  }
191  break;
192 
193  default:
194  break;
195  }
196  } break;
197 
198  case 7:
199  exc_desc = "EXC_SYSCALL";
200  break;
201 
202  case 8:
203  exc_desc = "EXC_MACH_SYSCALL";
204  break;
205 
206  case 9:
207  exc_desc = "EXC_RPC_ALERT";
208  break;
209 
210  case 10:
211  exc_desc = "EXC_CRASH";
212  break;
213  case 11:
214  exc_desc = "EXC_RESOURCE";
215 #if defined(__APPLE__)
216  {
217  int resource_type = EXC_RESOURCE_DECODE_RESOURCE_TYPE(m_exc_code);
218 
219  code_label = "limit";
220  code_desc = code_desc_buf;
221  subcode_label = "observed";
222  subcode_desc = subcode_desc_buf;
223 
224  switch (resource_type) {
225  case RESOURCE_TYPE_CPU:
226  exc_desc = "EXC_RESOURCE RESOURCE_TYPE_CPU";
227  snprintf(code_desc_buf, sizeof(code_desc_buf), "%d%%",
228  (int)EXC_RESOURCE_CPUMONITOR_DECODE_PERCENTAGE(m_exc_code));
229  snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d%%",
230  (int)EXC_RESOURCE_CPUMONITOR_DECODE_PERCENTAGE_OBSERVED(
231  m_exc_subcode));
232  break;
233  case RESOURCE_TYPE_WAKEUPS:
234  exc_desc = "EXC_RESOURCE RESOURCE_TYPE_WAKEUPS";
235  snprintf(
236  code_desc_buf, sizeof(code_desc_buf), "%d w/s",
237  (int)EXC_RESOURCE_CPUMONITOR_DECODE_WAKEUPS_PERMITTED(m_exc_code));
238  snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d w/s",
239  (int)EXC_RESOURCE_CPUMONITOR_DECODE_WAKEUPS_OBSERVED(
240  m_exc_subcode));
241  break;
242  case RESOURCE_TYPE_MEMORY:
243  exc_desc = "EXC_RESOURCE RESOURCE_TYPE_MEMORY";
244  snprintf(code_desc_buf, sizeof(code_desc_buf), "%d MB",
245  (int)EXC_RESOURCE_HWM_DECODE_LIMIT(m_exc_code));
246  subcode_desc = nullptr;
247  subcode_label = "unused";
248  break;
249 #if defined(RESOURCE_TYPE_IO)
250  // RESOURCE_TYPE_IO is introduced in macOS SDK 10.12.
251  case RESOURCE_TYPE_IO:
252  exc_desc = "EXC_RESOURCE RESOURCE_TYPE_IO";
253  snprintf(code_desc_buf, sizeof(code_desc_buf), "%d MB",
254  (int)EXC_RESOURCE_IO_DECODE_LIMIT(m_exc_code));
255  snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d MB",
256  (int)EXC_RESOURCE_IO_OBSERVED(m_exc_subcode));
257  ;
258  break;
259 #endif
260  }
261  }
262 #endif
263  break;
264  case 12:
265  exc_desc = "EXC_GUARD";
266  break;
267  }
268 
269  StreamString strm;
270 
271  if (exc_desc)
272  strm.PutCString(exc_desc);
273  else
274  strm.Printf("EXC_??? (%" PRIu64 ")", m_value);
275 
276  if (m_exc_data_count >= 1) {
277  if (code_desc)
278  strm.Printf(" (%s=%s", code_label, code_desc);
279  else
280  strm.Printf(" (%s=%" PRIu64, code_label, m_exc_code);
281  }
282 
283  if (m_exc_data_count >= 2) {
284  if (subcode_desc)
285  strm.Printf(", %s=%s", subcode_label, subcode_desc);
286  else
287  strm.Printf(", %s=0x%" PRIx64, subcode_label, m_exc_subcode);
288  }
289 
290  if (m_exc_data_count > 0)
291  strm.PutChar(')');
292 
293  m_description = std::string(strm.GetString());
294  return m_description.c_str();
295 }
296 
297 static StopInfoSP GetStopInfoForHardwareBP(Thread &thread, Target *target,
298  uint32_t exc_data_count,
299  uint64_t exc_sub_code,
300  uint64_t exc_sub_sub_code) {
301  // Try hardware watchpoint.
302  if (target) {
303  // The exc_sub_code indicates the data break address.
304  lldb::WatchpointSP wp_sp =
305  target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code);
306  if (wp_sp && wp_sp->IsEnabled()) {
307  // Debugserver may piggyback the hardware index of the fired watchpoint
308  // in the exception data. Set the hardware index if that's the case.
309  if (exc_data_count >= 3)
310  wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
311  return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID());
312  }
313  }
314 
315  // Try hardware breakpoint.
316  ProcessSP process_sp(thread.GetProcess());
317  if (process_sp) {
318  // The exc_sub_code indicates the data break address.
319  lldb::BreakpointSiteSP bp_sp =
320  process_sp->GetBreakpointSiteList().FindByAddress(
321  (lldb::addr_t)exc_sub_code);
322  if (bp_sp && bp_sp->IsEnabled()) {
323  // Debugserver may piggyback the hardware index of the fired breakpoint
324  // in the exception data. Set the hardware index if that's the case.
325  if (exc_data_count >= 3)
326  bp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
327  return StopInfo::CreateStopReasonWithBreakpointSiteID(thread,
328  bp_sp->GetID());
329  }
330  }
331 
332  return nullptr;
333 }
334 
335 StopInfoSP StopInfoMachException::CreateStopReasonWithMachException(
336  Thread &thread, uint32_t exc_type, uint32_t exc_data_count,
337  uint64_t exc_code, uint64_t exc_sub_code, uint64_t exc_sub_sub_code,
338  bool pc_already_adjusted, bool adjust_pc_if_needed) {
339  if (exc_type == 0)
340  return StopInfoSP();
341 
342  uint32_t pc_decrement = 0;
343  ExecutionContext exe_ctx(thread.shared_from_this());
344  Target *target = exe_ctx.GetTargetPtr();
345  const llvm::Triple::ArchType cpu =
346  target ? target->GetArchitecture().GetMachine()
347  : llvm::Triple::UnknownArch;
348 
349  switch (exc_type) {
350  case 1: // EXC_BAD_ACCESS
351  case 2: // EXC_BAD_INSTRUCTION
352  case 3: // EXC_ARITHMETIC
353  case 4: // EXC_EMULATION
354  break;
355 
356  case 5: // EXC_SOFTWARE
357  if (exc_code == 0x10003) // EXC_SOFT_SIGNAL
358  {
359  if (exc_sub_code == 5) {
360  // On MacOSX, a SIGTRAP can signify that a process has called exec,
361  // so we should check with our dynamic loader to verify.
362  ProcessSP process_sp(thread.GetProcess());
363  if (process_sp) {
364  DynamicLoader *dynamic_loader = process_sp->GetDynamicLoader();
365  if (dynamic_loader && dynamic_loader->ProcessDidExec()) {
366  // The program was re-exec'ed
367  return StopInfo::CreateStopReasonWithExec(thread);
368  }
369  }
370  }
371  return StopInfo::CreateStopReasonWithSignal(thread, exc_sub_code);
372  }
373  break;
374 
375  case 6: // EXC_BREAKPOINT
376  {
377  bool is_actual_breakpoint = false;
378  bool is_trace_if_actual_breakpoint_missing = false;
379  switch (cpu) {
380  case llvm::Triple::x86:
381  case llvm::Triple::x86_64:
382  if (exc_code == 1) // EXC_I386_SGL
383  {
384  if (!exc_sub_code) {
385  // This looks like a plain trap.
386  // Have to check if there is a breakpoint here as well. When you
387  // single-step onto a trap, the single step stops you not to trap.
388  // Since we also do that check below, let's just use that logic.
389  is_actual_breakpoint = true;
390  is_trace_if_actual_breakpoint_missing = true;
391  } else {
392  if (StopInfoSP stop_info =
393  GetStopInfoForHardwareBP(thread, target, exc_data_count,
394  exc_sub_code, exc_sub_sub_code))
395  return stop_info;
396  }
397  } else if (exc_code == 2 || // EXC_I386_BPT
398  exc_code == 3) // EXC_I386_BPTFLT
399  {
400  // KDP returns EXC_I386_BPTFLT for trace breakpoints
401  if (exc_code == 3)
402  is_trace_if_actual_breakpoint_missing = true;
403 
404  is_actual_breakpoint = true;
405  if (!pc_already_adjusted)
406  pc_decrement = 1;
407  }
408  break;
409 
410  case llvm::Triple::arm:
411  case llvm::Triple::thumb:
412  if (exc_code == 0x102) // EXC_ARM_DA_DEBUG
413  {
414  // It's a watchpoint, then, if the exc_sub_code indicates a
415  // known/enabled data break address from our watchpoint list.
416  lldb::WatchpointSP wp_sp;
417  if (target)
418  wp_sp = target->GetWatchpointList().FindByAddress(
419  (lldb::addr_t)exc_sub_code);
420  if (wp_sp && wp_sp->IsEnabled()) {
421  // Debugserver may piggyback the hardware index of the fired
422  // watchpoint in the exception data. Set the hardware index if
423  // that's the case.
424  if (exc_data_count >= 3)
425  wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
426  return StopInfo::CreateStopReasonWithWatchpointID(thread,
427  wp_sp->GetID());
428  } else {
429  is_actual_breakpoint = true;
430  is_trace_if_actual_breakpoint_missing = true;
431  }
432  } else if (exc_code == 1) // EXC_ARM_BREAKPOINT
433  {
434  is_actual_breakpoint = true;
435  is_trace_if_actual_breakpoint_missing = true;
436  } else if (exc_code == 0) // FIXME not EXC_ARM_BREAKPOINT but a kernel
437  // is currently returning this so accept it
438  // as indicating a breakpoint until the
439  // kernel is fixed
440  {
441  is_actual_breakpoint = true;
442  is_trace_if_actual_breakpoint_missing = true;
443  }
444  break;
445 
446  case llvm::Triple::aarch64_32:
447  case llvm::Triple::aarch64: {
448  if (exc_code == 1 && exc_sub_code == 0) // EXC_ARM_BREAKPOINT
449  {
450  // This is hit when we single instruction step aka MDSCR_EL1 SS bit 0
451  // is set
452  is_actual_breakpoint = false;
453  is_trace_if_actual_breakpoint_missing = true;
454  }
455  if (exc_code == 0x102) // EXC_ARM_DA_DEBUG
456  {
457  // It's a watchpoint, then, if the exc_sub_code indicates a
458  // known/enabled data break address from our watchpoint list.
459  lldb::WatchpointSP wp_sp;
460  if (target)
461  wp_sp = target->GetWatchpointList().FindByAddress(
462  (lldb::addr_t)exc_sub_code);
463  if (wp_sp && wp_sp->IsEnabled()) {
464  // Debugserver may piggyback the hardware index of the fired
465  // watchpoint in the exception data. Set the hardware index if
466  // that's the case.
467  if (exc_data_count >= 3)
468  wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
469  return StopInfo::CreateStopReasonWithWatchpointID(thread,
470  wp_sp->GetID());
471  }
472  // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as
473  // EXC_BAD_ACCESS
474  if (thread.GetTemporaryResumeState() == eStateStepping)
475  return StopInfo::CreateStopReasonToTrace(thread);
476  }
477  // It looks like exc_sub_code has the 4 bytes of the instruction that
478  // triggered the exception, i.e. our breakpoint opcode
479  is_actual_breakpoint = exc_code == 1;
480  break;
481  }
482 
483  default:
484  break;
485  }
486 
487  if (is_actual_breakpoint) {
488  RegisterContextSP reg_ctx_sp(thread.GetRegisterContext());
489  addr_t pc = reg_ctx_sp->GetPC() - pc_decrement;
490 
491  ProcessSP process_sp(thread.CalculateProcess());
492 
493  lldb::BreakpointSiteSP bp_site_sp;
494  if (process_sp)
495  bp_site_sp = process_sp->GetBreakpointSiteList().FindByAddress(pc);
496  if (bp_site_sp && bp_site_sp->IsEnabled()) {
497  // Update the PC if we were asked to do so, but only do so if we find
498  // a breakpoint that we know about cause this could be a trap
499  // instruction in the code
500  if (pc_decrement > 0 && adjust_pc_if_needed)
501  reg_ctx_sp->SetPC(pc);
502 
503  // If the breakpoint is for this thread, then we'll report the hit,
504  // but if it is for another thread, we can just report no reason. We
505  // don't need to worry about stepping over the breakpoint here, that
506  // will be taken care of when the thread resumes and notices that
507  // there's a breakpoint under the pc. If we have an operating system
508  // plug-in, we might have set a thread specific breakpoint using the
509  // operating system thread ID, so we can't make any assumptions about
510  // the thread ID so we must always report the breakpoint regardless
511  // of the thread.
512  if (bp_site_sp->ValidForThisThread(&thread) ||
513  thread.GetProcess()->GetOperatingSystem() != nullptr)
514  return StopInfo::CreateStopReasonWithBreakpointSiteID(
515  thread, bp_site_sp->GetID());
516  else if (is_trace_if_actual_breakpoint_missing)
517  return StopInfo::CreateStopReasonToTrace(thread);
518  else
519  return StopInfoSP();
520  }
521 
522  // Don't call this a trace if we weren't single stepping this thread.
523  if (is_trace_if_actual_breakpoint_missing &&
525  return StopInfo::CreateStopReasonToTrace(thread);
526  }
527  }
528  } break;
529 
530  case 7: // EXC_SYSCALL
531  case 8: // EXC_MACH_SYSCALL
532  case 9: // EXC_RPC_ALERT
533  case 10: // EXC_CRASH
534  break;
535  }
536 
537  return StopInfoSP(new StopInfoMachException(thread, exc_type, exc_data_count,
538  exc_code, exc_sub_code));
539 }
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition: Stream.cpp:63
A class that represents a running process on the host machine.
const ArchSpec & GetArchitecture() const
Definition: Target.h:942
WatchpointList & GetWatchpointList()
Definition: Target.h:696
static StopInfoSP GetStopInfoForHardwareBP(Thread &thread, Target *target, uint32_t exc_data_count, uint64_t exc_sub_code, uint64_t exc_sub_sub_code)
lldb::user_id_t GetID() const
Get accessor for the user ID.
Definition: UserID.h:47
virtual bool ProcessDidExec()
Helper function that can be used to detect when a process has called exec and is now a new and differ...
Definition: DynamicLoader.h:95
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
const lldb::WatchpointSP FindByAddress(lldb::addr_t addr) const
Returns a shared pointer to the watchpoint at address addr - const version.
llvm::StringRef GetString() const
virtual lldb::RegisterContextSP GetRegisterContext()=0
lldb::ProcessSP CalculateProcess() override
Definition: Thread.cpp:1398
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:107
Process or thread is in the process of stepping and can not be examined.
lldb::ProcessSP GetProcess() const
Definition: Thread.h:153
A plug-in interface definition class for dynamic loaders.
Definition: DynamicLoader.h:52
size_t PutChar(char ch)
Definition: Stream.cpp:104
uint64_t addr_t
Definition: lldb-types.h:83
Definition: SBAddress.h:15
lldb::StateType GetTemporaryResumeState() const
Definition: Thread.h:1136
llvm::Triple::ArchType GetMachine() const
Returns a machine family for the current architecture.
Definition: ArchSpec.cpp:714