1 //===-- StopInfoMachException.cpp -------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "StopInfoMachException.h"
11 
12 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 // Project includes
16 #include "lldb/Breakpoint/WatchpointLocation.h"
17 #include "lldb/Core/ArchSpec.h"
18 #include "lldb/Core/StreamString.h"
19 #include "lldb/Target/Process.h"
20 #include "lldb/Target/RegisterContext.h"
21 #include "lldb/Target/Target.h"
22 #include "lldb/Target/Thread.h"
23 #include "lldb/Target/ThreadPlan.h"
24 #include "lldb/Target/UnixSignals.h"
25 
26 using namespace lldb;
27 using namespace lldb_private;
28 
29 const char *
30 StopInfoMachException::GetDescription ()
31 {
32     if (m_description.empty() && m_value != 0)
33     {
34         const llvm::Triple::ArchType cpu = m_thread.GetProcess().GetTarget().GetArchitecture().GetMachine();
35 
36         const char *exc_desc = NULL;
37         const char *code_label = "code";
38         const char *code_desc = NULL;
39         const char *subcode_label = "subcode";
40         const char *subcode_desc = NULL;
41         switch (m_value)
42         {
43         case 1: // EXC_BAD_ACCESS
44             exc_desc = "EXC_BAD_ACCESS";
45             subcode_label = "address";
46             switch (cpu)
47             {
48             case llvm::Triple::arm:
49                 switch (m_exc_code)
50                 {
51                 case 0x101: code_desc = "EXC_ARM_DA_ALIGN"; break;
52                 case 0x102: code_desc = "EXC_ARM_DA_DEBUG"; break;
53                 }
54                 break;
55 
56             case llvm::Triple::ppc:
57             case llvm::Triple::ppc64:
58                 switch (m_exc_code)
59                 {
60                 case 0x101: code_desc = "EXC_PPC_VM_PROT_READ"; break;
61                 case 0x102: code_desc = "EXC_PPC_BADSPACE";     break;
62                 case 0x103: code_desc = "EXC_PPC_UNALIGNED";    break;
63                 }
64                 break;
65 
66             default:
67                 break;
68             }
69             break;
70 
71         case 2: // EXC_BAD_INSTRUCTION
72             exc_desc = "EXC_BAD_INSTRUCTION";
73             switch (cpu)
74             {
75             case llvm::Triple::x86:
76             case llvm::Triple::x86_64:
77                 if (m_exc_code == 1)
78                     code_desc = "EXC_I386_INVOP";
79                 break;
80 
81             case llvm::Triple::ppc:
82             case llvm::Triple::ppc64:
83                 switch (m_exc_code)
84                 {
85                 case 1: code_desc = "EXC_PPC_INVALID_SYSCALL"; break;
86                 case 2: code_desc = "EXC_PPC_UNIPL_INST"; break;
87                 case 3: code_desc = "EXC_PPC_PRIVINST"; break;
88                 case 4: code_desc = "EXC_PPC_PRIVREG"; break;
89                 case 5: code_desc = "EXC_PPC_TRACE"; break;
90                 case 6: code_desc = "EXC_PPC_PERFMON"; break;
91                 }
92                 break;
93 
94             case llvm::Triple::arm:
95                 if (m_exc_code == 1)
96                     code_desc = "EXC_ARM_UNDEFINED";
97                 break;
98 
99             default:
100                 break;
101             }
102             break;
103 
104         case 3: // EXC_ARITHMETIC
105             exc_desc = "EXC_ARITHMETIC";
106             switch (cpu)
107             {
108             case llvm::Triple::x86:
109             case llvm::Triple::x86_64:
110                 switch (m_exc_code)
111                 {
112                 case 1: code_desc = "EXC_I386_DIV"; break;
113                 case 2: code_desc = "EXC_I386_INTO"; break;
114                 case 3: code_desc = "EXC_I386_NOEXT"; break;
115                 case 4: code_desc = "EXC_I386_EXTOVR"; break;
116                 case 5: code_desc = "EXC_I386_EXTERR"; break;
117                 case 6: code_desc = "EXC_I386_EMERR"; break;
118                 case 7: code_desc = "EXC_I386_BOUND"; break;
119                 case 8: code_desc = "EXC_I386_SSEEXTERR"; break;
120                 }
121                 break;
122 
123             case llvm::Triple::ppc:
124             case llvm::Triple::ppc64:
125                 switch (m_exc_code)
126                 {
127                 case 1: code_desc = "EXC_PPC_OVERFLOW"; break;
128                 case 2: code_desc = "EXC_PPC_ZERO_DIVIDE"; break;
129                 case 3: code_desc = "EXC_PPC_FLT_INEXACT"; break;
130                 case 4: code_desc = "EXC_PPC_FLT_ZERO_DIVIDE"; break;
131                 case 5: code_desc = "EXC_PPC_FLT_UNDERFLOW"; break;
132                 case 6: code_desc = "EXC_PPC_FLT_OVERFLOW"; break;
133                 case 7: code_desc = "EXC_PPC_FLT_NOT_A_NUMBER"; break;
134                 }
135                 break;
136 
137             default:
138                 break;
139             }
140             break;
141 
142         case 4: // EXC_EMULATION
143             exc_desc = "EXC_EMULATION";
144             break;
145 
146 
147         case 5: // EXC_SOFTWARE
148             exc_desc = "EXC_SOFTWARE";
149             if (m_exc_code == 0x10003)
150             {
151                 subcode_desc = "EXC_SOFT_SIGNAL";
152                 subcode_label = "signo";
153             }
154             break;
155 
156         case 6: // EXC_BREAKPOINT
157             {
158                 exc_desc = "EXC_BREAKPOINT";
159                 switch (cpu)
160                 {
161                 case llvm::Triple::x86:
162                 case llvm::Triple::x86_64:
163                     switch (m_exc_code)
164                     {
165                     case 1: code_desc = "EXC_I386_SGL"; break;
166                     case 2: code_desc = "EXC_I386_BPT"; break;
167                     }
168                     break;
169 
170                 case llvm::Triple::ppc:
171                 case llvm::Triple::ppc64:
172                     switch (m_exc_code)
173                     {
174                     case 1: code_desc = "EXC_PPC_BREAKPOINT"; break;
175                     }
176                     break;
177 
178                 case llvm::Triple::arm:
179                     switch (m_exc_code)
180                     {
181                     case 0x101: code_desc = "EXC_ARM_DA_ALIGN"; break;
182                     case 0x102: code_desc = "EXC_ARM_DA_DEBUG"; break;
183                     case 1: code_desc = "EXC_ARM_BREAKPOINT"; break;
184                     }
185                     break;
186 
187                 default:
188                     break;
189                 }
190             }
191             break;
192 
193         case 7:
194             exc_desc = "EXC_SYSCALL";
195             break;
196 
197         case 8:
198             exc_desc = "EXC_MACH_SYSCALL";
199             break;
200 
201         case 9:
202             exc_desc = "EXC_RPC_ALERT";
203             break;
204 
205         case 10:
206             exc_desc = "EXC_CRASH";
207             break;
208         }
209 
210         StreamString strm;
211 
212         if (exc_desc)
213             strm.PutCString(exc_desc);
214         else
215             strm.Printf("EXC_??? (%llu)", m_value);
216 
217         if (m_exc_data_count >= 1)
218         {
219             if (code_desc)
220                 strm.Printf(" (%s=%s", code_label, code_desc);
221             else
222                 strm.Printf(" (%s=%llu", code_label, m_exc_code);
223         }
224 
225         if (m_exc_data_count >= 2)
226         {
227             if (subcode_desc)
228                 strm.Printf(", %s=%s", subcode_label, subcode_desc);
229             else
230                 strm.Printf(", %s=0x%llx", subcode_label, m_exc_subcode);
231         }
232 
233         if (m_exc_data_count > 0)
234             strm.PutChar(')');
235 
236         m_description.swap (strm.GetString());
237     }
238     return m_description.c_str();
239 }
240 
241 
242 StopInfoSP
243 StopInfoMachException::CreateStopReasonWithMachException
244 (
245     Thread &thread,
246     uint32_t exc_type,
247     uint32_t exc_data_count,
248     uint64_t exc_code,
249     uint64_t exc_sub_code,
250     uint64_t exc_sub_sub_code
251 )
252 {
253     if (exc_type != 0)
254     {
255         const llvm::Triple::ArchType cpu = thread.GetProcess().GetTarget().GetArchitecture().GetMachine();
256 
257         switch (exc_type)
258         {
259         case 1: // EXC_BAD_ACCESS
260             break;
261 
262         case 2: // EXC_BAD_INSTRUCTION
263             switch (cpu)
264             {
265             case llvm::Triple::ppc:
266             case llvm::Triple::ppc64:
267                 switch (exc_code)
268                 {
269                 case 1: // EXC_PPC_INVALID_SYSCALL
270                 case 2: // EXC_PPC_UNIPL_INST
271                 case 3: // EXC_PPC_PRIVINST
272                 case 4: // EXC_PPC_PRIVREG
273                     break;
274                 case 5: // EXC_PPC_TRACE
275                     return StopInfo::CreateStopReasonToTrace (thread);
276                 case 6: // EXC_PPC_PERFMON
277                     break;
278                 }
279                 break;
280 
281             default:
282                 break;
283             }
284             break;
285 
286         case 3: // EXC_ARITHMETIC
287         case 4: // EXC_EMULATION
288             break;
289 
290         case 5: // EXC_SOFTWARE
291             if (exc_code == 0x10003) // EXC_SOFT_SIGNAL
292                 return StopInfo::CreateStopReasonWithSignal (thread, exc_sub_code);
293             break;
294 
295         case 6: // EXC_BREAKPOINT
296             {
297                 bool is_software_breakpoint = false;
298                 switch (cpu)
299                 {
300                 case llvm::Triple::x86:
301                 case llvm::Triple::x86_64:
302                     if (exc_code == 1) // EXC_I386_SGL
303                     {
304                         if (!exc_sub_code)
305                             return StopInfo::CreateStopReasonToTrace(thread);
306 
307                         // It's a watchpoint, then.
308                         // The exc_sub_code indicates the data break address.
309                         lldb::WatchpointLocationSP wp_loc_sp =
310                             thread.GetProcess().GetTarget().GetWatchpointLocationList().FindByAddress((lldb::addr_t)exc_sub_code);
311                         if (wp_loc_sp)
312                         {
313                             // Debugserver may piggyback the hardware index of the fired watchpoint in the exception data.
314                             // Set the hardware index if that's the case.
315                             if (exc_data_count >=3)
316                                 wp_loc_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
317                             return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_loc_sp->GetID());
318                         }
319                     }
320                     else if (exc_code == 2) // EXC_I386_BPT
321                     {
322                         is_software_breakpoint = true;
323                     }
324                     break;
325 
326                 case llvm::Triple::ppc:
327                 case llvm::Triple::ppc64:
328                     is_software_breakpoint = exc_code == 1; // EXC_PPC_BREAKPOINT
329                     break;
330 
331                 case llvm::Triple::arm:
332                     if (exc_code == 0x102)
333                     {
334                         // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as EXC_BAD_ACCESS
335                         return StopInfo::CreateStopReasonToTrace(thread);
336                     }
337                     else
338                         is_software_breakpoint = exc_code == 1; // EXC_ARM_BREAKPOINT
339                     break;
340 
341                 default:
342                     break;
343                 }
344 
345                 if (is_software_breakpoint)
346                 {
347                     addr_t pc = thread.GetRegisterContext()->GetPC();
348                     lldb::BreakpointSiteSP bp_site_sp = thread.GetProcess().GetBreakpointSiteList().FindByAddress(pc);
349                     if (bp_site_sp)
350                     {
351                         // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread,
352                         // we can just report no reason.  We don't need to worry about stepping over the breakpoint here, that
353                         // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
354                         if (bp_site_sp->ValidForThisThread (&thread))
355                             return StopInfo::CreateStopReasonWithBreakpointSiteID (thread, bp_site_sp->GetID());
356                         else
357                             return StopInfoSP();
358                     }
359                     else if (cpu == llvm::Triple::arm)
360                     {
361                         return StopInfo::CreateStopReasonToTrace (thread);
362                     }
363                 }
364             }
365             break;
366 
367         case 7:     // EXC_SYSCALL
368         case 8:     // EXC_MACH_SYSCALL
369         case 9:     // EXC_RPC_ALERT
370         case 10:    // EXC_CRASH
371             break;
372         }
373 
374         return StopInfoSP(new StopInfoMachException (thread, exc_type, exc_data_count, exc_code, exc_sub_code));
375     }
376     return StopInfoSP();
377 }
378