llvm-project/lldb/source/Target/ThreadPlanCallFunction.cpp

270 lines
7.7 KiB
C++
Raw Normal View History

//===-- 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
// Project includes
#include "lldb/lldb-private-log.h"
#include "lldb/Core/Address.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Stream.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#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,
lldb::addr_t arg,
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,
lldb::addr_t *this_arg) :
ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
m_valid (false),
m_stop_other_threads (stop_other_threads),
m_arg_addr (arg),
m_args (NULL),
m_process (thread.GetProcess()),
m_thread (thread)
{
SetOkayToDiscard (discard_on_error);
Process& process = thread.GetProcess();
Target& target = process.GetTarget();
const ABI *abi = process.GetABI();
if (!abi)
return;
lldb::addr_t spBelowRedZone = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize();
SymbolContextList contexts;
SymbolContext context;
ModuleSP executableModuleSP (target.GetExecutableModule());
if (!executableModuleSP ||
!executableModuleSP->FindSymbolsWithNameAndType(ConstString ("start"), eSymbolTypeCode, contexts))
return;
contexts.GetContextAtIndex(0, context);
m_start_addr = context.symbol->GetValue();
lldb::addr_t StartLoadAddr = m_start_addr.GetLoadAddress(&target);
if (!thread.SaveFrameZeroState(m_register_backup))
return;
m_function_addr = function;
lldb::addr_t FunctionLoadAddr = m_function_addr.GetLoadAddress(&target);
if (!abi->PrepareTrivialCall(thread,
spBelowRedZone,
FunctionLoadAddr,
StartLoadAddr,
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
m_arg_addr,
this_arg))
return;
m_valid = true;
}
ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
Address &function,
ValueList &args,
bool stop_other_threads,
bool discard_on_error) :
ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
m_valid (false),
m_stop_other_threads (stop_other_threads),
m_arg_addr (0),
m_args (&args),
m_process (thread.GetProcess()),
m_thread (thread)
{
SetOkayToDiscard (discard_on_error);
Process& process = thread.GetProcess();
Target& target = process.GetTarget();
const ABI *abi = process.GetABI();
if(!abi)
return;
lldb::addr_t spBelowRedZone = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize();
SymbolContextList contexts;
SymbolContext context;
ModuleSP executableModuleSP (target.GetExecutableModule());
if (!executableModuleSP ||
!executableModuleSP->FindSymbolsWithNameAndType(ConstString ("start"), eSymbolTypeCode, contexts))
return;
contexts.GetContextAtIndex(0, context);
m_start_addr = context.symbol->GetValue();
lldb::addr_t StartLoadAddr = m_start_addr.GetLoadAddress(&target);
if(!thread.SaveFrameZeroState(m_register_backup))
return;
m_function_addr = function;
lldb::addr_t FunctionLoadAddr = m_function_addr.GetLoadAddress(&target);
if (!abi->PrepareNormalCall(thread,
spBelowRedZone,
FunctionLoadAddr,
StartLoadAddr,
*m_args))
return;
m_valid = true;
}
ThreadPlanCallFunction::~ThreadPlanCallFunction ()
{
}
void
ThreadPlanCallFunction::GetDescription (Stream *s, lldb::DescriptionLevel level)
{
if (level == lldb::eDescriptionLevelBrief)
{
s->Printf("Function call thread plan");
}
else
{
if (m_args)
s->Printf("Thread plan to call 0x%llx with parsed arguments", m_function_addr.GetLoadAddress(&m_process.GetTarget()), m_arg_addr);
else
s->Printf("Thread plan to call 0x%llx void * argument at: 0x%llx", m_function_addr.GetLoadAddress(&m_process.GetTarget()), m_arg_addr);
}
}
bool
ThreadPlanCallFunction::ValidatePlan (Stream *error)
{
if (!m_valid)
return false;
return true;
}
bool
ThreadPlanCallFunction::PlanExplainsStop ()
{
// If the subplan is running, any crashes are attributable to us.
return (m_subplan_sp.get() != NULL);
}
bool
ThreadPlanCallFunction::ShouldStop (Event *event_ptr)
{
if (PlanExplainsStop())
{
Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
if (log)
{
RegisterContext *reg_ctx = m_thread.GetRegisterContext();
log->PutCString("Function completed. Register state was:");
for (uint32_t register_index = 0, num_registers = reg_ctx->GetRegisterCount();
register_index < num_registers;
++register_index)
{
const char *register_name = reg_ctx->GetRegisterName(register_index);
uint64_t register_value = reg_ctx->ReadRegisterAsUnsigned(register_index, LLDB_INVALID_ADDRESS);
log->Printf(" %s = 0x%llx", register_name, register_value);
}
}
m_thread.RestoreSaveFrameZero(m_register_backup);
m_thread.ClearStackFrames();
SetPlanComplete();
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
ThreadPlanCallFunction::RunState ()
{
return eStateRunning;
}
void
ThreadPlanCallFunction::DidPush ()
{
m_subplan_sp.reset(new ThreadPlanRunToAddress(m_thread, m_start_addr, m_stop_other_threads));
m_thread.QueueThreadPlan(m_subplan_sp, false);
}
bool
ThreadPlanCallFunction::WillStop ()
{
return true;
}
bool
ThreadPlanCallFunction::MischiefManaged ()
{
if (IsPlanComplete())
{
Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
if (log)
log->Printf("Completed call function plan.");
ThreadPlan::MischiefManaged ();
return true;
}
else
{
return false;
}
}