ThreadPlanCallFunction.cpp revision 94fb5432f10882f8917acb7849abdba7c61277ac
1//===-- ThreadPlanCallFunction.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 "lldb/Target/ThreadPlanCallFunction.h" 11 12// C Includes 13// C++ Includes 14// Other libraries and framework includes 15#include "llvm/Support/MachO.h" 16// Project includes 17#include "lldb/lldb-private-log.h" 18#include "lldb/Breakpoint/Breakpoint.h" 19#include "lldb/Breakpoint/BreakpointLocation.h" 20#include "lldb/Core/Address.h" 21#include "lldb/Core/Log.h" 22#include "lldb/Core/Stream.h" 23#include "lldb/Target/Process.h" 24#include "lldb/Target/RegisterContext.h" 25#include "lldb/Target/StopInfo.h" 26#include "lldb/Target/Target.h" 27#include "lldb/Target/Thread.h" 28#include "lldb/Target/ThreadPlanRunToAddress.h" 29 30using namespace lldb; 31using namespace lldb_private; 32 33//---------------------------------------------------------------------- 34// ThreadPlanCallFunction: Plan to call a single function 35//---------------------------------------------------------------------- 36 37ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread, 38 Address &function, 39 lldb::addr_t arg, 40 bool stop_other_threads, 41 bool discard_on_error, 42 lldb::addr_t *this_arg) : 43 ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion), 44 m_valid (false), 45 m_stop_other_threads (stop_other_threads), 46 m_arg_addr (arg), 47 m_args (NULL), 48 m_process (thread.GetProcess()), 49 m_thread (thread) 50{ 51 SetOkayToDiscard (discard_on_error); 52 53 Process& process = thread.GetProcess(); 54 Target& target = process.GetTarget(); 55 const ABI *abi = process.GetABI(); 56 57 if (!abi) 58 return; 59 60 SetBreakpoints(); 61 62 lldb::addr_t spBelowRedZone = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize(); 63 64 SymbolContextList contexts; 65 SymbolContext context; 66 ModuleSP executableModuleSP (target.GetExecutableModule()); 67 68 if (!executableModuleSP || 69 !executableModuleSP->FindSymbolsWithNameAndType(ConstString ("start"), eSymbolTypeCode, contexts)) 70 return; 71 72 contexts.GetContextAtIndex(0, context); 73 74 m_start_addr = context.symbol->GetValue(); 75 lldb::addr_t StartLoadAddr = m_start_addr.GetLoadAddress(&target); 76 77 if (!thread.SaveFrameZeroState(m_register_backup)) 78 return; 79 80 m_function_addr = function; 81 lldb::addr_t FunctionLoadAddr = m_function_addr.GetLoadAddress(&target); 82 83 if (!abi->PrepareTrivialCall(thread, 84 spBelowRedZone, 85 FunctionLoadAddr, 86 StartLoadAddr, 87 m_arg_addr, 88 this_arg)) 89 return; 90 91 m_valid = true; 92} 93 94ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread, 95 Address &function, 96 ValueList &args, 97 bool stop_other_threads, 98 bool discard_on_error) : 99 ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion), 100 m_valid (false), 101 m_stop_other_threads (stop_other_threads), 102 m_arg_addr (0), 103 m_args (&args), 104 m_process (thread.GetProcess()), 105 m_thread (thread) 106{ 107 108 SetOkayToDiscard (discard_on_error); 109 110 Process& process = thread.GetProcess(); 111 Target& target = process.GetTarget(); 112 const ABI *abi = process.GetABI(); 113 114 if(!abi) 115 return; 116 117 SetBreakpoints(); 118 119 lldb::addr_t spBelowRedZone = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize(); 120 121 SymbolContextList contexts; 122 SymbolContext context; 123 ModuleSP executableModuleSP (target.GetExecutableModule()); 124 125 if (!executableModuleSP || 126 !executableModuleSP->FindSymbolsWithNameAndType(ConstString ("start"), eSymbolTypeCode, contexts)) 127 return; 128 129 contexts.GetContextAtIndex(0, context); 130 131 m_start_addr = context.symbol->GetValue(); 132 lldb::addr_t StartLoadAddr = m_start_addr.GetLoadAddress(&target); 133 134 if(!thread.SaveFrameZeroState(m_register_backup)) 135 return; 136 137 m_function_addr = function; 138 lldb::addr_t FunctionLoadAddr = m_function_addr.GetLoadAddress(&target); 139 140 if (!abi->PrepareNormalCall(thread, 141 spBelowRedZone, 142 FunctionLoadAddr, 143 StartLoadAddr, 144 *m_args)) 145 return; 146 147 m_valid = true; 148} 149 150ThreadPlanCallFunction::~ThreadPlanCallFunction () 151{ 152} 153 154void 155ThreadPlanCallFunction::GetDescription (Stream *s, lldb::DescriptionLevel level) 156{ 157 if (level == lldb::eDescriptionLevelBrief) 158 { 159 s->Printf("Function call thread plan"); 160 } 161 else 162 { 163 if (m_args) 164 s->Printf("Thread plan to call 0x%llx with parsed arguments", m_function_addr.GetLoadAddress(&m_process.GetTarget()), m_arg_addr); 165 else 166 s->Printf("Thread plan to call 0x%llx void * argument at: 0x%llx", m_function_addr.GetLoadAddress(&m_process.GetTarget()), m_arg_addr); 167 } 168} 169 170bool 171ThreadPlanCallFunction::ValidatePlan (Stream *error) 172{ 173 if (!m_valid) 174 return false; 175 176 return true; 177} 178 179bool 180ThreadPlanCallFunction::PlanExplainsStop () 181{ 182 // If our subplan knows why we stopped, even if it's done (which would forward the question to us) 183 // we answer yes. 184 if(m_subplan_sp.get() != NULL && m_subplan_sp->PlanExplainsStop()) 185 return true; 186 187 // Check if the breakpoint is one of ours. 188 189 if (BreakpointsExplainStop()) 190 return true; 191 192 // If we don't want to discard this plan, than any stop we don't understand should be propagated up the stack. 193 if (!OkayToDiscard()) 194 return false; 195 196 // Otherwise, check the case where we stopped for an internal breakpoint, in that case, continue on. 197 // If it is not an internal breakpoint, consult OkayToDiscard. 198 lldb::StopInfoSP stop_info_sp = GetPrivateStopReason(); 199 200 if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonBreakpoint) 201 { 202 uint64_t break_site_id = stop_info_sp->GetValue(); 203 lldb::BreakpointSiteSP bp_site_sp = m_thread.GetProcess().GetBreakpointSiteList().FindByID(break_site_id); 204 if (bp_site_sp) 205 { 206 uint32_t num_owners = bp_site_sp->GetNumberOfOwners(); 207 bool is_internal = true; 208 for (uint32_t i = 0; i < num_owners; i++) 209 { 210 Breakpoint &bp = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint(); 211 212 if (!bp.IsInternal()) 213 { 214 is_internal = false; 215 break; 216 } 217 } 218 if (is_internal) 219 return false; 220 } 221 222 return OkayToDiscard(); 223 } 224 else 225 { 226 // If the subplan is running, any crashes are attributable to us. 227 return (m_subplan_sp.get() != NULL); 228 } 229} 230 231bool 232ThreadPlanCallFunction::ShouldStop (Event *event_ptr) 233{ 234 if (PlanExplainsStop()) 235 { 236 Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP); 237 238 if (log) 239 { 240 RegisterContext *reg_ctx = m_thread.GetRegisterContext(); 241 242 log->PutCString("Function completed. Register state was:"); 243 244 for (uint32_t register_index = 0, num_registers = reg_ctx->GetRegisterCount(); 245 register_index < num_registers; 246 ++register_index) 247 { 248 const char *register_name = reg_ctx->GetRegisterName(register_index); 249 uint64_t register_value = reg_ctx->ReadRegisterAsUnsigned(register_index, LLDB_INVALID_ADDRESS); 250 251 log->Printf(" %s = 0x%llx", register_name, register_value); 252 } 253 } 254 255 m_thread.RestoreSaveFrameZero(m_register_backup); 256 m_thread.ClearStackFrames(); 257 SetPlanComplete(); 258 259 ClearBreakpoints(); 260 return true; 261 } 262 else 263 { 264 return false; 265 } 266} 267 268bool 269ThreadPlanCallFunction::StopOthers () 270{ 271 return m_stop_other_threads; 272} 273 274void 275ThreadPlanCallFunction::SetStopOthers (bool new_value) 276{ 277 if (m_subplan_sp) 278 { 279 ThreadPlanRunToAddress *address_plan = static_cast<ThreadPlanRunToAddress *>(m_subplan_sp.get()); 280 address_plan->SetStopOthers(new_value); 281 } 282 m_stop_other_threads = new_value; 283} 284 285StateType 286ThreadPlanCallFunction::RunState () 287{ 288 return eStateRunning; 289} 290 291void 292ThreadPlanCallFunction::DidPush () 293{ 294//#define SINGLE_STEP_EXPRESSIONS 295 296#ifndef SINGLE_STEP_EXPRESSIONS 297 m_subplan_sp.reset(new ThreadPlanRunToAddress(m_thread, m_start_addr, m_stop_other_threads)); 298 299 m_thread.QueueThreadPlan(m_subplan_sp, false); 300#endif 301} 302 303bool 304ThreadPlanCallFunction::WillStop () 305{ 306 return true; 307} 308 309bool 310ThreadPlanCallFunction::MischiefManaged () 311{ 312 if (IsPlanComplete()) 313 { 314 Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP); 315 316 if (log) 317 log->Printf("Completed call function plan."); 318 319 ThreadPlan::MischiefManaged (); 320 return true; 321 } 322 else 323 { 324 return false; 325 } 326} 327 328void 329ThreadPlanCallFunction::SetBreakpoints () 330{ 331 Target& target = m_process.GetTarget(); 332 333 ArchSpec arch_spec = target.GetArchitecture(); 334 335 switch (arch_spec.GetCPUType()) 336 { 337 default: 338 break; 339 case llvm::MachO::CPUTypeI386: 340 m_cxx_exception_bp_sp = target.CreateBreakpoint (NULL, 341 "__cxa_throw", 342 eFunctionNameTypeBase, 343 true); 344 m_cxx_exception_alloc_bp_sp = target.CreateBreakpoint (NULL, 345 "__cxa_allocate", 346 eFunctionNameTypeBase, 347 true); 348 m_objc_exception_bp_sp = target.CreateBreakpoint (NULL, 349 "objc_exception_throw", 350 eFunctionNameTypeBase, 351 true); 352 break; 353 case llvm::MachO::CPUTypeX86_64: 354 m_cxx_exception_bp_sp = target.CreateBreakpoint (NULL, 355 "__cxa_throw", 356 eFunctionNameTypeBase, 357 true); 358 m_cxx_exception_alloc_bp_sp = target.CreateBreakpoint (NULL, 359 "__cxa_allocate", 360 eFunctionNameTypeBase, 361 true); 362 break; 363 } 364} 365 366void 367ThreadPlanCallFunction::ClearBreakpoints () 368{ 369 Target& target = m_process.GetTarget(); 370 371 if (m_cxx_exception_bp_sp.get()) 372 { 373 target.RemoveBreakpointByID(m_cxx_exception_bp_sp->GetID()); 374 m_cxx_exception_bp_sp.reset(); 375 } 376 377 if (m_cxx_exception_alloc_bp_sp.get()) 378 { 379 target.RemoveBreakpointByID(m_cxx_exception_alloc_bp_sp->GetID()); 380 m_cxx_exception_bp_sp.reset(); 381 } 382 383 if (m_objc_exception_bp_sp.get()) 384 { 385 target.RemoveBreakpointByID(m_objc_exception_bp_sp->GetID()); 386 m_cxx_exception_bp_sp.reset(); 387 } 388} 389 390bool 391ThreadPlanCallFunction::BreakpointsExplainStop() 392{ 393 // A temporary fix to set breakpoints at points where exceptions are being 394 // thrown. This functionality will migrate into the Target. 395 396 lldb::StopInfoSP stop_info_sp = GetPrivateStopReason(); 397 398 if (!stop_info_sp || 399 stop_info_sp->GetStopReason() != eStopReasonBreakpoint) 400 return false; 401 402 uint64_t break_site_id = stop_info_sp->GetValue(); 403 lldb::BreakpointSiteSP bp_site_sp = m_thread.GetProcess().GetBreakpointSiteList().FindByID(break_site_id); 404 405 if (!bp_site_sp) 406 return false; 407 408 uint32_t num_owners = bp_site_sp->GetNumberOfOwners(); 409 410 bool check_cxx_exception = false; 411 break_id_t cxx_exception_bid; 412 413 bool check_cxx_exception_alloc = false; 414 break_id_t cxx_exception_alloc_bid; 415 416 bool check_objc_exception = false; 417 break_id_t objc_exception_bid; 418 419 if (m_cxx_exception_bp_sp.get()) 420 { 421 check_cxx_exception = true; 422 cxx_exception_bid = m_cxx_exception_bp_sp->GetID(); 423 } 424 425 if (m_cxx_exception_bp_sp.get()) 426 { 427 check_cxx_exception_alloc = true; 428 cxx_exception_alloc_bid = m_cxx_exception_alloc_bp_sp->GetID(); 429 } 430 431 if (m_cxx_exception_bp_sp.get()) 432 { 433 check_objc_exception = true; 434 objc_exception_bid = m_objc_exception_bp_sp->GetID(); 435 } 436 437 438 for (uint32_t i = 0; i < num_owners; i++) 439 { 440 break_id_t bid = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().GetID(); 441 442 if ((check_cxx_exception && (bid == cxx_exception_bid)) || 443 (check_cxx_exception_alloc && (bid == cxx_exception_alloc_bid)) || 444 (check_objc_exception && (bid == objc_exception_bid))) 445 return true; 446 } 447 448 return false; 449} 450