2010-06-09 00:52:24 +08:00
|
|
|
//===-- ThreadPlanCallFunction.cpp ------------------------------*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "lldb/Target/ThreadPlanCallFunction.h"
|
|
|
|
|
|
|
|
// C Includes
|
|
|
|
// C++ Includes
|
|
|
|
// Other libraries and framework includes
|
2010-11-03 09:37:52 +08:00
|
|
|
#include "llvm/Support/MachO.h"
|
2010-06-09 00:52:24 +08:00
|
|
|
// Project includes
|
|
|
|
#include "lldb/lldb-private-log.h"
|
2010-10-26 08:27:45 +08:00
|
|
|
#include "lldb/Breakpoint/Breakpoint.h"
|
|
|
|
#include "lldb/Breakpoint/BreakpointLocation.h"
|
2010-06-09 00:52:24 +08:00
|
|
|
#include "lldb/Core/Address.h"
|
|
|
|
#include "lldb/Core/Log.h"
|
|
|
|
#include "lldb/Core/Stream.h"
|
2010-11-04 06:19:38 +08:00
|
|
|
#include "lldb/Target/LanguageRuntime.h"
|
2010-06-09 00:52:24 +08:00
|
|
|
#include "lldb/Target/Process.h"
|
|
|
|
#include "lldb/Target/RegisterContext.h"
|
2010-10-26 08:27:45 +08:00
|
|
|
#include "lldb/Target/StopInfo.h"
|
2010-06-09 00:52:24 +08:00
|
|
|
#include "lldb/Target/Target.h"
|
|
|
|
#include "lldb/Target/Thread.h"
|
|
|
|
#include "lldb/Target/ThreadPlanRunToAddress.h"
|
|
|
|
|
|
|
|
using namespace lldb;
|
|
|
|
using namespace lldb_private;
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// ThreadPlanCallFunction: Plan to call a single function
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
|
|
|
|
Address &function,
|
2011-05-14 09:50:35 +08:00
|
|
|
addr_t arg,
|
2010-06-09 00:52:24 +08:00
|
|
|
bool stop_other_threads,
|
Removed the hacky "#define this ___clang_this" handler
for C++ classes. Replaced it with a less hacky approach:
- If an expression is defined in the context of a
method of class A, then that expression is wrapped as
___clang_class::___clang_expr(void*) { ... }
instead of ___clang_expr(void*) { ... }.
- ___clang_class is resolved as the type of the target
of the "this" pointer in the method the expression
is defined in.
- When reporting the type of ___clang_class, a method
with the signature ___clang_expr(void*) is added to
that class, so that Clang doesn't complain about a
method being defined without a corresponding
declaration.
- Whenever the expression gets called, "this" gets
looked up, type-checked, and then passed in as the
first argument.
This required the following changes:
- The ABIs were changed to support passing of the "this"
pointer as part of trivial calls.
- ThreadPlanCallFunction and ClangFunction were changed
to support passing of an optional "this" pointer.
- ClangUserExpression was extended to perform the
wrapping described above.
- ClangASTSource was changed to revert the changes
required by the hack.
- ClangExpressionParser, IRForTarget, and
ClangExpressionDeclMap were changed to handle
different manglings of ___clang_expr flexibly. This
meant no longer searching for a function called
___clang_expr, but rather looking for a function whose
name *contains* ___clang_expr.
- ClangExpressionParser and ClangExpressionDeclMap now
remember whether "this" is required, and know how to
look it up as necessary.
A few inheritance bugs remain, and I'm trying to resolve
these. But it is now possible to use "this" as well as
refer implicitly to member variables, when in the proper
context.
llvm-svn: 114384
2010-09-21 08:44:12 +08:00
|
|
|
bool discard_on_error,
|
2011-05-14 09:50:35 +08:00
|
|
|
addr_t *this_arg,
|
|
|
|
addr_t *cmd_arg) :
|
2010-06-19 12:45:32 +08:00
|
|
|
ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
|
2010-07-16 20:32:33 +08:00
|
|
|
m_valid (false),
|
|
|
|
m_stop_other_threads (stop_other_threads),
|
2011-08-13 07:34:31 +08:00
|
|
|
m_function_addr (function),
|
2011-06-04 04:41:09 +08:00
|
|
|
m_function_sp (NULL),
|
2010-07-16 20:32:33 +08:00
|
|
|
m_process (thread.GetProcess()),
|
2011-01-22 09:27:23 +08:00
|
|
|
m_thread (thread),
|
2011-06-04 04:41:09 +08:00
|
|
|
m_takedown_done (false)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
SetOkayToDiscard (discard_on_error);
|
|
|
|
|
|
|
|
Process& process = thread.GetProcess();
|
|
|
|
Target& target = process.GetTarget();
|
2011-05-12 02:39:18 +08:00
|
|
|
const ABI *abi = process.GetABI().get();
|
2010-11-03 09:37:52 +08:00
|
|
|
|
2010-06-09 00:52:24 +08:00
|
|
|
if (!abi)
|
|
|
|
return;
|
2010-11-03 09:37:52 +08:00
|
|
|
|
2011-01-20 10:03:18 +08:00
|
|
|
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
|
|
|
|
|
2010-11-03 09:37:52 +08:00
|
|
|
SetBreakpoints();
|
|
|
|
|
2011-05-10 06:04:36 +08:00
|
|
|
m_function_sp = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize();
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2011-08-11 10:48:45 +08:00
|
|
|
Module *exe_module = target.GetExecutableModulePointer();
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2011-08-11 10:48:45 +08:00
|
|
|
if (exe_module == NULL)
|
2011-03-08 07:44:08 +08:00
|
|
|
{
|
2011-08-11 01:58:11 +08:00
|
|
|
if (log)
|
|
|
|
log->Printf ("Can't execute code without an executable module.");
|
2010-06-09 00:52:24 +08:00
|
|
|
return;
|
2011-03-08 07:44:08 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-08-11 10:48:45 +08:00
|
|
|
ObjectFile *objectFile = exe_module->GetObjectFile();
|
2011-03-08 07:44:08 +08:00
|
|
|
if (!objectFile)
|
|
|
|
{
|
2011-08-11 01:58:11 +08:00
|
|
|
if (log)
|
|
|
|
log->Printf ("Could not find object file for module \"%s\".",
|
2011-08-11 12:30:39 +08:00
|
|
|
exe_module->GetFileSpec().GetFilename().AsCString());
|
2011-03-08 07:44:08 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_start_addr = objectFile->GetEntryPointAddress();
|
|
|
|
if (!m_start_addr.IsValid())
|
|
|
|
{
|
2011-08-11 01:58:11 +08:00
|
|
|
if (log)
|
|
|
|
log->Printf ("Could not find entry point address for executable module \"%s\".",
|
2011-08-11 12:30:39 +08:00
|
|
|
exe_module->GetFileSpec().GetFilename().AsCString());
|
2011-03-08 07:44:08 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2011-05-14 09:50:35 +08:00
|
|
|
addr_t start_load_addr = m_start_addr.GetLoadAddress(&target);
|
2011-03-08 07:44:08 +08:00
|
|
|
|
2011-01-20 10:03:18 +08:00
|
|
|
// Checkpoint the thread state so we can restore it later.
|
2011-01-22 09:27:23 +08:00
|
|
|
if (log && log->GetVerbose())
|
|
|
|
ReportRegisterState ("About to checkpoint thread before function call. Original register state was:");
|
|
|
|
|
2011-01-20 10:03:18 +08:00
|
|
|
if (!thread.CheckpointThreadState (m_stored_thread_state))
|
|
|
|
{
|
|
|
|
if (log)
|
|
|
|
log->Printf ("Setting up ThreadPlanCallFunction, failed to checkpoint thread state.");
|
2010-06-09 00:52:24 +08:00
|
|
|
return;
|
2011-01-20 10:03:18 +08:00
|
|
|
}
|
|
|
|
// Now set the thread state to "no reason" so we don't run with whatever signal was outstanding...
|
|
|
|
thread.SetStopInfoToNothing();
|
|
|
|
|
2011-05-14 09:50:35 +08:00
|
|
|
addr_t FunctionLoadAddr = m_function_addr.GetLoadAddress(&target);
|
2010-06-09 00:52:24 +08:00
|
|
|
|
Cleaned up the ABI::PrepareTrivialCall() function to take three argument
pointers:
virtual bool
PrepareTrivialCall (Thread &thread,
lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
lldb::addr_t *arg1_ptr,
lldb::addr_t *arg2_ptr,
lldb::addr_t *arg3_ptr) const = 0;
Prior to this it was:
virtual bool
PrepareTrivialCall (Thread &thread,
lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
lldb::addr_t arg,
lldb::addr_t *this_arg,
lldb::addr_t *cmd_arg) const = 0;
This was because the function that called this slowly added more features to
be able to call a C++ member function that might have a "this" pointer, and
then later added "self + cmd" support for objective C. Cleaning this code up
and the code that calls it makes it easier to implement the functions for
new targets.
The MacOSX_arm::PrepareTrivialCall() is now filled in and ready for testing.
llvm-svn: 131221
2011-05-12 10:14:56 +08:00
|
|
|
if (this_arg && cmd_arg)
|
|
|
|
{
|
|
|
|
if (!abi->PrepareTrivialCall (thread,
|
|
|
|
m_function_sp,
|
|
|
|
FunctionLoadAddr,
|
2011-05-14 09:50:35 +08:00
|
|
|
start_load_addr,
|
Cleaned up the ABI::PrepareTrivialCall() function to take three argument
pointers:
virtual bool
PrepareTrivialCall (Thread &thread,
lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
lldb::addr_t *arg1_ptr,
lldb::addr_t *arg2_ptr,
lldb::addr_t *arg3_ptr) const = 0;
Prior to this it was:
virtual bool
PrepareTrivialCall (Thread &thread,
lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
lldb::addr_t arg,
lldb::addr_t *this_arg,
lldb::addr_t *cmd_arg) const = 0;
This was because the function that called this slowly added more features to
be able to call a C++ member function that might have a "this" pointer, and
then later added "self + cmd" support for objective C. Cleaning this code up
and the code that calls it makes it easier to implement the functions for
new targets.
The MacOSX_arm::PrepareTrivialCall() is now filled in and ready for testing.
llvm-svn: 131221
2011-05-12 10:14:56 +08:00
|
|
|
this_arg,
|
|
|
|
cmd_arg,
|
2011-05-14 09:50:35 +08:00
|
|
|
&arg))
|
Cleaned up the ABI::PrepareTrivialCall() function to take three argument
pointers:
virtual bool
PrepareTrivialCall (Thread &thread,
lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
lldb::addr_t *arg1_ptr,
lldb::addr_t *arg2_ptr,
lldb::addr_t *arg3_ptr) const = 0;
Prior to this it was:
virtual bool
PrepareTrivialCall (Thread &thread,
lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
lldb::addr_t arg,
lldb::addr_t *this_arg,
lldb::addr_t *cmd_arg) const = 0;
This was because the function that called this slowly added more features to
be able to call a C++ member function that might have a "this" pointer, and
then later added "self + cmd" support for objective C. Cleaning this code up
and the code that calls it makes it easier to implement the functions for
new targets.
The MacOSX_arm::PrepareTrivialCall() is now filled in and ready for testing.
llvm-svn: 131221
2011-05-12 10:14:56 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (this_arg)
|
|
|
|
{
|
|
|
|
if (!abi->PrepareTrivialCall (thread,
|
|
|
|
m_function_sp,
|
|
|
|
FunctionLoadAddr,
|
2011-05-14 09:50:35 +08:00
|
|
|
start_load_addr,
|
Cleaned up the ABI::PrepareTrivialCall() function to take three argument
pointers:
virtual bool
PrepareTrivialCall (Thread &thread,
lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
lldb::addr_t *arg1_ptr,
lldb::addr_t *arg2_ptr,
lldb::addr_t *arg3_ptr) const = 0;
Prior to this it was:
virtual bool
PrepareTrivialCall (Thread &thread,
lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
lldb::addr_t arg,
lldb::addr_t *this_arg,
lldb::addr_t *cmd_arg) const = 0;
This was because the function that called this slowly added more features to
be able to call a C++ member function that might have a "this" pointer, and
then later added "self + cmd" support for objective C. Cleaning this code up
and the code that calls it makes it easier to implement the functions for
new targets.
The MacOSX_arm::PrepareTrivialCall() is now filled in and ready for testing.
llvm-svn: 131221
2011-05-12 10:14:56 +08:00
|
|
|
this_arg,
|
2011-05-14 09:50:35 +08:00
|
|
|
&arg))
|
Cleaned up the ABI::PrepareTrivialCall() function to take three argument
pointers:
virtual bool
PrepareTrivialCall (Thread &thread,
lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
lldb::addr_t *arg1_ptr,
lldb::addr_t *arg2_ptr,
lldb::addr_t *arg3_ptr) const = 0;
Prior to this it was:
virtual bool
PrepareTrivialCall (Thread &thread,
lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
lldb::addr_t arg,
lldb::addr_t *this_arg,
lldb::addr_t *cmd_arg) const = 0;
This was because the function that called this slowly added more features to
be able to call a C++ member function that might have a "this" pointer, and
then later added "self + cmd" support for objective C. Cleaning this code up
and the code that calls it makes it easier to implement the functions for
new targets.
The MacOSX_arm::PrepareTrivialCall() is now filled in and ready for testing.
llvm-svn: 131221
2011-05-12 10:14:56 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!abi->PrepareTrivialCall (thread,
|
|
|
|
m_function_sp,
|
|
|
|
FunctionLoadAddr,
|
2011-05-14 09:50:35 +08:00
|
|
|
start_load_addr,
|
|
|
|
&arg))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReportRegisterState ("Function call was set up. Register state was:");
|
|
|
|
|
|
|
|
m_valid = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
|
|
|
|
Address &function,
|
|
|
|
bool stop_other_threads,
|
|
|
|
bool discard_on_error,
|
|
|
|
addr_t *arg1_ptr,
|
|
|
|
addr_t *arg2_ptr,
|
|
|
|
addr_t *arg3_ptr,
|
|
|
|
addr_t *arg4_ptr,
|
|
|
|
addr_t *arg5_ptr,
|
|
|
|
addr_t *arg6_ptr) :
|
|
|
|
ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
|
|
|
|
m_valid (false),
|
|
|
|
m_stop_other_threads (stop_other_threads),
|
2011-08-13 07:34:31 +08:00
|
|
|
m_function_addr (function),
|
2011-06-04 04:41:09 +08:00
|
|
|
m_function_sp(NULL),
|
2011-05-14 09:50:35 +08:00
|
|
|
m_process (thread.GetProcess()),
|
|
|
|
m_thread (thread),
|
2011-06-04 04:41:09 +08:00
|
|
|
m_takedown_done (false)
|
2011-05-14 09:50:35 +08:00
|
|
|
{
|
|
|
|
SetOkayToDiscard (discard_on_error);
|
|
|
|
|
|
|
|
Process& process = thread.GetProcess();
|
|
|
|
Target& target = process.GetTarget();
|
|
|
|
const ABI *abi = process.GetABI().get();
|
|
|
|
|
|
|
|
if (!abi)
|
|
|
|
return;
|
|
|
|
|
|
|
|
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
|
|
|
|
|
|
|
|
SetBreakpoints();
|
|
|
|
|
|
|
|
m_function_sp = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize();
|
|
|
|
|
2011-08-11 10:48:45 +08:00
|
|
|
Module *exe_module = target.GetExecutableModulePointer();
|
2011-05-14 09:50:35 +08:00
|
|
|
|
2011-08-11 10:48:45 +08:00
|
|
|
if (exe_module == NULL)
|
2011-05-14 09:50:35 +08:00
|
|
|
{
|
2011-08-11 01:58:11 +08:00
|
|
|
if (log)
|
|
|
|
log->Printf ("Can't execute code without an executable module.");
|
2011-05-14 09:50:35 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-08-11 10:48:45 +08:00
|
|
|
ObjectFile *objectFile = exe_module->GetObjectFile();
|
2011-05-14 09:50:35 +08:00
|
|
|
if (!objectFile)
|
|
|
|
{
|
2011-08-11 01:58:11 +08:00
|
|
|
if (log)
|
|
|
|
log->Printf ("Could not find object file for module \"%s\".",
|
2011-08-11 12:30:39 +08:00
|
|
|
exe_module->GetFileSpec().GetFilename().AsCString());
|
2011-05-14 09:50:35 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_start_addr = objectFile->GetEntryPointAddress();
|
|
|
|
if (!m_start_addr.IsValid())
|
|
|
|
{
|
2011-05-19 11:54:16 +08:00
|
|
|
if (log)
|
|
|
|
log->Printf ("Could not find entry point address for executable module \"%s\".",
|
2011-08-11 10:48:45 +08:00
|
|
|
exe_module->GetFileSpec().GetFilename().AsCString());
|
2011-05-14 09:50:35 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
addr_t start_load_addr = m_start_addr.GetLoadAddress(&target);
|
|
|
|
|
|
|
|
// Checkpoint the thread state so we can restore it later.
|
|
|
|
if (log && log->GetVerbose())
|
|
|
|
ReportRegisterState ("About to checkpoint thread before function call. Original register state was:");
|
|
|
|
|
|
|
|
if (!thread.CheckpointThreadState (m_stored_thread_state))
|
|
|
|
{
|
|
|
|
if (log)
|
|
|
|
log->Printf ("Setting up ThreadPlanCallFunction, failed to checkpoint thread state.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Now set the thread state to "no reason" so we don't run with whatever signal was outstanding...
|
|
|
|
thread.SetStopInfoToNothing();
|
|
|
|
|
|
|
|
addr_t FunctionLoadAddr = m_function_addr.GetLoadAddress(&target);
|
|
|
|
|
|
|
|
if (!abi->PrepareTrivialCall (thread,
|
|
|
|
m_function_sp,
|
|
|
|
FunctionLoadAddr,
|
|
|
|
start_load_addr,
|
|
|
|
arg1_ptr,
|
|
|
|
arg2_ptr,
|
|
|
|
arg3_ptr,
|
|
|
|
arg4_ptr,
|
|
|
|
arg5_ptr,
|
|
|
|
arg6_ptr))
|
|
|
|
{
|
Cleaned up the ABI::PrepareTrivialCall() function to take three argument
pointers:
virtual bool
PrepareTrivialCall (Thread &thread,
lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
lldb::addr_t *arg1_ptr,
lldb::addr_t *arg2_ptr,
lldb::addr_t *arg3_ptr) const = 0;
Prior to this it was:
virtual bool
PrepareTrivialCall (Thread &thread,
lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
lldb::addr_t arg,
lldb::addr_t *this_arg,
lldb::addr_t *cmd_arg) const = 0;
This was because the function that called this slowly added more features to
be able to call a C++ member function that might have a "this" pointer, and
then later added "self + cmd" support for objective C. Cleaning this code up
and the code that calls it makes it easier to implement the functions for
new targets.
The MacOSX_arm::PrepareTrivialCall() is now filled in and ready for testing.
llvm-svn: 131221
2011-05-12 10:14:56 +08:00
|
|
|
return;
|
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2011-01-22 09:27:23 +08:00
|
|
|
ReportRegisterState ("Function call was set up. Register state was:");
|
|
|
|
|
|
|
|
m_valid = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ThreadPlanCallFunction::~ThreadPlanCallFunction ()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ThreadPlanCallFunction::ReportRegisterState (const char *message)
|
|
|
|
{
|
2011-05-19 11:54:16 +08:00
|
|
|
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP | LIBLLDB_LOG_VERBOSE));
|
2010-11-08 11:49:50 +08:00
|
|
|
if (log)
|
|
|
|
{
|
2011-05-19 11:54:16 +08:00
|
|
|
StreamString strm;
|
2011-01-07 06:15:06 +08:00
|
|
|
RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
|
2011-01-22 09:27:23 +08:00
|
|
|
|
|
|
|
log->PutCString(message);
|
|
|
|
|
2011-05-19 11:54:16 +08:00
|
|
|
RegisterValue reg_value;
|
|
|
|
|
|
|
|
for (uint32_t reg_idx = 0, num_registers = reg_ctx->GetRegisterCount();
|
|
|
|
reg_idx < num_registers;
|
|
|
|
++reg_idx)
|
2010-11-08 11:49:50 +08:00
|
|
|
{
|
2011-05-19 11:54:16 +08:00
|
|
|
const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex (reg_idx);
|
|
|
|
if (reg_ctx->ReadRegister(reg_info, reg_value))
|
|
|
|
{
|
|
|
|
reg_value.Dump(&strm, reg_info, true, false, eFormatDefault);
|
|
|
|
strm.EOL();
|
|
|
|
}
|
2010-11-08 11:49:50 +08:00
|
|
|
}
|
2011-05-19 11:54:16 +08:00
|
|
|
log->PutCString(strm.GetData());
|
2010-11-08 11:49:50 +08:00
|
|
|
}
|
2010-11-04 09:51:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ThreadPlanCallFunction::DoTakedown ()
|
|
|
|
{
|
2011-01-22 09:27:23 +08:00
|
|
|
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
|
|
|
|
if (!m_takedown_done)
|
2011-01-20 10:03:18 +08:00
|
|
|
{
|
2011-05-15 09:25:55 +08:00
|
|
|
// TODO: how do we tell if all went well?
|
|
|
|
if (m_return_value_sp)
|
|
|
|
{
|
|
|
|
const ABI *abi = m_thread.GetProcess().GetABI().get();
|
|
|
|
if (abi)
|
|
|
|
abi->GetReturnValue(m_thread, *m_return_value_sp);
|
|
|
|
}
|
2011-01-22 09:27:23 +08:00
|
|
|
if (log)
|
|
|
|
log->Printf ("DoTakedown called for thread 0x%4.4x, m_valid: %d complete: %d.\n", m_thread.GetID(), m_valid, IsPlanComplete());
|
|
|
|
m_takedown_done = true;
|
2011-05-17 09:10:11 +08:00
|
|
|
m_real_stop_info_sp = GetPrivateStopReason();
|
2011-01-20 10:03:18 +08:00
|
|
|
m_thread.RestoreThreadStateFromCheckpoint(m_stored_thread_state);
|
|
|
|
SetPlanComplete();
|
|
|
|
ClearBreakpoints();
|
2011-01-22 09:27:23 +08:00
|
|
|
if (log && log->GetVerbose())
|
|
|
|
ReportRegisterState ("Restoring thread state after function call. Restored register state:");
|
2011-01-27 03:13:09 +08:00
|
|
|
|
2011-01-22 09:27:23 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (log)
|
|
|
|
log->Printf ("DoTakedown called as no-op for thread 0x%4.4x, m_valid: %d complete: %d.\n", m_thread.GetID(), m_valid, IsPlanComplete());
|
2011-01-20 10:03:18 +08:00
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
|
2011-01-18 09:58:06 +08:00
|
|
|
void
|
|
|
|
ThreadPlanCallFunction::WillPop ()
|
|
|
|
{
|
2011-01-20 10:03:18 +08:00
|
|
|
DoTakedown();
|
2011-01-18 09:58:06 +08:00
|
|
|
}
|
|
|
|
|
2010-06-09 00:52:24 +08:00
|
|
|
void
|
2011-05-14 09:50:35 +08:00
|
|
|
ThreadPlanCallFunction::GetDescription (Stream *s, DescriptionLevel level)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2011-05-14 09:50:35 +08:00
|
|
|
if (level == eDescriptionLevelBrief)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
s->Printf("Function call thread plan");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-05-14 09:50:35 +08:00
|
|
|
s->Printf("Thread plan to call 0x%llx", m_function_addr.GetLoadAddress(&m_process.GetTarget()));
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ThreadPlanCallFunction::ValidatePlan (Stream *error)
|
|
|
|
{
|
|
|
|
if (!m_valid)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ThreadPlanCallFunction::PlanExplainsStop ()
|
2010-11-03 09:37:52 +08:00
|
|
|
{
|
2011-05-17 09:10:11 +08:00
|
|
|
m_real_stop_info_sp = GetPrivateStopReason();
|
|
|
|
|
2010-10-26 08:27:45 +08:00
|
|
|
// If our subplan knows why we stopped, even if it's done (which would forward the question to us)
|
|
|
|
// we answer yes.
|
The implementation of categories is now synchronization safe
Code cleanup:
- The Format Manager implementation is now split between two files: FormatClasses.{h|cpp} where the
actual formatter classes (ValueFormat, SummaryFormat, ...) are implemented and
FormatManager.{h|cpp} where the infrastructure classes (FormatNavigator, FormatManager, ...)
are contained. The wrapper code always remains in Debugger.{h|cpp}
- Several leftover fields, methods and comments from previous design choices have been removed
type category subcommands (enable, disable, delete) now can take a list of category names as input
- for type category enable, saying "enable A B C" is the same as saying
enable C
enable B
enable A
(the ordering is relevant in enabling categories, and it is expected that a user typing
enable A B C wants to look into category A, then into B, then into C and not the other
way round)
- for the other two commands, the order is not really relevant (however, the same inverted ordering
is used for consistency)
llvm-svn: 135494
2011-07-20 02:03:25 +08:00
|
|
|
if (m_subplan_sp.get() != NULL && m_subplan_sp->PlanExplainsStop())
|
2010-10-26 08:27:45 +08:00
|
|
|
return true;
|
2010-10-20 06:24:06 +08:00
|
|
|
|
2010-11-04 03:36:28 +08:00
|
|
|
// Check if the breakpoint is one of ours.
|
|
|
|
|
|
|
|
if (BreakpointsExplainStop())
|
|
|
|
return true;
|
|
|
|
|
2010-10-26 08:27:45 +08:00
|
|
|
// If we don't want to discard this plan, than any stop we don't understand should be propagated up the stack.
|
|
|
|
if (!OkayToDiscard())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Otherwise, check the case where we stopped for an internal breakpoint, in that case, continue on.
|
|
|
|
// If it is not an internal breakpoint, consult OkayToDiscard.
|
2010-11-03 09:37:52 +08:00
|
|
|
|
2011-05-17 09:10:11 +08:00
|
|
|
if (m_real_stop_info_sp && m_real_stop_info_sp->GetStopReason() == eStopReasonBreakpoint)
|
2010-10-26 08:27:45 +08:00
|
|
|
{
|
2011-05-17 09:10:11 +08:00
|
|
|
uint64_t break_site_id = m_real_stop_info_sp->GetValue();
|
2011-05-14 09:50:35 +08:00
|
|
|
BreakpointSiteSP bp_site_sp = m_thread.GetProcess().GetBreakpointSiteList().FindByID(break_site_id);
|
2010-10-26 08:27:45 +08:00
|
|
|
if (bp_site_sp)
|
|
|
|
{
|
|
|
|
uint32_t num_owners = bp_site_sp->GetNumberOfOwners();
|
|
|
|
bool is_internal = true;
|
|
|
|
for (uint32_t i = 0; i < num_owners; i++)
|
|
|
|
{
|
2010-11-03 09:37:52 +08:00
|
|
|
Breakpoint &bp = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint();
|
|
|
|
|
|
|
|
if (!bp.IsInternal())
|
2010-10-26 08:27:45 +08:00
|
|
|
{
|
|
|
|
is_internal = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (is_internal)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return OkayToDiscard();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// If the subplan is running, any crashes are attributable to us.
|
2011-01-27 03:13:09 +08:00
|
|
|
// If we want to discard the plan, then we say we explain the stop
|
|
|
|
// but if we are going to be discarded, let whoever is above us
|
|
|
|
// explain the stop.
|
|
|
|
return ((m_subplan_sp.get() != NULL) && !OkayToDiscard());
|
2010-10-26 08:27:45 +08:00
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ThreadPlanCallFunction::ShouldStop (Event *event_ptr)
|
|
|
|
{
|
|
|
|
if (PlanExplainsStop())
|
|
|
|
{
|
2011-01-22 09:27:23 +08:00
|
|
|
ReportRegisterState ("Function completed. Register state was:");
|
2010-07-31 09:32:05 +08:00
|
|
|
|
2010-11-04 09:51:38 +08:00
|
|
|
DoTakedown();
|
2010-11-03 09:37:52 +08:00
|
|
|
|
2010-06-09 00:52:24 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ThreadPlanCallFunction::StopOthers ()
|
|
|
|
{
|
|
|
|
return m_stop_other_threads;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ThreadPlanCallFunction::SetStopOthers (bool new_value)
|
|
|
|
{
|
|
|
|
if (m_subplan_sp)
|
|
|
|
{
|
|
|
|
ThreadPlanRunToAddress *address_plan = static_cast<ThreadPlanRunToAddress *>(m_subplan_sp.get());
|
|
|
|
address_plan->SetStopOthers(new_value);
|
|
|
|
}
|
|
|
|
m_stop_other_threads = new_value;
|
|
|
|
}
|
|
|
|
|
|
|
|
StateType
|
2010-11-12 03:26:09 +08:00
|
|
|
ThreadPlanCallFunction::GetPlanRunState ()
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
return eStateRunning;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ThreadPlanCallFunction::DidPush ()
|
|
|
|
{
|
2010-10-26 08:31:56 +08:00
|
|
|
//#define SINGLE_STEP_EXPRESSIONS
|
|
|
|
|
|
|
|
#ifndef SINGLE_STEP_EXPRESSIONS
|
2010-06-09 00:52:24 +08:00
|
|
|
m_subplan_sp.reset(new ThreadPlanRunToAddress(m_thread, m_start_addr, m_stop_other_threads));
|
|
|
|
|
|
|
|
m_thread.QueueThreadPlan(m_subplan_sp, false);
|
2011-01-20 10:03:18 +08:00
|
|
|
m_subplan_sp->SetPrivate (true);
|
2010-10-26 08:31:56 +08:00
|
|
|
#endif
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ThreadPlanCallFunction::WillStop ()
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ThreadPlanCallFunction::MischiefManaged ()
|
|
|
|
{
|
|
|
|
if (IsPlanComplete())
|
|
|
|
{
|
2010-11-06 09:53:30 +08:00
|
|
|
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
|
2010-06-09 00:52:24 +08:00
|
|
|
|
|
|
|
if (log)
|
|
|
|
log->Printf("Completed call function plan.");
|
|
|
|
|
|
|
|
ThreadPlan::MischiefManaged ();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2010-11-03 09:37:52 +08:00
|
|
|
|
|
|
|
void
|
|
|
|
ThreadPlanCallFunction::SetBreakpoints ()
|
|
|
|
{
|
2010-11-04 06:19:38 +08:00
|
|
|
m_cxx_language_runtime = m_process.GetLanguageRuntime(eLanguageTypeC_plus_plus);
|
|
|
|
m_objc_language_runtime = m_process.GetLanguageRuntime(eLanguageTypeObjC);
|
2010-11-03 09:37:52 +08:00
|
|
|
|
2010-11-04 06:19:38 +08:00
|
|
|
if (m_cxx_language_runtime)
|
|
|
|
m_cxx_language_runtime->SetExceptionBreakpoints();
|
|
|
|
if (m_objc_language_runtime)
|
|
|
|
m_objc_language_runtime->SetExceptionBreakpoints();
|
2010-11-03 09:37:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ThreadPlanCallFunction::ClearBreakpoints ()
|
|
|
|
{
|
2010-11-04 06:19:38 +08:00
|
|
|
if (m_cxx_language_runtime)
|
|
|
|
m_cxx_language_runtime->ClearExceptionBreakpoints();
|
|
|
|
if (m_objc_language_runtime)
|
|
|
|
m_objc_language_runtime->ClearExceptionBreakpoints();
|
2010-11-03 09:37:52 +08:00
|
|
|
}
|
2010-11-04 03:36:28 +08:00
|
|
|
|
|
|
|
bool
|
|
|
|
ThreadPlanCallFunction::BreakpointsExplainStop()
|
|
|
|
{
|
2011-05-14 09:50:35 +08:00
|
|
|
StopInfoSP stop_info_sp = GetPrivateStopReason();
|
2010-11-04 03:36:28 +08:00
|
|
|
|
2010-11-04 06:19:38 +08:00
|
|
|
if (m_cxx_language_runtime &&
|
|
|
|
m_cxx_language_runtime->ExceptionBreakpointsExplainStop(stop_info_sp))
|
|
|
|
return true;
|
2010-11-04 03:36:28 +08:00
|
|
|
|
2010-11-04 06:19:38 +08:00
|
|
|
if (m_objc_language_runtime &&
|
|
|
|
m_objc_language_runtime->ExceptionBreakpointsExplainStop(stop_info_sp))
|
|
|
|
return true;
|
2010-11-04 03:36:28 +08:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|