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/Watchpoint.h" 17 #include "lldb/Core/ArchSpec.h" 18 #include "lldb/Core/StreamString.h" 19 #include "lldb/Target/ExecutionContext.h" 20 #include "lldb/Target/Process.h" 21 #include "lldb/Target/RegisterContext.h" 22 #include "lldb/Target/Target.h" 23 #include "lldb/Target/Thread.h" 24 #include "lldb/Target/ThreadPlan.h" 25 #include "lldb/Target/UnixSignals.h" 26 27 using namespace lldb; 28 using namespace lldb_private; 29 30 const char * 31 StopInfoMachException::GetDescription () 32 { 33 if (m_description.empty() && m_value != 0) 34 { 35 ExecutionContext exe_ctx (m_thread.shared_from_this()); 36 Target *target = exe_ctx.GetTargetPtr(); 37 const llvm::Triple::ArchType cpu = target ? target->GetArchitecture().GetMachine() : llvm::Triple::UnknownArch; 38 39 const char *exc_desc = NULL; 40 const char *code_label = "code"; 41 const char *code_desc = NULL; 42 const char *subcode_label = "subcode"; 43 const char *subcode_desc = NULL; 44 switch (m_value) 45 { 46 case 1: // EXC_BAD_ACCESS 47 exc_desc = "EXC_BAD_ACCESS"; 48 subcode_label = "address"; 49 switch (cpu) 50 { 51 case llvm::Triple::arm: 52 switch (m_exc_code) 53 { 54 case 0x101: code_desc = "EXC_ARM_DA_ALIGN"; break; 55 case 0x102: code_desc = "EXC_ARM_DA_DEBUG"; break; 56 } 57 break; 58 59 case llvm::Triple::ppc: 60 case llvm::Triple::ppc64: 61 switch (m_exc_code) 62 { 63 case 0x101: code_desc = "EXC_PPC_VM_PROT_READ"; break; 64 case 0x102: code_desc = "EXC_PPC_BADSPACE"; break; 65 case 0x103: code_desc = "EXC_PPC_UNALIGNED"; break; 66 } 67 break; 68 69 default: 70 break; 71 } 72 break; 73 74 case 2: // EXC_BAD_INSTRUCTION 75 exc_desc = "EXC_BAD_INSTRUCTION"; 76 switch (cpu) 77 { 78 case llvm::Triple::x86: 79 case llvm::Triple::x86_64: 80 if (m_exc_code == 1) 81 code_desc = "EXC_I386_INVOP"; 82 break; 83 84 case llvm::Triple::ppc: 85 case llvm::Triple::ppc64: 86 switch (m_exc_code) 87 { 88 case 1: code_desc = "EXC_PPC_INVALID_SYSCALL"; break; 89 case 2: code_desc = "EXC_PPC_UNIPL_INST"; break; 90 case 3: code_desc = "EXC_PPC_PRIVINST"; break; 91 case 4: code_desc = "EXC_PPC_PRIVREG"; break; 92 case 5: code_desc = "EXC_PPC_TRACE"; break; 93 case 6: code_desc = "EXC_PPC_PERFMON"; break; 94 } 95 break; 96 97 case llvm::Triple::arm: 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 { 111 case llvm::Triple::x86: 112 case llvm::Triple::x86_64: 113 switch (m_exc_code) 114 { 115 case 1: code_desc = "EXC_I386_DIV"; break; 116 case 2: code_desc = "EXC_I386_INTO"; break; 117 case 3: code_desc = "EXC_I386_NOEXT"; break; 118 case 4: code_desc = "EXC_I386_EXTOVR"; break; 119 case 5: code_desc = "EXC_I386_EXTERR"; break; 120 case 6: code_desc = "EXC_I386_EMERR"; break; 121 case 7: code_desc = "EXC_I386_BOUND"; break; 122 case 8: code_desc = "EXC_I386_SSEEXTERR"; break; 123 } 124 break; 125 126 case llvm::Triple::ppc: 127 case llvm::Triple::ppc64: 128 switch (m_exc_code) 129 { 130 case 1: code_desc = "EXC_PPC_OVERFLOW"; break; 131 case 2: code_desc = "EXC_PPC_ZERO_DIVIDE"; break; 132 case 3: code_desc = "EXC_PPC_FLT_INEXACT"; break; 133 case 4: code_desc = "EXC_PPC_FLT_ZERO_DIVIDE"; break; 134 case 5: code_desc = "EXC_PPC_FLT_UNDERFLOW"; break; 135 case 6: code_desc = "EXC_PPC_FLT_OVERFLOW"; break; 136 case 7: code_desc = "EXC_PPC_FLT_NOT_A_NUMBER"; 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 150 case 5: // EXC_SOFTWARE 151 exc_desc = "EXC_SOFTWARE"; 152 if (m_exc_code == 0x10003) 153 { 154 subcode_desc = "EXC_SOFT_SIGNAL"; 155 subcode_label = "signo"; 156 } 157 break; 158 159 case 6: // EXC_BREAKPOINT 160 { 161 exc_desc = "EXC_BREAKPOINT"; 162 switch (cpu) 163 { 164 case llvm::Triple::x86: 165 case llvm::Triple::x86_64: 166 switch (m_exc_code) 167 { 168 case 1: code_desc = "EXC_I386_SGL"; break; 169 case 2: code_desc = "EXC_I386_BPT"; break; 170 } 171 break; 172 173 case llvm::Triple::ppc: 174 case llvm::Triple::ppc64: 175 switch (m_exc_code) 176 { 177 case 1: code_desc = "EXC_PPC_BREAKPOINT"; break; 178 } 179 break; 180 181 case llvm::Triple::arm: 182 switch (m_exc_code) 183 { 184 case 0x101: code_desc = "EXC_ARM_DA_ALIGN"; break; 185 case 0x102: code_desc = "EXC_ARM_DA_DEBUG"; break; 186 case 1: code_desc = "EXC_ARM_BREAKPOINT"; break; 187 } 188 break; 189 190 default: 191 break; 192 } 193 } 194 break; 195 196 case 7: 197 exc_desc = "EXC_SYSCALL"; 198 break; 199 200 case 8: 201 exc_desc = "EXC_MACH_SYSCALL"; 202 break; 203 204 case 9: 205 exc_desc = "EXC_RPC_ALERT"; 206 break; 207 208 case 10: 209 exc_desc = "EXC_CRASH"; 210 break; 211 } 212 213 StreamString strm; 214 215 if (exc_desc) 216 strm.PutCString(exc_desc); 217 else 218 strm.Printf("EXC_??? (%llu)", m_value); 219 220 if (m_exc_data_count >= 1) 221 { 222 if (code_desc) 223 strm.Printf(" (%s=%s", code_label, code_desc); 224 else 225 strm.Printf(" (%s=%llu", code_label, m_exc_code); 226 } 227 228 if (m_exc_data_count >= 2) 229 { 230 if (subcode_desc) 231 strm.Printf(", %s=%s", subcode_label, subcode_desc); 232 else 233 strm.Printf(", %s=0x%llx", subcode_label, m_exc_subcode); 234 } 235 236 if (m_exc_data_count > 0) 237 strm.PutChar(')'); 238 239 m_description.swap (strm.GetString()); 240 } 241 return m_description.c_str(); 242 } 243 244 245 246 247 248 StopInfoSP 249 StopInfoMachException::CreateStopReasonWithMachException 250 ( 251 Thread &thread, 252 uint32_t exc_type, 253 uint32_t exc_data_count, 254 uint64_t exc_code, 255 uint64_t exc_sub_code, 256 uint64_t exc_sub_sub_code, 257 bool pc_already_adjusted, 258 bool adjust_pc_if_needed 259 ) 260 { 261 if (exc_type != 0) 262 { 263 uint32_t pc_decrement = 0; 264 ExecutionContext exe_ctx (thread.shared_from_this()); 265 Target *target = exe_ctx.GetTargetPtr(); 266 const llvm::Triple::ArchType cpu = target ? target->GetArchitecture().GetMachine() : llvm::Triple::UnknownArch; 267 268 switch (exc_type) 269 { 270 case 1: // EXC_BAD_ACCESS 271 break; 272 273 case 2: // EXC_BAD_INSTRUCTION 274 switch (cpu) 275 { 276 case llvm::Triple::ppc: 277 case llvm::Triple::ppc64: 278 switch (exc_code) 279 { 280 case 1: // EXC_PPC_INVALID_SYSCALL 281 case 2: // EXC_PPC_UNIPL_INST 282 case 3: // EXC_PPC_PRIVINST 283 case 4: // EXC_PPC_PRIVREG 284 break; 285 case 5: // EXC_PPC_TRACE 286 return StopInfo::CreateStopReasonToTrace (thread); 287 case 6: // EXC_PPC_PERFMON 288 break; 289 } 290 break; 291 292 default: 293 break; 294 } 295 break; 296 297 case 3: // EXC_ARITHMETIC 298 case 4: // EXC_EMULATION 299 break; 300 301 case 5: // EXC_SOFTWARE 302 if (exc_code == 0x10003) // EXC_SOFT_SIGNAL 303 return StopInfo::CreateStopReasonWithSignal (thread, exc_sub_code); 304 break; 305 306 case 6: // EXC_BREAKPOINT 307 { 308 bool is_software_breakpoint = false; 309 bool is_trace_if_software_breakpoint_missing = false; 310 switch (cpu) 311 { 312 case llvm::Triple::x86: 313 case llvm::Triple::x86_64: 314 if (exc_code == 1) // EXC_I386_SGL 315 { 316 if (!exc_sub_code) 317 return StopInfo::CreateStopReasonToTrace(thread); 318 319 // It's a watchpoint, then. 320 // The exc_sub_code indicates the data break address. 321 lldb::WatchpointSP wp_sp; 322 if (target) 323 wp_sp = target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code); 324 if (wp_sp && wp_sp->IsEnabled()) 325 { 326 // Debugserver may piggyback the hardware index of the fired watchpoint in the exception data. 327 // Set the hardware index if that's the case. 328 if (exc_data_count >=3) 329 wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code); 330 return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID()); 331 } 332 } 333 else if (exc_code == 2 || // EXC_I386_BPT 334 exc_code == 3) // EXC_I386_BPTFLT 335 { 336 // KDP returns EXC_I386_BPTFLT for trace breakpoints 337 if (exc_code == 3) 338 is_trace_if_software_breakpoint_missing = true; 339 340 is_software_breakpoint = true; 341 if (!pc_already_adjusted) 342 pc_decrement = 1; 343 } 344 break; 345 346 case llvm::Triple::ppc: 347 case llvm::Triple::ppc64: 348 is_software_breakpoint = exc_code == 1; // EXC_PPC_BREAKPOINT 349 break; 350 351 case llvm::Triple::arm: 352 if (exc_code == 0x102) 353 { 354 // It's a watchpoint, then, if the exc_sub_code indicates a known/enabled 355 // data break address from our watchpoint list. 356 lldb::WatchpointSP wp_sp; 357 if (target) 358 wp_sp = target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code); 359 if (wp_sp && wp_sp->IsEnabled()) 360 { 361 // Debugserver may piggyback the hardware index of the fired watchpoint in the exception data. 362 // Set the hardware index if that's the case. 363 if (exc_data_count >=3) 364 wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code); 365 return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID()); 366 } 367 // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as EXC_BAD_ACCESS 368 return StopInfo::CreateStopReasonToTrace(thread); 369 } 370 else if (exc_code == 1) 371 { 372 is_software_breakpoint = true; 373 is_trace_if_software_breakpoint_missing = true; 374 } 375 break; 376 377 default: 378 break; 379 } 380 381 if (is_software_breakpoint) 382 { 383 RegisterContextSP reg_ctx_sp (thread.GetRegisterContext()); 384 addr_t pc = reg_ctx_sp->GetPC() - pc_decrement; 385 386 ProcessSP process_sp (thread.CalculateProcess()); 387 388 lldb::BreakpointSiteSP bp_site_sp; 389 if (process_sp) 390 bp_site_sp = process_sp->GetBreakpointSiteList().FindByAddress(pc); 391 if (bp_site_sp && bp_site_sp->IsEnabled()) 392 { 393 // Update the PC if we were asked to do so, but only do 394 // so if we find a breakpoint that we know about cause 395 // this could be a trap instruction in the code 396 if (pc_decrement > 0 && adjust_pc_if_needed) 397 reg_ctx_sp->SetPC (pc); 398 399 // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread, 400 // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that 401 // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc. 402 if (bp_site_sp->ValidForThisThread (&thread)) 403 return StopInfo::CreateStopReasonWithBreakpointSiteID (thread, bp_site_sp->GetID()); 404 else 405 return StopInfoSP(); 406 } 407 408 if (is_trace_if_software_breakpoint_missing) 409 { 410 return StopInfo::CreateStopReasonToTrace (thread); 411 } 412 } 413 } 414 break; 415 416 case 7: // EXC_SYSCALL 417 case 8: // EXC_MACH_SYSCALL 418 case 9: // EXC_RPC_ALERT 419 case 10: // EXC_CRASH 420 break; 421 } 422 423 return StopInfoSP(new StopInfoMachException (thread, exc_type, exc_data_count, exc_code, exc_sub_code)); 424 } 425 return StopInfoSP(); 426 } 427