mirror of
https://github.com/intel/llvm.git
synced 2026-01-17 14:48:27 +08:00
Fixed a bug where Objective-C variables coming out of the expression parser could crash the Python synthetic providers: - expression parser output has a "frozen data" component, which is a byte-exact copy of the value (in host memory), if trying to read into memory based on the host address, LLDB would crash. we are now passing the correct (target) pointer to the Python code Objective-C "id" variables are now formatted according to their dynamic type, if the -d option to frame variable is used: - Code based on the Objective-C 2.0 runtime is used to obtain this information without running code on the target llvm-svn: 136695
234 lines
8.6 KiB
C++
234 lines
8.6 KiB
C++
//===-- FormatClasses.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
|
|
#include <ostream>
|
|
|
|
// Other libraries and framework includes
|
|
|
|
// Project includes
|
|
#include "lldb/lldb-public.h"
|
|
#include "lldb/lldb-enumerations.h"
|
|
|
|
#include "lldb/Core/Debugger.h"
|
|
#include "lldb/Core/FormatClasses.h"
|
|
#include "lldb/Core/StreamString.h"
|
|
#include "lldb/Core/ValueObjectConstResult.h"
|
|
#include "lldb/Interpreter/CommandInterpreter.h"
|
|
#include "lldb/Symbol/ClangASTType.h"
|
|
#include "lldb/Target/StackFrame.h"
|
|
#include "lldb/Target/Target.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
std::string
|
|
ValueFormat::FormatObject(lldb::ValueObjectSP object)
|
|
{
|
|
if (!object.get())
|
|
return "NULL";
|
|
|
|
StreamString sstr;
|
|
|
|
if (ClangASTType::DumpTypeValue (object->GetClangAST(), // The clang AST
|
|
object->GetClangType(), // The clang type to display
|
|
&sstr,
|
|
m_format, // Format to display this type with
|
|
object->GetDataExtractor(), // Data to extract from
|
|
0, // Byte offset into "data"
|
|
object->GetByteSize(), // Byte size of item in "data"
|
|
object->GetBitfieldBitSize(), // Bitfield bit size
|
|
object->GetBitfieldBitOffset())) // Bitfield bit offset
|
|
return (sstr.GetString());
|
|
else
|
|
{
|
|
return ("unsufficient data for value");
|
|
}
|
|
}
|
|
|
|
std::string
|
|
StringSummaryFormat::FormatObject(lldb::ValueObjectSP object)
|
|
{
|
|
if (!object.get())
|
|
return "NULL";
|
|
|
|
StreamString s;
|
|
ExecutionContext exe_ctx;
|
|
object->GetExecutionContextScope()->CalculateExecutionContext(exe_ctx);
|
|
SymbolContext sc;
|
|
if (exe_ctx.frame)
|
|
sc = exe_ctx.frame->GetSymbolContext(lldb::eSymbolContextEverything);
|
|
|
|
if (m_show_members_oneliner)
|
|
{
|
|
ValueObjectSP synth_vobj = object->GetSyntheticValue(lldb::eUseSyntheticFilter);
|
|
const uint32_t num_children = synth_vobj->GetNumChildren();
|
|
if (num_children)
|
|
{
|
|
s.PutChar('(');
|
|
|
|
for (uint32_t idx=0; idx<num_children; ++idx)
|
|
{
|
|
lldb::ValueObjectSP child_sp(synth_vobj->GetChildAtIndex(idx, true));
|
|
if (child_sp.get())
|
|
{
|
|
if (idx)
|
|
s.PutCString(", ");
|
|
s.PutCString(child_sp.get()->GetName().AsCString());
|
|
s.PutChar('=');
|
|
s.PutCString(child_sp.get()->GetPrintableRepresentation());
|
|
}
|
|
}
|
|
|
|
s.PutChar(')');
|
|
|
|
return s.GetString();
|
|
}
|
|
else
|
|
return "";
|
|
|
|
}
|
|
else
|
|
{
|
|
if (Debugger::FormatPrompt(m_format.c_str(), &sc, &exe_ctx, &sc.line_entry.range.GetBaseAddress(), s, NULL, object.get()))
|
|
return s.GetString();
|
|
else
|
|
return "";
|
|
}
|
|
}
|
|
|
|
std::string
|
|
StringSummaryFormat::GetDescription()
|
|
{
|
|
StreamString sstr;
|
|
sstr.Printf ("`%s`%s%s%s%s%s%s", m_format.c_str(),
|
|
m_cascades ? "" : " (not cascading)",
|
|
m_dont_show_children ? "" : " (show children)",
|
|
m_dont_show_value ? " (hide value)" : "",
|
|
m_show_members_oneliner ? " (one-line printout)" : "",
|
|
m_skip_pointers ? " (skip pointers)" : "",
|
|
m_skip_references ? " (skip references)" : "");
|
|
return sstr.GetString();
|
|
}
|
|
|
|
std::string
|
|
ScriptSummaryFormat::FormatObject(lldb::ValueObjectSP object)
|
|
{
|
|
lldb::ValueObjectSP target_object;
|
|
if (object->GetIsExpressionResult() &&
|
|
ClangASTContext::IsPointerType(object->GetClangType()) &&
|
|
object->GetValue().GetValueType() == Value::eValueTypeHostAddress)
|
|
{
|
|
// when using the expression parser, an additional layer of "frozen data"
|
|
// can be created, which is basically a byte-exact copy of the data returned
|
|
// by the expression, but in host memory. because Python code might need to read
|
|
// into the object memory in non-obvious ways, we need to hand it the target version
|
|
// of the expression output
|
|
lldb::addr_t tgt_address = object->GetValueAsUnsigned();
|
|
target_object = ValueObjectConstResult::Create (object->GetExecutionContextScope(),
|
|
object->GetClangAST(),
|
|
object->GetClangType(),
|
|
object->GetName(),
|
|
tgt_address,
|
|
eAddressTypeLoad,
|
|
object->GetUpdatePoint().GetProcessSP()->GetAddressByteSize());
|
|
}
|
|
else
|
|
target_object = object;
|
|
return std::string(ScriptInterpreterPython::CallPythonScriptFunction(m_function_name.c_str(),
|
|
target_object).c_str());
|
|
}
|
|
|
|
std::string
|
|
ScriptSummaryFormat::GetDescription()
|
|
{
|
|
StreamString sstr;
|
|
sstr.Printf ("%s%s%s%s%s%s\n%s", m_cascades ? "" : " (not cascading)",
|
|
m_dont_show_children ? "" : " (show children)",
|
|
m_dont_show_value ? " (hide value)" : "",
|
|
m_show_members_oneliner ? " (one-line printout)" : "",
|
|
m_skip_pointers ? " (skip pointers)" : "",
|
|
m_skip_references ? " (skip references)" : "",
|
|
m_python_script.c_str());
|
|
return sstr.GetString();
|
|
|
|
}
|
|
|
|
std::string
|
|
SyntheticFilter::GetDescription()
|
|
{
|
|
StreamString sstr;
|
|
sstr.Printf("%s%s%s {\n",
|
|
m_cascades ? "" : " (not cascading)",
|
|
m_skip_pointers ? " (skip pointers)" : "",
|
|
m_skip_references ? " (skip references)" : "");
|
|
|
|
for (int i = 0; i < GetCount(); i++)
|
|
{
|
|
sstr.Printf(" %s\n",
|
|
GetExpressionPathAtIndex(i).c_str());
|
|
}
|
|
|
|
sstr.Printf("}");
|
|
return sstr.GetString();
|
|
}
|
|
|
|
SyntheticScriptProvider::FrontEnd::FrontEnd(std::string pclass,
|
|
lldb::ValueObjectSP be) :
|
|
SyntheticChildrenFrontEnd(be),
|
|
m_python_class(pclass)
|
|
{
|
|
if (be.get() == NULL)
|
|
{
|
|
m_interpreter = NULL;
|
|
m_wrapper = NULL;
|
|
return;
|
|
}
|
|
|
|
if (be->GetIsExpressionResult() &&
|
|
ClangASTContext::IsPointerType(be->GetClangType()) &&
|
|
be->GetValue().GetValueType() == Value::eValueTypeHostAddress)
|
|
{
|
|
// when using the expression parser, an additional layer of "frozen data"
|
|
// can be created, which is basically a byte-exact copy of the data returned
|
|
// by the expression, but in host memory. because Python code might need to read
|
|
// into the object memory in non-obvious ways, we need to hand it the target version
|
|
// of the expression output
|
|
lldb::addr_t tgt_address = be->GetValueAsUnsigned();
|
|
m_backend = ValueObjectConstResult::Create (be->GetExecutionContextScope(),
|
|
be->GetClangAST(),
|
|
be->GetClangType(),
|
|
be->GetName(),
|
|
tgt_address,
|
|
eAddressTypeLoad,
|
|
be->GetUpdatePoint().GetProcessSP()->GetAddressByteSize());
|
|
}
|
|
|
|
m_interpreter = m_backend->GetUpdatePoint().GetTargetSP()->GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
|
|
|
|
if (m_interpreter == NULL)
|
|
m_wrapper = NULL;
|
|
else
|
|
m_wrapper = (PyObject*)m_interpreter->CreateSyntheticScriptedProvider(m_python_class, m_backend);
|
|
}
|
|
|
|
std::string
|
|
SyntheticScriptProvider::GetDescription()
|
|
{
|
|
StreamString sstr;
|
|
sstr.Printf("%s%s%s Python class %s",
|
|
m_cascades ? "" : " (not cascading)",
|
|
m_skip_pointers ? " (skip pointers)" : "",
|
|
m_skip_references ? " (skip references)" : "",
|
|
m_python_class.c_str());
|
|
|
|
return sstr.GetString();
|
|
} |