summaryrefslogtreecommitdiffstats
path: root/lldb/source
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source')
-rw-r--r--lldb/source/Commands/CommandObjectFrame.cpp203
-rw-r--r--lldb/source/Expression/DWARFExpression.cpp148
-rw-r--r--lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp7
-rw-r--r--lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.h3
-rw-r--r--lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp7
-rw-r--r--lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h5
-rw-r--r--lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp566
-rw-r--r--lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h1
-rw-r--r--lldb/source/Target/Process.cpp18
-rw-r--r--lldb/source/Target/StackFrame.cpp583
-rw-r--r--lldb/source/Target/StopInfo.cpp46
11 files changed, 1586 insertions, 1 deletions
diff --git a/lldb/source/Commands/CommandObjectFrame.cpp b/lldb/source/Commands/CommandObjectFrame.cpp
index 935fee80a6a..d508bf48634 100644
--- a/lldb/source/Commands/CommandObjectFrame.cpp
+++ b/lldb/source/Commands/CommandObjectFrame.cpp
@@ -43,12 +43,214 @@
#include "lldb/Symbol/VariableList.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/LLDBAssert.h"
using namespace lldb;
using namespace lldb_private;
+#pragma mark CommandObjectFrameDiagnose
+
+//-------------------------------------------------------------------------
+// CommandObjectFrameInfo
+//-------------------------------------------------------------------------
+
+//-------------------------------------------------------------------------
+// CommandObjectFrameDiagnose
+//-------------------------------------------------------------------------
+
+class CommandObjectFrameDiagnose : public CommandObjectParsed
+{
+public:
+ class CommandOptions : public Options
+ {
+ public:
+ CommandOptions() :
+ Options()
+ {
+ OptionParsingStarting(nullptr);
+ }
+
+ ~CommandOptions() override = default;
+
+ Error
+ SetOptionValue(uint32_t option_idx, const char *option_arg,
+ ExecutionContext *execution_context) override
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+ switch (short_option)
+ {
+ case 'r':
+ reg = ConstString(option_arg);
+ break;
+
+ case 'a':
+ {
+ bool success = false;
+
+ address = StringConvert::ToUInt64 (option_arg, 0, 0, &success);
+ if (!success)
+ {
+ address.reset();
+ error.SetErrorStringWithFormat ("invalid address argument '%s'", option_arg);
+ }
+ }
+ break;
+
+ case 'o':
+ {
+ bool success = false;
+
+ offset = StringConvert::ToSInt64 (option_arg, 0, 0, &success);
+ if (!success)
+ {
+ offset.reset();
+ error.SetErrorStringWithFormat ("invalid offset argument '%s'", option_arg);
+ }
+ }
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("invalid short option character '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting(ExecutionContext *execution_context) override
+ {
+ address.reset();
+ reg.reset();
+ offset.reset();
+ }
+
+ const OptionDefinition*
+ GetDefinitions () override
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+ static OptionDefinition g_option_table[];
+
+ // Options.
+ llvm::Optional<lldb::addr_t> address;
+ llvm::Optional<ConstString> reg;
+ llvm::Optional<int64_t> offset;
+ };
+
+ CommandObjectFrameDiagnose(CommandInterpreter &interpreter)
+ : CommandObjectParsed(interpreter, "frame diagnose",
+ "Try to determine what path path the current stop location used to get to a register or address",
+ nullptr, eCommandRequiresThread | eCommandTryTargetAPILock | eCommandProcessMustBeLaunched |
+ eCommandProcessMustBePaused),
+ m_options()
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData index_arg;
+
+ // Define the first (and only) variant of this arg.
+ index_arg.arg_type = eArgTypeFrameIndex;
+ index_arg.arg_repetition = eArgRepeatOptional;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (index_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ ~CommandObjectFrameDiagnose() override = default;
+
+ Options *
+ GetOptions () override
+ {
+ return &m_options;
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result) override
+ {
+ Thread *thread = m_exe_ctx.GetThreadPtr();
+ StackFrameSP frame_sp = thread->GetSelectedFrame();
+
+ ValueObjectSP valobj_sp;
+
+ if (m_options.address.hasValue())
+ {
+ if (m_options.reg.hasValue() || m_options.offset.hasValue())
+ {
+ result.AppendError("`frame diagnose --address` is incompatible with other arguments.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue());
+ }
+ else if (m_options.reg.hasValue())
+ {
+ valobj_sp = frame_sp->GuessValueForRegisterAndOffset(m_options.reg.getValue(), m_options.offset.getValueOr(0));
+ }
+ else
+ {
+ StopInfoSP stop_info_sp = thread->GetStopInfo();
+ if (!stop_info_sp)
+ {
+ result.AppendError("No arguments provided, and no stop info.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp);
+ }
+
+ if (!valobj_sp)
+ {
+ result.AppendError("No diagnosis available.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ const bool qualify_cxx_base_classes = false;
+
+ DumpValueObjectOptions::DeclPrintingHelper helper = [&valobj_sp](ConstString type,
+ ConstString var,
+ const DumpValueObjectOptions &opts,
+ Stream &stream) -> bool {
+ const ValueObject::GetExpressionPathFormat format = ValueObject::GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
+ valobj_sp->GetExpressionPath(stream, qualify_cxx_base_classes, format);
+ stream.PutCString(" =");
+ return true;
+ };
+
+ DumpValueObjectOptions options;
+ options.SetDeclPrintingHelper(helper);
+ ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(), options);
+ printer.PrintValueObject();
+
+ return true;
+ }
+
+protected:
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectFrameDiagnose::CommandOptions::g_option_table[] =
+{
+ // clang-format off
+ {LLDB_OPT_SET_1, false, "register", 'r', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeRegisterName, "A register to diagnose."},
+ {LLDB_OPT_SET_1, false, "address", 'a', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeAddress, "An address to diagnose."},
+ {LLDB_OPT_SET_1, false, "offset", 'o', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeOffset, "An optional offset. Requires --register."},
+ {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}
+ // clang-format on
+};
+
#pragma mark CommandObjectFrameInfo
//-------------------------------------------------------------------------
@@ -612,6 +814,7 @@ CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(CommandInterpreter &int
"Commands for selecting and examing the current thread's stack frames.",
"frame <subcommand> [<subcommand-options>]")
{
+ LoadSubCommand ("diagnose", CommandObjectSP (new CommandObjectFrameDiagnose (interpreter)));
LoadSubCommand ("info", CommandObjectSP (new CommandObjectFrameInfo (interpreter)));
LoadSubCommand ("select", CommandObjectSP (new CommandObjectFrameSelect (interpreter)));
LoadSubCommand ("variable", CommandObjectSP (new CommandObjectFrameVariable (interpreter)));
diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp
index b81d60e9b06..23a922c491b 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -30,6 +30,8 @@
#include "lldb/Host/Endian.h"
#include "lldb/Host/Host.h"
+#include "lldb/Symbol/Function.h"
+
#include "lldb/Target/ABI.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
@@ -3336,3 +3338,149 @@ DWARFExpression::PrintDWARFLocationList(Stream &s,
offset += loc_length;
}
}
+
+bool
+DWARFExpression::GetOpAndEndOffsets(StackFrame &frame, lldb::offset_t &op_offset, lldb::offset_t &end_offset)
+{
+ SymbolContext sc = frame.GetSymbolContext(eSymbolContextFunction);
+ if (!sc.function)
+ {
+ return false;
+ }
+
+ addr_t loclist_base_file_addr = sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
+ if (loclist_base_file_addr == LLDB_INVALID_ADDRESS)
+ {
+ return false;
+ }
+
+ addr_t pc_file_addr = frame.GetFrameCodeAddress().GetFileAddress();
+ lldb::offset_t opcodes_offset, opcodes_length;
+ if (!GetLocation(loclist_base_file_addr, pc_file_addr, opcodes_offset, opcodes_length))
+ {
+ return false;
+ }
+
+ if (opcodes_length == 0)
+ {
+ return false;
+ }
+
+ op_offset = opcodes_offset;
+ end_offset = opcodes_offset + opcodes_length;
+ return true;
+}
+
+bool
+DWARFExpression::IsRegister(StackFrame &frame,
+ const RegisterInfo *&register_info)
+{
+ lldb::offset_t op_offset;
+ lldb::offset_t end_offset;
+ if (!GetOpAndEndOffsets(frame, op_offset, end_offset))
+ {
+ return false;
+ }
+
+ if (!m_data.ValidOffset(op_offset) || op_offset >= end_offset)
+ {
+ return false;
+ }
+
+ RegisterContextSP reg_ctx_sp = frame.GetRegisterContext();
+ if (!reg_ctx_sp)
+ {
+ return false;
+ }
+
+ DataExtractor opcodes = m_data;
+ uint8_t opcode = opcodes.GetU8(&op_offset);
+
+ if (opcode >= DW_OP_reg0 && opcode <= DW_OP_breg31)
+ {
+ register_info = reg_ctx_sp->GetRegisterInfo(m_reg_kind, opcode - DW_OP_reg0);
+ return register_info != nullptr;
+ }
+ switch (opcode)
+ {
+ default:
+ return false;
+ case DW_OP_regx:
+ {
+ uint32_t reg_num = m_data.GetULEB128(&op_offset);
+ register_info = reg_ctx_sp->GetRegisterInfo(m_reg_kind, reg_num);
+ return register_info != nullptr;
+ }
+ }
+}
+
+bool
+DWARFExpression::IsDereferenceOfRegister(StackFrame &frame,
+ const RegisterInfo *&register_info,
+ int64_t &offset)
+{
+ lldb::offset_t op_offset;
+ lldb::offset_t end_offset;
+ if (!GetOpAndEndOffsets(frame, op_offset, end_offset))
+ {
+ return false;
+ }
+
+ if (!m_data.ValidOffset(op_offset) || op_offset >= end_offset)
+ {
+ return false;
+ }
+
+ RegisterContextSP reg_ctx_sp = frame.GetRegisterContext();
+ if (!reg_ctx_sp)
+ {
+ return false;
+ }
+
+ DataExtractor opcodes = m_data;
+ uint8_t opcode = opcodes.GetU8(&op_offset);
+
+ switch (opcode)
+ {
+ default:
+ return false;
+ case DW_OP_bregx:
+ {
+ uint32_t reg_num = static_cast<uint32_t>(opcodes.GetULEB128(&op_offset));
+ int64_t breg_offset = opcodes.GetSLEB128(&op_offset);
+
+ const RegisterInfo *reg_info = reg_ctx_sp->GetRegisterInfo(m_reg_kind, reg_num);
+ if (!reg_info)
+ {
+ return false;
+ }
+
+ register_info = reg_info;
+ offset = breg_offset;
+ return true;
+ }
+ case DW_OP_fbreg:
+ {
+ int64_t fbreg_offset = opcodes.GetSLEB128(&op_offset);
+
+ DWARFExpression *dwarf_expression = frame.GetFrameBaseExpression(nullptr);
+
+ if (!dwarf_expression)
+ {
+ return false;
+ }
+
+ const RegisterInfo *fbr_info;
+
+ if (!dwarf_expression->IsRegister(frame, fbr_info))
+ {
+ return false;
+ }
+
+ register_info = fbr_info;
+ offset = fbreg_offset;
+ return true;
+ }
+ }
+}
+
diff --git a/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp b/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp
index ac5151afdee..32dc28e2c7d 100644
--- a/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp
+++ b/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp
@@ -204,6 +204,13 @@ ABISysV_arm64::GetRegisterInfoArray (uint32_t &count)
return g_register_infos;
}
+bool
+ABISysV_arm64::GetPointerReturnRegister (const char *&name)
+{
+ name = "x0";
+ return true;
+}
+
size_t
ABISysV_arm64::GetRedZoneSize () const
{
diff --git a/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.h b/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.h
index e36f87e744f..548d42a8780 100644
--- a/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.h
+++ b/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.h
@@ -81,6 +81,9 @@ public:
const lldb_private::RegisterInfo *
GetRegisterInfoArray (uint32_t &count) override;
+
+ bool
+ GetPointerReturnRegister (const char *&name) override;
//------------------------------------------------------------------
// Static Functions
diff --git a/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp b/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
index cc568d6f635..89b39a1a752 100644
--- a/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
+++ b/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
@@ -211,6 +211,13 @@ ABISysV_x86_64::GetRegisterInfoArray (uint32_t &count)
return g_register_infos;
}
+bool
+ABISysV_x86_64::GetPointerReturnRegister (const char *&name)
+{
+ name = "rax";
+ return true;
+}
+
size_t
ABISysV_x86_64::GetRedZoneSize () const
{
diff --git a/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h b/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
index 07b57abaf57..2adf22d109c 100644
--- a/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
+++ b/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
@@ -84,7 +84,10 @@ public:
const lldb_private::RegisterInfo *
GetRegisterInfoArray(uint32_t &count) override;
-
+
+ bool
+ GetPointerReturnRegister (const char *&name) override;
+
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------
diff --git a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
index 4d24cf1ab6d..61a57ef3fcd 100644
--- a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
+++ b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
@@ -31,6 +31,7 @@
#include "lldb/Core/Address.h"
#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Stream.h"
#include "lldb/Symbol/SymbolContext.h"
@@ -56,6 +57,7 @@ public:
m_disasm_wp (std::static_pointer_cast<DisassemblerLLVMC>(disasm.shared_from_this())),
m_does_branch (eLazyBoolCalculate),
m_has_delay_slot (eLazyBoolCalculate),
+ m_is_call (eLazyBoolCalculate),
m_is_valid (false),
m_using_file_addr (false)
{
@@ -467,11 +469,569 @@ public:
{
return m_disasm_wp.lock();
}
+
+ static llvm::StringRef::const_iterator
+ ConsumeWhitespace(llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
+ {
+ while (osi != ose)
+ {
+ switch (*osi) {
+ default:
+ return osi;
+ case ' ': case '\t':
+ break;
+ }
+ ++osi;
+ }
+
+ return osi;
+ }
+
+ static std::pair<bool, llvm::StringRef::const_iterator>
+ ConsumeChar(llvm::StringRef::const_iterator osi, const char c, llvm::StringRef::const_iterator ose)
+ {
+ bool found = false;
+
+ osi = ConsumeWhitespace(osi, ose);
+ if (osi != ose && *osi == c)
+ {
+ found = true;
+ ++osi;
+ }
+
+ return std::make_pair(found, osi);
+ }
+
+ static std::pair<Operand, llvm::StringRef::const_iterator>
+ ParseRegisterName(llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
+ {
+ Operand ret;
+ ret.m_type = Operand::Type::Register;
+ std::string str;
+
+ osi = ConsumeWhitespace(osi, ose);
+
+ while (osi != ose)
+ {
+ if (*osi >= '0' && *osi <= '9')
+ {
+ if (str.empty())
+ {
+ return std::make_pair(Operand(), osi);
+ }
+ else
+ {
+ str.push_back(*osi);
+ }
+ }
+ else if (*osi >= 'a' && *osi <= 'z')
+ {
+ str.push_back(*osi);
+ }
+ else
+ {
+ switch (*osi)
+ {
+ default:
+ if (str.empty())
+ {
+ return std::make_pair(Operand(), osi);
+ }
+ else
+ {
+ ret.m_register = ConstString(str);
+ return std::make_pair(ret, osi);
+ }
+ case '%':
+ if (!str.empty())
+ {
+ return std::make_pair(Operand(), osi);
+ }
+ break;
+ }
+ }
+ ++osi;
+ }
+
+ ret.m_register = ConstString(str);
+ return std::make_pair(ret, osi);
+ }
+
+ static std::pair<Operand, llvm::StringRef::const_iterator>
+ ParseImmediate(llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
+ {
+ Operand ret;
+ ret.m_type = Operand::Type::Immediate;
+ std::string str;
+ bool is_hex = false;
+
+ osi = ConsumeWhitespace(osi, ose);
+
+ while (osi != ose)
+ {
+ if (*osi >= '0' && *osi <= '9')
+ {
+ str.push_back(*osi);
+ }
+ else if (*osi >= 'a' && *osi <= 'f')
+ {
+ if (is_hex)
+ {
+ str.push_back(*osi);
+ }
+ else
+ {
+ return std::make_pair(Operand(), osi);
+ }
+ }
+ else
+ {
+ switch (*osi)
+ {
+ default:
+ if (str.empty())
+ {
+ return std::make_pair(Operand(), osi);
+ }
+ else
+ {
+ ret.m_immediate = std::stoull(str, nullptr, 0);
+ return std::make_pair(ret, osi);
+ }
+ case 'x':
+ if (!str.compare("0"))
+ {
+ is_hex = true;
+ str.push_back(*osi);
+ }
+ else
+ {
+ return std::make_pair(Operand(), osi);
+ }
+ break;
+ case '#': case '$':
+ if (!str.empty())
+ {
+ return std::make_pair(Operand(), osi);
+ }
+ break;
+ case '-':
+ if (str.empty())
+ {
+ ret.m_negative = true;
+ }
+ else
+ {
+ return std::make_pair(Operand(), osi);
+ }
+ }
+ }
+ ++osi;
+ }
+
+ ret.m_immediate = std::stoull(str, nullptr, 0);
+ return std::make_pair(ret, osi);
+ }
+
+ // -0x5(%rax,%rax,2)
+ static std::pair<Operand, llvm::StringRef::const_iterator>
+ ParseIntelIndexedAccess (llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
+ {
+ std::pair<Operand, llvm::StringRef::const_iterator> offset_and_iterator = ParseImmediate(osi, ose);
+ if (offset_and_iterator.first.IsValid())
+ {
+ osi = offset_and_iterator.second;
+ }
+
+ bool found = false;
+ std::tie(found, osi) = ConsumeChar(osi, '(', ose);
+ if (!found)
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ std::pair<Operand, llvm::StringRef::const_iterator> base_and_iterator = ParseRegisterName(osi, ose);
+ if (base_and_iterator.first.IsValid())
+ {
+ osi = base_and_iterator.second;
+ }
+ else
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ std::tie(found, osi) = ConsumeChar(osi, ',', ose);
+ if (!found)
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ std::pair<Operand, llvm::StringRef::const_iterator> index_and_iterator = ParseRegisterName(osi, ose);
+ if (index_and_iterator.first.IsValid())
+ {
+ osi = index_and_iterator.second;
+ }
+ else
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ std::tie(found, osi) = ConsumeChar(osi, ',', ose);
+ if (!found)
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ std::pair<Operand, llvm::StringRef::const_iterator> multiplier_and_iterator = ParseImmediate(osi, ose);
+ if (index_and_iterator.first.IsValid())
+ {
+ osi = index_and_iterator.second;
+ }
+ else
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ std::tie(found, osi) = ConsumeChar(osi, ')', ose);
+ if (!found)
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ Operand product;
+ product.m_type = Operand::Type::Product;
+ product.m_children.push_back(index_and_iterator.first);
+ product.m_children.push_back(multiplier_and_iterator.first);
+
+ Operand index;
+ index.m_type = Operand::Type::Sum;
+ index.m_children.push_back(base_and_iterator.first);
+ index.m_children.push_back(product);
+
+ if (offset_and_iterator.first.IsValid())
+ {
+ Operand offset;
+ offset.m_type = Operand::Type::Sum;
+ offset.m_children.push_back(offset_and_iterator.first);
+ offset.m_children.push_back(index);
+
+ Operand deref;
+ deref.m_type = Operand::Type::Dereference;
+ deref.m_children.push_back(offset);
+ return std::make_pair(deref, osi);
+ }
+ else
+ {
+ Operand deref;
+ deref.m_type = Operand::Type::Dereference;
+ deref.m_children.push_back(index);
+ return std::make_pair(deref, osi);
+ }
+ }
+
+ // -0x10(%rbp)
+ static std::pair<Operand, llvm::StringRef::const_iterator>
+ ParseIntelDerefAccess (llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
+ {
+ std::pair<Operand, llvm::StringRef::const_iterator> offset_and_iterator = ParseImmediate(osi, ose);
+ if (offset_and_iterator.first.IsValid())
+ {
+ osi = offset_and_iterator.second;
+ }
+
+ bool found = false;
+ std::tie(found, osi) = ConsumeChar(osi, '(', ose);
+ if (!found)
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ std::pair<Operand, llvm::StringRef::const_iterator> base_and_iterator = ParseRegisterName(osi, ose);
+ if (base_and_iterator.first.IsValid())
+ {
+ osi = base_and_iterator.second;
+ }
+ else
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ std::tie(found, osi) = ConsumeChar(osi, ')', ose);
+ if (!found)
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ if (offset_and_iterator.first.IsValid())
+ {
+ Operand offset;
+ offset.m_type = Operand::Type::Sum;
+ offset.m_children.push_back(offset_and_iterator.first);
+ offset.m_children.push_back(base_and_iterator.first);
+
+ Operand deref;
+ deref.m_type = Operand::Type::Dereference;
+ deref.m_children.push_back(offset);
+ return std::make_pair(deref, osi);
+ }
+ else
+ {
+ Operand deref;
+ deref.m_type = Operand::Type::Dereference;
+ deref.m_children.push_back(base_and_iterator.first);
+ return std::make_pair(deref, osi);
+ }
+ }
+
+ // [sp, #8]!
+ static std::pair<Operand, llvm::StringRef::const_iterator>
+ ParseARMOffsetAccess (llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
+ {
+ bool found = false;
+ std::tie(found, osi) = ConsumeChar(osi, '[', ose);
+ if (!found)
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ std::pair<Operand, llvm::StringRef::const_iterator> base_and_iterator = ParseRegisterName(osi, ose);
+ if (base_and_iterator.first.IsValid())
+ {
+ osi = base_and_iterator.second;
+ }
+ else
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ std::tie(found, osi) = ConsumeChar(osi, ',', ose);
+ if (!found)
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ std::pair<Operand, llvm::StringRef::const_iterator> offset_and_iterator = ParseImmediate(osi, ose);
+ if (offset_and_iterator.first.IsValid())
+ {
+ osi = offset_and_iterator.second;
+ }
+
+ std::tie(found, osi) = ConsumeChar(osi, ']', ose);
+ if (!found)
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ Operand offset;
+ offset.m_type = Operand::Type::Sum;
+ offset.m_children.push_back(offset_and_iterator.first);
+ offset.m_children.push_back(base_and_iterator.first);
+
+ Operand deref;
+ deref.m_type = Operand::Type::Dereference;
+ deref.m_children.push_back(offset);
+ return std::make_pair(deref, osi);
+ }
+
+ // [sp]
+ static std::pair<Operand, llvm::StringRef::const_iterator>
+ ParseARMDerefAccess (llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
+ {
+ bool found = false;
+ std::tie(found, osi) = ConsumeChar(osi, '[', ose);
+ if (!found)
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ std::pair<Operand, llvm::StringRef::const_iterator> base_and_iterator = ParseRegisterName(osi, ose);
+ if (base_and_iterator.first.IsValid())
+ {
+ osi = base_and_iterator.second;
+ }
+ else
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ std::tie(found, osi) = ConsumeChar(osi, ']', ose);
+ if (!found)
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ Operand deref;
+ deref.m_type = Operand::Type::Dereference;
+ deref.m_children.push_back(base_and_iterator.first);
+ return std::make_pair(deref, osi);
+ }
+
+ static void
+ DumpOperand(const Operand &op, Stream &s)
+ {
+ switch (op.m_type)
+ {
+ case Operand::Type::Dereference:
+ s.PutCString("*");
+ DumpOperand(op.m_children[0], s);
+ break;
+ case Operand::Type::Immediate:
+ if (op.m_negative)
+ {
+ s.PutCString("-");
+ }
+ s.PutCString(std::to_string(op.m_immediate).c_str());
+ break;
+ case Operand::Type::Invalid:
+ s.PutCString("Invalid");
+ break;
+ case Operand::Type::Product:
+ s.PutCString("(");
+ DumpOperand(op.m_children[0], s);
+ s.PutCString("*");
+ DumpOperand(op.m_children[1], s);
+ s.PutCString(")");
+ break;
+ case Operand::Type::Register:
+ s.PutCString(op.m_register.AsCString());
+ break;
+ case Operand::Type::Sum:
+ s.PutCString("(");
+ DumpOperand(op.m_children[0], s);
+ s.PutCString("+");
+ DumpOperand(op.m_children[1], s);
+ s.PutCString(")");
+ break;
+ }
+ }
+
+ bool
+ ParseOperands (llvm::SmallVectorImpl<Instruction::Operand> &operands) override
+ {
+ const char *operands_string = GetOperands(nullptr);
+
+ if (!operands_string)
+ {
+ return false;
+ }
+
+ llvm::StringRef operands_ref(operands_string);
+
+ llvm::StringRef::const_iterator osi = operands_ref.begin();
+ llvm::StringRef::const_iterator ose = operands_ref.end();
+
+ while (osi != ose)
+ {
+ Operand operand;
+ llvm::StringRef::const_iterator iter;
+
+ if ((std::tie(operand, iter) = ParseIntelIndexedAccess(osi, ose), operand.IsValid()) ||
+ (std::tie(operand, iter) = ParseIntelDerefAccess(osi, ose), operand.IsValid()) ||
+ (std::tie(operand, iter) = ParseARMOffsetAccess(osi, ose), operand.IsValid()) ||
+ (std::tie(operand, iter) = ParseARMDerefAccess(osi, ose), operand.IsValid()) ||
+ (std::tie(operand, iter) = ParseRegisterName(osi, ose), operand.IsValid()) ||
+ (std::tie(operand, iter) = ParseImmediate(osi, ose), operand.IsValid()))
+ {
+ osi = iter;
+ operands.push_back(operand);
+ }
+ else
+ {
+ return false;
+ }
+
+ std::pair<bool, llvm::StringRef::const_iterator> found_and_iter = ConsumeChar(osi, ',', ose);
+ if (found_and_iter.first)
+ {
+ osi = found_and_iter.second;
+ }
+
+ osi = ConsumeWhitespace(osi, ose);
+ }
+
+ DisassemblerSP disasm_sp = m_disasm_wp.lock();
+
+ if (disasm_sp && operands.size() > 1)
+ {
+ // TODO tie this into the MC Disassembler's notion of clobbers.
+ switch (disasm_sp->GetArchitecture().GetMachine())
+ {
+ default:
+ break;
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ operands[operands.size() - 1].m_clobbered = true;
+ break;
+ case llvm::Triple::arm:
+ operands[0].m_clobbered = true;
+ break;
+ }
+ }
+
+ if (Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS))
+ {
+ StreamString ss;
+
+ ss.Printf("[%s] expands to %zu operands:\n", operands_string, operands.size());
+ for (const Operand &operand : operands) {
+ ss.PutCString(" ");
+ DumpOperand(operand, ss);
+ ss.PutCString("\n");
+ }
+
+ log->PutCString(ss.GetData());
+ }
+
+ return true;
+ }
+
+ bool
+ IsCall () override
+ {
+ if (m_is_call == eLazyBoolCalculate)
+ {
+ std::shared_ptr<DisassemblerLLVMC> disasm_sp(GetDisassembler());
+ if (disasm_sp)
+ {
+ disasm_sp->Lock(this, NULL);
+ DataExtractor data;
+ if (m_opcode.GetData(data))
+ {
+ bool is_alternate_isa;
+ lldb::addr_t pc = m_address.GetFileAddress();
+
+ DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr = GetDisasmToUse (is_alternate_isa);
+ const uint8_t *opcode_data = data.GetDataStart();
+ const size_t opcode_data_len = data.GetByteSize();
+ llvm::MCInst inst;
+ const size_t inst_size = mc_disasm_ptr->GetMCInst (opcode_data,
+ opcode_data_len,
+ pc,
+ inst);
+ if (inst_size == 0)
+ {
+ m_is_call = eLazyBoolNo;
+ }
+ else
+ {
+ if (mc_disasm_ptr->IsCall(inst))
+ m_is_call = eLazyBoolYes;
+ else
+ m_is_call = eLazyBoolNo;
+ }
+ }
+ disasm_sp->Unlock();
+ }
+ }
+ return m_is_call == eLazyBoolYes;
+ }
+
protected:
std::weak_ptr<DisassemblerLLVMC> m_disasm_wp;
LazyBool m_does_branch;
LazyBool m_has_delay_slot;
+ LazyBool m_is_call;
bool m_is_valid;
bool m_using_file_addr;
};
@@ -611,6 +1171,12 @@ DisassemblerLLVMC::LLVMCDisassembler::HasDelaySlot (llvm::MCInst &mc_inst)
return m_instr_info_ap->get(mc_inst.getOpcode()).hasDelaySlot();
}
+bool
+DisassemblerLLVMC::LLVMCDisassembler::IsCall (llvm::MCInst &mc_inst)
+{
+ return m_instr_info_ap->get(mc_inst.getOpcode()).isCall();
+}
+
DisassemblerLLVMC::DisassemblerLLVMC (const ArchSpec &arch, const char *flavor_string) :
Disassembler(arch, flavor_string),
m_exe_ctx (NULL),
diff --git a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h
index e8f09a4d3ab..f2f54d39399 100644
--- a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h
+++ b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h
@@ -55,6 +55,7 @@ class DisassemblerLLVMC : public lldb_private::Disassembler
void SetStyle (bool use_hex_immed, HexImmediateStyle hex_style);
bool CanBranch (llvm::MCInst &mc_inst);
bool HasDelaySlot (llvm::MCInst &mc_inst);
+ bool IsCall (llvm::MCInst &mc_inst);
bool IsValid()
{
return m_is_valid;
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index f5f8660a122..b40502995b6 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -1150,6 +1150,7 @@ Process::HandleProcessStateChangedEvent (const EventSP &event_sp,
}
else
{
+ StopInfoSP curr_thread_stop_info_sp;
// Lock the thread list so it doesn't change on us, this is the scope for the locker:
{
ThreadList &thread_list = process_sp->GetThreadList();
@@ -1159,7 +1160,10 @@ Process::HandleProcessStateChangedEvent (const EventSP &event_sp,
ThreadSP thread;
StopReason curr_thread_stop_reason = eStopReasonInvalid;
if (curr_thread)
+ {
curr_thread_stop_reason = curr_thread->GetStopReason();
+ curr_thread_stop_info_sp = curr_thread->GetStopInfo();
+ }
if (!curr_thread ||
!curr_thread->IsValid() ||
curr_thread_stop_reason == eStopReasonInvalid ||
@@ -1244,6 +1248,20 @@ Process::HandleProcessStateChangedEvent (const EventSP &event_sp,
start_frame,
num_frames,
num_frames_with_source);
+ if (curr_thread_stop_info_sp)
+ {
+ lldb::addr_t crashing_address;
+ ValueObjectSP valobj_sp = StopInfo::GetCrashingDereference(curr_thread_stop_info_sp, &crashing_address);
+ if (valobj_sp)
+ {
+ const bool qualify_cxx_base_classes = false;
+
+ const ValueObject::GetExpressionPathFormat format = ValueObject::GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
+ stream->PutCString("Likely cause: ");
+ valobj_sp->GetExpressionPath(*stream, qualify_cxx_base_classes, format);
+ stream->Printf(" accessed 0x%llx\n", crashing_address);
+ }
+ }
}
else
{
diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp
index 7110051d28e..aaf0a4d7ac7 100644
--- a/lldb/source/Target/StackFrame.cpp
+++ b/lldb/source/Target/StackFrame.cpp
@@ -20,12 +20,14 @@
#include "lldb/Core/Value.h"
#include "lldb/Core/ValueObjectVariable.h"
#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Core/ValueObjectMemory.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContextScope.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/ABI.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
@@ -1236,6 +1238,21 @@ StackFrame::GetFrameBaseValue (Scalar &frame_base, Error *error_ptr)
return m_frame_base_error.Success();
}
+DWARFExpression *
+StackFrame::GetFrameBaseExpression(Error *error_ptr)
+{
+ if (!m_sc.function)
+ {
+ if (error_ptr)
+ {
+ error_ptr->SetErrorString ("No function in symbol context.");
+ }
+ return nullptr;
+ }
+
+ return &m_sc.function->GetFrameBaseExpression();
+}
+
RegisterContextSP
StackFrame::GetRegisterContext ()
{
@@ -1354,6 +1371,572 @@ StackFrame::GuessLanguage ()
return lang_type;
}
+namespace
+{
+ std::pair<const Instruction::Operand *, int64_t>
+ GetBaseExplainingValue(const Instruction::Operand &operand,
+ RegisterContext &register_context,
+ lldb::addr_t value)
+ {
+ switch(operand.m_type)
+ {
+ case Instruction::Operand::Type::Dereference:
+ case Instruction::Operand::Type::Immediate:
+ case Instruction::Operand::Type::Invalid:
+ case Instruction::Operand::Type::Product:
+ // These are not currently interesting
+ return std::make_pair(nullptr, 0);
+ case Instruction::Operand::Type::Sum:
+ {
+ const Instruction::Operand *immediate_child = nullptr;
+ const Instruction::Operand *variable_child = nullptr;
+ if (operand.m_children[0].m_type == Instruction::Operand::Type::Immediate)
+ {
+ immediate_child = &operand.m_children[0];
+ variable_child = &operand.m_children[1];
+ }
+ else if (operand.m_children[1].m_type == Instruction::Operand::Type::Immediate)
+ {
+ immediate_child = &operand.m_children[1];
+ variable_child = &operand.m_children[0];
+ }
+ if (!immediate_child)
+ {
+ return std::make_pair(nullptr, 0);
+ }
+ lldb::addr_t adjusted_value = value;
+ if (immediate_child->m_negative)
+ {
+ adjusted_value += immediate_child->m_immediate;
+ }
+ else
+ {
+ adjusted_value -= immediate_child->m_immediate;
+ }
+ std::pair<const Instruction::Operand *, int64_t> base_and_offset = GetBaseExplainingValue(*variable_child, register_context, adjusted_value);
+ if (!base_and_offset.first)
+ {
+ return std::make_pair(nullptr, 0);
+ }
+ if (immediate_child->m_negative)
+ {
+ base_and_offset.second -= immediate_child->m_immediate;
+ }
+ else
+ {
+ base_and_offset.second += immediate_child->m_immediate;
+ }
+ return base_and_offset;
+ }
+ case Instruction::Operand::Type::Register:
+ {
+ const RegisterInfo *info = register_context.GetRegisterInfoByName(operand.m_register.AsCString());
+ if (!info)
+ {
+ return std::make_pair(nullptr, 0);
+ }
+ RegisterValue reg_value;
+ if (!register_context.ReadRegister(info, reg_value))
+ {
+ return std::make_pair(nullptr, 0);
+ }
+ if (reg_value.GetAsUInt64() == value)
+ {
+ return std::make_pair(&operand, 0);
+ }
+ else
+ {
+ return std::make_pair(nullptr, 0);
+ }
+ }
+ }
+ }
+
+ std::pair<const Instruction::Operand *, int64_t>
+ GetBaseExplainingDereference(const Instruction::Operand &operand,
+ RegisterContext &register_context,
+ lldb::addr_t addr)
+ {
+ if (operand.m_type == Instruction::Operand::Type::Dereference)
+ {
+ return GetBaseExplainingValue(operand.m_children[0],
+ register_context,
+ addr);
+ }
+ return std::make_pair(nullptr, 0);
+ }
+};
+
+lldb::ValueObjectSP
+StackFrame::GuessValueForAddress(lldb::addr_t addr)
+{
+ TargetSP target_sp = CalculateTarget();
+
+ const ArchSpec &target_arch = target_sp->GetArchitecture();
+
+ AddressRange pc_range;
+ pc_range.GetBaseAddress() = GetFrameCodeAddress();
+ pc_range.SetByteSize(target_arch.GetMaximumOpcodeByteSize());
+
+ ExecutionContext exe_ctx (shared_from_this());
+
+ const char *plugin_name = nullptr;
+ const char *flavor = nullptr;
+ const bool prefer_file_cache = false;
+
+ DisassemblerSP disassembler_sp = Disassembler::DisassembleRange (target_arch,
+ plugin_name,
+ flavor,
+ exe_ctx,
+ pc_range,
+ prefer_file_cache);
+
+ if (!disassembler_sp->GetInstructionList().GetSize())
+ {
+ return ValueObjectSP();
+ }
+
+ InstructionSP instruction_sp = disassembler_sp->GetInstructionList().GetInstructionAtIndex(0);
+
+ llvm::SmallVector<Instruction::Operand, 3> operands;
+
+ if (!instruction_sp->ParseOperands(operands))
+ {
+ return ValueObjectSP();
+ }
+
+ RegisterContextSP register_context_sp = GetRegisterContext();
+
+ if (!register_context_sp)
+ {
+ return ValueObjectSP();
+ }
+
+ for (const Instruction::Operand &operand : operands)
+ {
+ std::pair<const Instruction::Operand *, int64_t>
+ base_and_offset = GetBaseExplainingDereference(operand, *register_context_sp, addr);
+
+ if (!base_and_offset.first)
+ {
+ continue;
+ }
+
+ switch (base_and_offset.first->m_type)
+ {
+ case Instruction::Operand::Type::Immediate:
+ {
+ lldb_private::Address addr;
+ if (target_sp->ResolveLoadAddress(base_and_offset.first->m_immediate + base_and_offset.second, addr))
+ {
+ TypeSystem *c_type_system = target_sp->GetScratchTypeSystemForLanguage(nullptr, eLanguageTypeC);
+ if (!c_type_system)
+ {
+ return ValueObjectSP();
+ }
+ else
+ {
+ CompilerType void_ptr_type = c_type_system->GetBasicTypeFromAST(lldb::BasicType::eBasicTypeChar).GetPointerType();
+ return ValueObjectMemory::Create(this, "", addr, void_ptr_type);
+ }
+ }
+ else
+ {
+ return ValueObjectSP();
+ }
+ break;
+ }
+ case Instruction::Operand::Type::Register:
+ {
+ return GuessValueForRegisterAndOffset(base_and_offset.first->m_register, base_and_offset.second);
+ }
+ default:
+ return ValueObjectSP();
+ }
+
+ }
+
+ return ValueObjectSP();
+}
+
+namespace
+{
+ ValueObjectSP
+ GetValueForOffset(StackFrame &frame, ValueObjectSP &parent, int64_t offset)
+ {
+ if (offset < 0 || offset >= parent->GetByteSize())
+ {
+ return ValueObjectSP();
+ }
+
+ if (parent->IsPointerOrReferenceType())
+ {
+ return parent;
+ }
+
+ for (int ci = 0, ce = parent->GetNumChildren(); ci != ce; ++ci)
+ {
+ const bool can_create = true;
+ ValueObjectSP child_sp = parent->GetChildAtIndex(ci, can_create);
+
+ if (!child_sp)
+ {
+ return ValueObjectSP();
+ }
+
+ int64_t child_offset = child_sp->GetByteOffset();
+ int64_t child_size = child_sp->GetByteSize();
+
+ if (offset >= child_offset &&
+ offset < (child_offset + child_size))
+ {
+ return GetValueForOffset(frame, child_sp, offset - child_offset);
+ }
+ }
+
+ if (offset == 0)
+ {
+ return parent;
+ }
+ else
+ {
+ return ValueObjectSP();
+ }
+ }
+
+ ValueObjectSP
+ GetValueForDereferincingOffset(StackFrame &frame, ValueObjectSP &base, int64_t offset)
+ {
+ // base is a pointer to something
+ // offset is the thing to add to the pointer
+ // We return the most sensible ValueObject for the result of *(base+offset)
+
+ if (!base->IsPointerOrReferenceType())
+ {
+ return ValueObjectSP();
+ }
+
+ Error error;
+ ValueObjectSP pointee = base->Dereference(error);
+
+ if (offset >= pointee->GetByteSize())
+ {
+ int64_t index = offset / pointee->GetByteSize();
+ offset = offset % pointee->GetByteSize();
+ const bool can_create = true;
+ pointee = base->GetSyntheticArrayMember(index, can_create);
+ }
+
+ if (!pointee || error.Fail())
+ {
+ return ValueObjectSP();
+ }
+
+ return GetValueForOffset(frame, pointee, offset);
+ }
+
+ //------------------------------------------------------------------
+ /// Attempt to reconstruct the ValueObject for the address contained in a
+ /// given register plus an offset.
+ ///
+ /// @params [in] frame
+ /// The current stack frame.
+ ///
+ /// @params [in] reg
+ /// The register.
+ ///
+ /// @params [in] offset
+ /// The offset from the register.
+ ///
+ /// @param [in] disassembler
+ /// A disassembler containing instructions valid up to the current PC.
+ ///
+ /// @param [in] variables
+ /// The variable list from the current frame,
+ ///
+ /// @param [in] pc
+ /// The program counter for the instruction considered the 'user'.
+ ///
+ /// @return
+ /// A string describing the base for the ExpressionPath. This could be a
+ /// variable, a register value, an argument, or a function return value.
+ /// The ValueObject if found. If valid, it has a valid ExpressionPath.
+ //------------------------------------------------------------------
+ lldb::ValueObjectSP
+ DoGuessValueAt(StackFrame &frame, ConstString reg, int64_t offset, Disassembler &disassembler, VariableList &variables, const Address &pc)
+ {
+ // Example of operation for Intel:
+ //
+ // +14: movq -0x8(%rbp), %rdi
+ // +18: movq 0x8(%rdi), %rdi
+ // +22: addl 0x4(%rdi), %eax
+ //
+ // f, a pointer to a struct, is known to be at -0x8(%rbp).
+ //
+ // DoGuessValueAt(frame, rdi, 4, dis, vars, 0x22) finds the instruction at +18 that assigns to rdi, and calls itself recursively for that dereference
+ // DoGuessValueAt(frame, rdi, 8, dis, vars, 0x18) finds the instruction at +14 that assigns to rdi, and calls itself recursively for that derefernece
+ // DoGuessValueAt(frame, rbp, -8, dis, vars, 0x14) finds "f" in the variable list.
+ // Returns a ValueObject for f. (That's what was stored at rbp-8 at +14)
+ // Returns a ValueObject for *(f+8) or f->b (That's what was stored at rdi+8 at +18)
+ // Returns a ValueObject for *(f->b+4) or f->b->a (That's what was stored at rdi+4 at +22)
+
+ // First, check the variable list to see if anything is at the specified location.
+ for (size_t vi = 0, ve = variables.GetSize(); vi != ve; ++vi)
+ {
+ VariableSP var_sp = variables.GetVariableAtIndex(vi);
+ DWARFExpression &dwarf_expression = var_sp->LocationExpression();
+
+ const RegisterInfo *expression_reg;
+ int64_t expression_offset;
+ ExecutionContext exe_ctx;
+
+ if (dwarf_expression.IsDereferenceOfRegister(frame, expression_reg, expression_offset))
+ {
+ if ((reg == ConstString(expression_reg->name) ||
+ reg == ConstString(expression_reg->alt_name)) &&
+ expression_offset == offset)
+ {
+ return frame.GetValueObjectForFrameVariable(var_sp, eNoDynamicValues);
+ }
+ }
+ }
+
+ bool is_in_return_register = false;
+ ABISP abi_sp = frame.CalculateProcess()->GetABI();
+ RegisterInfo return_register_info;
+
+ if (abi_sp)
+ {
+ const char *return_register_name;
+ const RegisterInfo *reg_info = nullptr;
+ if (abi_sp->GetPointerReturnRegister(return_register_name) &&
+ reg == ConstString(return_register_name) &&
+ (reg_info = frame.GetRegisterContext()->GetRegisterInfoByName(return_register_name)))
+ {
+ is_in_return_register = true;
+ return_register_info = *reg_info;
+ }
+ }
+
+ const uint32_t current_inst = disassembler.GetInstructionList().GetIndexOfInstructionAtAddress(pc);
+ if (current_inst == UINT32_MAX)
+ {
+ return ValueObjectSP();
+ }
+
+ ValueObjectSP source_path;
+
+ for (uint32_t ii = current_inst - 1; ii != (uint32_t)-1; --ii)
+ {
+ // This is not an exact algorithm, and it sacrifices accuracy for generality.
+ // Recognizing "mov" and "ld" instructions –– and which are their source and
+ // destination operands -- is something the disassembler should do for us.
+ InstructionSP instruction_sp = disassembler.GetInstructionList().GetInstructionAtIndex(ii);
+
+ if (is_in_return_register && instruction_sp->IsCall())
+ {
+ llvm::SmallVector<Instruction::Operand, 1> operands;
+ if (!instruction_sp->ParseOperands(operands) || operands.size() != 1)
+ {
+ continue;
+ }
+
+ switch (operands[0].m_type)
+ {
+ default:
+ break;
+ case Instruction::Operand::Type::Immediate:
+ {
+ SymbolContext sc;
+ Address load_address;
+ if (!frame.CalculateTarget()->ResolveLoadAddress(operands[0].m_immediate, load_address))
+ {
+ break;
+ }
+ frame.CalculateTarget()->GetImages().ResolveSymbolContextForAddress(load_address, eSymbolContextFunction, sc);
+ if (!sc.function)
+ {
+ break;
+ }
+ CompilerType function_type = sc.function->GetCompilerType();
+ if (!function_type.IsFunctionType())
+ {
+ break;
+ }
+ CompilerType return_type = function_type.GetFunctionReturnType();
+ RegisterValue return_value;
+ if (!frame.GetRegisterContext()->ReadRegister(&return_register_info, return_value))
+ {
+ break;
+ }
+ std::string name_str(sc.function->GetName().AsCString("<unknown function>"));
+ name_str.append("()");
+ Address return_value_address(return_value.GetAsUInt64());
+ ValueObjectSP return_value_sp = ValueObjectMemory::Create(&frame, name_str.c_str(), return_value_address, return_type);
+ return GetValueForDereferincingOffset(frame, return_value_sp, offset);
+ }
+ }
+
+ continue;
+ }
+
+ llvm::SmallVector<Instruction::Operand, 2> operands;
+ if (!instruction_sp->ParseOperands(operands) || operands.size() != 2)
+ {
+ continue;
+ }
+
+ Instruction::Operand *register_operand = nullptr;
+ Instruction::Operand *origin_operand = nullptr;
+ if (operands[0].m_type == Instruction::Operand::Type::Register &&
+ operands[0].m_clobbered == true &&
+ operands[0].m_register == reg)
+ {
+ register_operand = &operands[0];
+ origin_operand = &operands[1];
+ }
+ else if (operands[1].m_type == Instruction::Operand::Type::Register &&
+ operands[1].m_clobbered == true &&
+ operands[1].m_register == reg)
+ {
+ register_operand = &operands[1];
+ origin_operand = &operands[0];
+ }
+ else
+ {
+ continue;
+ }
+
+ // We have an origin operand. Can we track its value down?
+ switch (origin_operand->m_type)
+ {
+ default:
+ break;
+ case Instruction::Operand::Type::Register:
+ source_path = DoGuessValueAt(frame, origin_operand->m_register, 0, disassembler, variables, instruction_sp->GetAddress());
+ break;
+ case Instruction::Operand::Type::Dereference:
+ {
+ const Instruction::Operand &pointer = origin_operand->m_children[0];
+ switch (pointer.m_type)
+ {
+ default:
+ break;
+ case Instruction::Operand::Type::Register:
+ source_path = DoGuessValueAt(frame, pointer.m_register, 0, disassembler, variables, instruction_sp->GetAddress());
+ if (source_path)
+ {
+ Error err;
+ source_path = source_path->Dereference(err);
+ if (!err.Success())
+ {
+ source_path.reset();
+ }
+ }
+ break;
+ case Instruction::Operand::Type::Sum:
+ {
+ const Instruction::Operand *origin_register = nullptr;
+ const Instruction::Operand *origin_offset = nullptr;
+ if (pointer.m_children.size() != 2)
+ {
+ break;
+ }
+ if (pointer.m_children[0].m_type == Instruction::Operand::Type::Register &&
+ pointer.m_children[1].m_type == Instruction::Operand::Type::Immediate)
+ {
+ origin_register = &pointer.m_children[0];
+ origin_offset = &pointer.m_children[1];
+ }
+ else if (pointer.m_children[1].m_type == Instruction::Operand::Type::Register &&
+ pointer.m_children[0].m_type == Instruction::Operand::Type::Immediate)
+ {
+ origin_register = &pointer.m_children[1];
+ origin_offset = &pointer.m_children[0];
+ }
+ if (!origin_register)
+ {
+ break;
+ }
+ int64_t signed_origin_offset = origin_offset->m_negative ? -((int64_t)origin_offset->m_immediate) : origin_offset->m_immediate;
+ source_path = DoGuessValueAt(frame, origin_register->m_register, signed_origin_offset, disassembler, variables, instruction_sp->GetAddress());
+ if (!source_path)
+ {
+ break;
+ }
+ source_path = GetValueForDereferincingOffset(frame, source_path, offset);
+ break;
+ }
+ }
+ }
+ }
+
+ if (source_path)
+ {
+ return source_path;
+ }
+ }
+
+ return ValueObjectSP();
+ }
+}
+
+lldb::ValueObjectSP
+StackFrame::GuessValueForRegisterAndOffset(ConstString reg, int64_t offset)
+{
+ TargetSP target_sp = CalculateTarget();
+
+ const ArchSpec &target_arch = target_sp->GetArchitecture();
+
+ Block *frame_block = GetFrameBlock();
+
+ if (!frame_block)
+ {
+ return ValueObjectSP();
+ }
+
+ Function *function = frame_block->CalculateSymbolContextFunction();
+ if (!function)
+ {
+ return ValueObjectSP();
+ }
+
+ AddressRange pc_range = function->GetAddressRange();
+
+ if (GetFrameCodeAddress().GetFileAddress() < pc_range.GetBaseAddress().GetFileAddress() ||
+ GetFrameCodeAddress().GetFileAddress() - pc_range.GetBaseAddress().GetFileAddress() >= pc_range.GetByteSize())
+ {
+ return ValueObjectSP();
+ }
+
+ ExecutionContext exe_ctx (shared_from_this());
+
+ const char *plugin_name = nullptr;
+ const char *flavor = nullptr;
+ const bool prefer_file_cache = false;
+ DisassemblerSP disassembler_sp = Disassembler::DisassembleRange (target_arch,
+ plugin_name,
+ flavor,
+ exe_ctx,
+ pc_range,
+ prefer_file_cache);
+
+ if (!disassembler_sp || !disassembler_sp->GetInstructionList().GetSize())
+ {
+ return ValueObjectSP();
+ }
+
+ const bool get_file_globals = false;
+ VariableList *variables = GetVariableList(get_file_globals);
+
+ if (!variables)
+ {
+ return ValueObjectSP();
+ }
+
+ return DoGuessValueAt(*this, reg, offset, *disassembler_sp, *variables, GetFrameCodeAddress());
+}
+
TargetSP
StackFrame::CalculateTarget ()
{
diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp
index 7c244363ffd..085c0f181c0 100644
--- a/lldb/source/Target/StopInfo.cpp
+++ b/lldb/source/Target/StopInfo.cpp
@@ -1219,3 +1219,49 @@ StopInfo::GetExpressionVariable(StopInfoSP &stop_info_sp)
else
return ExpressionVariableSP();
}
+
+lldb::ValueObjectSP
+StopInfo::GetCrashingDereference (StopInfoSP &stop_info_sp, lldb::addr_t *crashing_address)
+{
+ if (!stop_info_sp)
+ {
+ return ValueObjectSP();
+ }
+
+ const char *description = stop_info_sp->GetDescription();
+ if (!description)
+ {
+ return ValueObjectSP();
+ }
+
+ ThreadSP thread_sp = stop_info_sp->GetThread();
+ if (!thread_sp)
+ {
+ return ValueObjectSP();
+ }
+
+ StackFrameSP frame_sp = thread_sp->GetSelectedFrame();
+
+ if (!frame_sp)
+ {
+ return ValueObjectSP();
+ }
+
+ const char address_string[] = "address=";
+
+ const char *address_loc = strstr(description, address_string);
+ if (!address_loc)
+ {
+ return ValueObjectSP();
+ }
+
+ address_loc += (sizeof(address_string) - 1);
+
+ uint64_t address = std::stoull(address_loc, 0, 0);
+ if (crashing_address)
+ {
+ *crashing_address = address;
+ }
+
+ return frame_sp->GuessValueForAddress(address);
+}
OpenPOWER on IntegriCloud