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