teak-llvm/lldb/source/DataFormatters/FormattersHelpers.cpp
Jim Ingham 8d94ba0fb1 This change introduces a "ExpressionExecutionThread" to the ThreadList.
Turns out that most of the code that runs expressions (e.g. the ObjC runtime grubber) on
behalf of the expression parser was using the currently selected thread.  But sometimes,
e.g. when we are evaluating breakpoint conditions/commands, we don't select the thread
we're running on, we instead set the context for the interpreter, and explicitly pass
that to other callers.  That wasn't getting communicated to these utility expressions, so
they would run on some other thread instead, and that could cause a variety of subtle and
hard to reproduce problems.  

I also went through the commands and cleaned up the use of GetSelectedThread.  All those
uses should have been trying the thread in the m_exe_ctx belonging to the command object
first.  It would actually have been pretty hard to get misbehavior in these cases, but for
correctness sake it is good to make this usage consistent.

<rdar://problem/24978569>

llvm-svn: 263326
2016-03-12 02:45:34 +00:00

342 lines
13 KiB
C++

//===-- FormattersHelpers.cpp -------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/Core/ConstString.h"
#include "lldb/Core/RegularExpression.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;
void
lldb_private::formatters::AddFormat (TypeCategoryImpl::SharedPointer category_sp,
lldb::Format format,
ConstString type_name,
TypeFormatImpl::Flags flags,
bool regex)
{
lldb::TypeFormatImplSP format_sp(new TypeFormatImpl_Format(format, flags));
if (regex)
category_sp->GetRegexTypeFormatsContainer()->Add(RegularExpressionSP(new RegularExpression(type_name.AsCString())),format_sp);
else
category_sp->GetTypeFormatsContainer()->Add(type_name, format_sp);
}
void
lldb_private::formatters::AddSummary(TypeCategoryImpl::SharedPointer category_sp,
TypeSummaryImplSP summary_sp,
ConstString type_name,
bool regex)
{
if (regex)
category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression(type_name.AsCString())),summary_sp);
else
category_sp->GetTypeSummariesContainer()->Add(type_name, summary_sp);
}
void
lldb_private::formatters::AddStringSummary(TypeCategoryImpl::SharedPointer category_sp,
const char* string,
ConstString type_name,
TypeSummaryImpl::Flags flags,
bool regex)
{
lldb::TypeSummaryImplSP summary_sp(new StringSummaryFormat(flags,
string));
if (regex)
category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression(type_name.AsCString())),summary_sp);
else
category_sp->GetTypeSummariesContainer()->Add(type_name, summary_sp);
}
void
lldb_private::formatters::AddOneLineSummary (TypeCategoryImpl::SharedPointer category_sp,
ConstString type_name,
TypeSummaryImpl::Flags flags,
bool regex)
{
flags.SetShowMembersOneLiner(true);
lldb::TypeSummaryImplSP summary_sp(new StringSummaryFormat(flags, ""));
if (regex)
category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression(type_name.AsCString())),summary_sp);
else
category_sp->GetTypeSummariesContainer()->Add(type_name, summary_sp);
}
#ifndef LLDB_DISABLE_PYTHON
void
lldb_private::formatters::AddCXXSummary (TypeCategoryImpl::SharedPointer category_sp,
CXXFunctionSummaryFormat::Callback funct,
const char* description,
ConstString type_name,
TypeSummaryImpl::Flags flags,
bool regex)
{
lldb::TypeSummaryImplSP summary_sp(new CXXFunctionSummaryFormat(flags,funct,description));
if (regex)
category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression(type_name.AsCString())),summary_sp);
else
category_sp->GetTypeSummariesContainer()->Add(type_name, summary_sp);
}
void
lldb_private::formatters::AddCXXSynthetic (TypeCategoryImpl::SharedPointer category_sp,
CXXSyntheticChildren::CreateFrontEndCallback generator,
const char* description,
ConstString type_name,
ScriptedSyntheticChildren::Flags flags,
bool regex)
{
lldb::SyntheticChildrenSP synth_sp(new CXXSyntheticChildren(flags,description,generator));
if (regex)
category_sp->GetRegexTypeSyntheticsContainer()->Add(RegularExpressionSP(new RegularExpression(type_name.AsCString())), synth_sp);
else
category_sp->GetTypeSyntheticsContainer()->Add(type_name,synth_sp);
}
void
lldb_private::formatters::AddFilter (TypeCategoryImpl::SharedPointer category_sp,
std::vector<std::string> children,
const char* description,
ConstString type_name,
ScriptedSyntheticChildren::Flags flags,
bool regex)
{
TypeFilterImplSP filter_sp(new TypeFilterImpl(flags));
for (auto child : children)
filter_sp->AddExpressionPath(child);
if (regex)
category_sp->GetRegexTypeFiltersContainer()->Add(RegularExpressionSP(new RegularExpression(type_name.AsCString())), filter_sp);
else
category_sp->GetTypeFiltersContainer()->Add(type_name,filter_sp);
}
#endif
StackFrame*
lldb_private::formatters::GetViableFrame (ExecutionContext exe_ctx)
{
StackFrame* frame = exe_ctx.GetFramePtr();
if (frame)
return frame;
Thread *thread = exe_ctx.GetThreadPtr();
if (thread)
return thread->GetSelectedFrame().get();
Process* process = exe_ctx.GetProcessPtr();
if (!process)
return nullptr;
thread = process->GetThreadList().GetSelectedThread().get();
if (thread)
return thread->GetSelectedFrame().get();
return nullptr;
}
bool
lldb_private::formatters::ExtractValueFromObjCExpression (ValueObject &valobj,
const char* target_type,
const char* selector,
uint64_t &value)
{
if (!target_type || !*target_type)
return false;
if (!selector || !*selector)
return false;
StreamString expr;
expr.Printf("(%s)[(id)0x%" PRIx64 " %s]",target_type,valobj.GetPointerValue(),selector);
ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
lldb::ValueObjectSP result_sp;
Target* target = exe_ctx.GetTargetPtr();
StackFrame* stack_frame = GetViableFrame(exe_ctx);
if (!target || !stack_frame)
return false;
EvaluateExpressionOptions options;
options.SetCoerceToId(false);
options.SetUnwindOnError(true);
options.SetKeepInMemory(true);
options.SetLanguage(lldb::eLanguageTypeObjC_plus_plus);
options.SetResultIsInternal(true);
options.SetUseDynamic(lldb::eDynamicCanRunTarget);
target->EvaluateExpression(expr.GetData(),
stack_frame,
result_sp,
options);
if (!result_sp)
return false;
value = result_sp->GetValueAsUnsigned(0);
return true;
}
bool
lldb_private::formatters::ExtractSummaryFromObjCExpression (ValueObject &valobj,
const char* target_type,
const char* selector,
Stream &stream,
lldb::LanguageType lang_type)
{
if (!target_type || !*target_type)
return false;
if (!selector || !*selector)
return false;
StreamString expr;
expr.Printf("(%s)[(id)0x%" PRIx64 " %s]",target_type,valobj.GetPointerValue(),selector);
ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
lldb::ValueObjectSP result_sp;
Target* target = exe_ctx.GetTargetPtr();
StackFrame* stack_frame = GetViableFrame(exe_ctx);
if (!target || !stack_frame)
return false;
EvaluateExpressionOptions options;
options.SetCoerceToId(false);
options.SetUnwindOnError(true);
options.SetKeepInMemory(true);
options.SetLanguage(lldb::eLanguageTypeObjC_plus_plus);
options.SetResultIsInternal(true);
options.SetUseDynamic(lldb::eDynamicCanRunTarget);
target->EvaluateExpression(expr.GetData(),
stack_frame,
result_sp,
options);
if (!result_sp)
return false;
stream.Printf("%s",result_sp->GetSummaryAsCString(lang_type));
return true;
}
lldb::ValueObjectSP
lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj,
const char* return_type,
const char* selector,
uint64_t index)
{
lldb::ValueObjectSP valobj_sp;
if (!return_type || !*return_type)
return valobj_sp;
if (!selector || !*selector)
return valobj_sp;
StreamString expr;
const char *colon = "";
llvm::StringRef selector_sr(selector);
if (selector_sr.back() != ':')
colon = ":";
expr.Printf("(%s)[(id)0x%" PRIx64 " %s%s%" PRId64 "]",return_type,valobj.GetPointerValue(),selector,colon,index);
ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
lldb::ValueObjectSP result_sp;
Target* target = exe_ctx.GetTargetPtr();
StackFrame* stack_frame = GetViableFrame(exe_ctx);
if (!target || !stack_frame)
return valobj_sp;
EvaluateExpressionOptions options;
options.SetCoerceToId(false);
options.SetUnwindOnError(true);
options.SetKeepInMemory(true);
options.SetLanguage(lldb::eLanguageTypeObjC_plus_plus);
options.SetResultIsInternal(true);
options.SetUseDynamic(lldb::eDynamicCanRunTarget);
target->EvaluateExpression(expr.GetData(),
stack_frame,
valobj_sp,
options);
return valobj_sp;
}
lldb::ValueObjectSP
lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj,
const char* return_type,
const char* selector,
const char* key)
{
lldb::ValueObjectSP valobj_sp;
if (!return_type || !*return_type)
return valobj_sp;
if (!selector || !*selector)
return valobj_sp;
if (!key || !*key)
return valobj_sp;
StreamString expr;
const char *colon = "";
llvm::StringRef selector_sr(selector);
if (selector_sr.back() != ':')
colon = ":";
expr.Printf("(%s)[(id)0x%" PRIx64 " %s%s%s]",return_type,valobj.GetPointerValue(),selector,colon,key);
ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
lldb::ValueObjectSP result_sp;
Target* target = exe_ctx.GetTargetPtr();
StackFrame* stack_frame = GetViableFrame(exe_ctx);
if (!target || !stack_frame)
return valobj_sp;
EvaluateExpressionOptions options;
options.SetCoerceToId(false);
options.SetUnwindOnError(true);
options.SetKeepInMemory(true);
options.SetLanguage(lldb::eLanguageTypeObjC_plus_plus);
options.SetResultIsInternal(true);
options.SetUseDynamic(lldb::eDynamicCanRunTarget);
target->EvaluateExpression(expr.GetData(),
stack_frame,
valobj_sp,
options);
return valobj_sp;
}
size_t
lldb_private::formatters::ExtractIndexFromString (const char* item_name)
{
if (!item_name || !*item_name)
return UINT32_MAX;
if (*item_name != '[')
return UINT32_MAX;
item_name++;
char* endptr = NULL;
unsigned long int idx = ::strtoul(item_name, &endptr, 0);
if (idx == 0 && endptr == item_name)
return UINT32_MAX;
if (idx == ULONG_MAX)
return UINT32_MAX;
return idx;
}
lldb::addr_t
lldb_private::formatters::GetArrayAddressOrPointerValue (ValueObject& valobj)
{
lldb::addr_t data_addr = LLDB_INVALID_ADDRESS;
if (valobj.IsPointerType())
data_addr = valobj.GetValueAsUnsigned(0);
else if (valobj.IsArrayType())
data_addr = valobj.GetAddressOf();
return data_addr;
}