diff options
Diffstat (limited to 'lldb/source/Expression/DWARFExpression.cpp')
| -rw-r--r-- | lldb/source/Expression/DWARFExpression.cpp | 264 |
1 files changed, 197 insertions, 67 deletions
diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp index ccd41fb4a94e..1f11907dc64c 100644 --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -16,6 +16,7 @@ #include "lldb/Core/Value.h" #include "lldb/Core/dwarf.h" #include "lldb/Utility/DataEncoder.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Scalar.h" @@ -35,11 +36,14 @@ #include "lldb/Target/StackID.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" +#include "llvm/DebugInfo/DWARF/DWARFExpression.h" #include "Plugins/SymbolFile/DWARF/DWARFUnit.h" using namespace lldb; using namespace lldb_private; +using namespace lldb_private::dwarf; static lldb::addr_t ReadAddressFromDebugAddrSection(const DWARFUnit *dwarf_cu, @@ -60,8 +64,7 @@ DWARFExpression::DWARFExpression() : m_module_wp(), m_data() {} DWARFExpression::DWARFExpression(lldb::ModuleSP module_sp, const DataExtractor &data, const DWARFUnit *dwarf_cu) - : m_module_wp(), m_data(data), m_dwarf_cu(dwarf_cu), - m_reg_kind(eRegisterKindDWARF) { + : m_module_wp(), m_data(data), m_dwarf_cu(dwarf_cu) { if (module_sp) m_module_wp = module_sp; } @@ -126,7 +129,6 @@ private: } void DWARFExpression::GetDescription(Stream *s, lldb::DescriptionLevel level, - addr_t location_list_base_addr, ABI *abi) const { if (IsLocationList()) { // We have a location list @@ -856,29 +858,28 @@ bool DWARFExpression::Evaluate(ExecutionContext *exe_ctx, ModuleSP module_sp = m_module_wp.lock(); if (IsLocationList()) { - addr_t pc; + Address pc; StackFrame *frame = nullptr; - if (reg_ctx) - pc = reg_ctx->GetPC(); - else { + if (!reg_ctx || !reg_ctx->GetPCForSymbolication(pc)) { frame = exe_ctx->GetFramePtr(); if (!frame) return false; RegisterContextSP reg_ctx_sp = frame->GetRegisterContext(); if (!reg_ctx_sp) return false; - pc = reg_ctx_sp->GetPC(); + reg_ctx_sp->GetPCForSymbolication(pc); } if (func_load_addr != LLDB_INVALID_ADDRESS) { - if (pc == LLDB_INVALID_ADDRESS) { + if (!pc.IsValid()) { if (error_ptr) error_ptr->SetErrorString("Invalid PC in frame."); return false; } - if (llvm::Optional<DataExtractor> expr = - GetLocationExpression(func_load_addr, pc)) { + Target *target = exe_ctx->GetTargetPtr(); + if (llvm::Optional<DataExtractor> expr = GetLocationExpression( + func_load_addr, pc.GetLoadAddress(target))) { return DWARFExpression::Evaluate( exe_ctx, reg_ctx, module_sp, *expr, m_dwarf_cu, m_reg_kind, initial_value_ptr, object_address_ptr, result, error_ptr); @@ -941,6 +942,72 @@ void UpdateValueTypeFromLocationDescription(Log *log, const DWARFUnit *dwarf_cu, } } // namespace +/// Helper function to move common code used to resolve a file address and turn +/// into a load address. +/// +/// \param exe_ctx Pointer to the execution context +/// \param module_sp shared_ptr contains the module if we have one +/// \param error_ptr pointer to Status object if we have one +/// \param dw_op_type C-style string used to vary the error output +/// \param file_addr the file address we are trying to resolve and turn into a +/// load address +/// \param so_addr out parameter, will be set to load addresss or section offset +/// \param check_sectionoffset bool which determines if having a section offset +/// but not a load address is considerd a success +/// \returns llvm::Optional containing the load address if resolving and getting +/// the load address succeed or an empty Optinal otherwise. If +/// check_sectionoffset is true we consider LLDB_INVALID_ADDRESS a +/// success if so_addr.IsSectionOffset() is true. +static llvm::Optional<lldb::addr_t> +ResolveLoadAddress(ExecutionContext *exe_ctx, lldb::ModuleSP &module_sp, + Status *error_ptr, const char *dw_op_type, + lldb::addr_t file_addr, Address &so_addr, + bool check_sectionoffset = false) { + if (!module_sp) { + if (error_ptr) + error_ptr->SetErrorStringWithFormat( + "need module to resolve file address for %s", dw_op_type); + return {}; + } + + if (!module_sp->ResolveFileAddress(file_addr, so_addr)) { + if (error_ptr) + error_ptr->SetErrorString("failed to resolve file address in module"); + return {}; + } + + addr_t load_addr = so_addr.GetLoadAddress(exe_ctx->GetTargetPtr()); + + if (load_addr == LLDB_INVALID_ADDRESS && + (check_sectionoffset && !so_addr.IsSectionOffset())) { + if (error_ptr) + error_ptr->SetErrorString("failed to resolve load address"); + return {}; + } + + return load_addr; +} + +/// Helper function to move common code used to load sized data from a uint8_t +/// buffer. +/// +/// \param addr_bytes uint8_t buffer containg raw data +/// \param size_addr_bytes how large is the underlying raw data +/// \param byte_order what is the byter order of the underlyig data +/// \param size How much of the underlying data we want to use +/// \return The underlying data converted into a Scalar +static Scalar DerefSizeExtractDataHelper(uint8_t *addr_bytes, + size_t size_addr_bytes, + ByteOrder byte_order, size_t size) { + DataExtractor addr_data(addr_bytes, size_addr_bytes, byte_order, size); + + lldb::offset_t addr_data_offset = 0; + if (size <= 8) + return addr_data.GetMaxU64(&addr_data_offset, size); + else + return addr_data.GetAddress(&addr_data_offset); +} + bool DWARFExpression::Evaluate( ExecutionContext *exe_ctx, RegisterContext *reg_ctx, lldb::ModuleSP module_sp, const DataExtractor &opcodes, @@ -977,7 +1044,7 @@ bool DWARFExpression::Evaluate( uint64_t op_piece_offset = 0; Value pieces; // Used for DW_OP_piece - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + Log *log = GetLog(LLDBLog::Expressions); // A generic type is "an integral type that has the size of an address and an // unspecified signedness". For now, just use the signedness of the operand. // TODO: Implement a real typed stack, and store the genericness of the value @@ -1086,26 +1153,15 @@ bool DWARFExpression::Evaluate( case Value::ValueType::FileAddress: { auto file_addr = stack.back().GetScalar().ULongLong( LLDB_INVALID_ADDRESS); - if (!module_sp) { - if (error_ptr) - error_ptr->SetErrorString( - "need module to resolve file address for DW_OP_deref"); - return false; - } + Address so_addr; - if (!module_sp->ResolveFileAddress(file_addr, so_addr)) { - if (error_ptr) - error_ptr->SetErrorString( - "failed to resolve file address in module"); - return false; - } - addr_t load_Addr = so_addr.GetLoadAddress(exe_ctx->GetTargetPtr()); - if (load_Addr == LLDB_INVALID_ADDRESS) { - if (error_ptr) - error_ptr->SetErrorString("failed to resolve load address"); + auto maybe_load_addr = ResolveLoadAddress( + exe_ctx, module_sp, error_ptr, "DW_OP_deref", file_addr, so_addr); + + if (!maybe_load_addr) return false; - } - stack.back().GetScalar() = load_Addr; + + stack.back().GetScalar() = *maybe_load_addr; // Fall through to load address promotion code below. } LLVM_FALLTHROUGH; case Value::ValueType::Scalar: @@ -1216,6 +1272,47 @@ bool DWARFExpression::Evaluate( stack.back().GetScalar() = ptr; stack.back().ClearContext(); } break; + case Value::ValueType::FileAddress: { + auto file_addr = + stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS); + Address so_addr; + auto maybe_load_addr = + ResolveLoadAddress(exe_ctx, module_sp, error_ptr, + "DW_OP_deref_size", file_addr, so_addr, + /*check_sectionoffset=*/true); + + if (!maybe_load_addr) + return false; + + addr_t load_addr = *maybe_load_addr; + + if (load_addr == LLDB_INVALID_ADDRESS && so_addr.IsSectionOffset()) { + uint8_t addr_bytes[8]; + Status error; + + if (exe_ctx->GetTargetRef().ReadMemory( + so_addr, &addr_bytes, size, error, + /*force_live_memory=*/false) == size) { + ObjectFile *objfile = module_sp->GetObjectFile(); + + stack.back().GetScalar() = DerefSizeExtractDataHelper( + addr_bytes, size, objfile->GetByteOrder(), size); + stack.back().ClearContext(); + break; + } else { + if (error_ptr) + error_ptr->SetErrorStringWithFormat( + "Failed to dereference pointer for for DW_OP_deref_size: " + "%s\n", + error.AsCString()); + return false; + } + } + stack.back().GetScalar() = load_addr; + // Fall through to load address promotion code below. + } + + LLVM_FALLTHROUGH; case Value::ValueType::Scalar: case Value::ValueType::LoadAddress: if (exe_ctx) { @@ -1226,26 +1323,10 @@ bool DWARFExpression::Evaluate( Status error; if (process->ReadMemory(pointer_addr, &addr_bytes, size, error) == size) { - DataExtractor addr_data(addr_bytes, sizeof(addr_bytes), - process->GetByteOrder(), size); - lldb::offset_t addr_data_offset = 0; - switch (size) { - case 1: - stack.back().GetScalar() = addr_data.GetU8(&addr_data_offset); - break; - case 2: - stack.back().GetScalar() = addr_data.GetU16(&addr_data_offset); - break; - case 4: - stack.back().GetScalar() = addr_data.GetU32(&addr_data_offset); - break; - case 8: - stack.back().GetScalar() = addr_data.GetU64(&addr_data_offset); - break; - default: - stack.back().GetScalar() = - addr_data.GetAddress(&addr_data_offset); - } + + stack.back().GetScalar() = + DerefSizeExtractDataHelper(addr_bytes, sizeof(addr_bytes), + process->GetByteOrder(), size); stack.back().ClearContext(); } else { if (error_ptr) @@ -1268,7 +1349,6 @@ bool DWARFExpression::Evaluate( } break; - case Value::ValueType::FileAddress: case Value::ValueType::Invalid: if (error_ptr) error_ptr->SetErrorString("Invalid value for DW_OP_deref_size.\n"); @@ -2670,14 +2750,50 @@ static DataExtractor ToDataExtractor(const llvm::DWARFLocationExpression &loc, return DataExtractor(buffer_sp, byte_order, addr_size); } -llvm::Optional<DataExtractor> -DWARFExpression::GetLocationExpression(addr_t load_function_start, - addr_t addr) const { - Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); +bool DWARFExpression::DumpLocations(Stream *s, lldb::DescriptionLevel level, + addr_t load_function_start, addr_t addr, + ABI *abi) { + if (!IsLocationList()) { + DumpLocation(s, m_data, level, abi); + return true; + } + bool dump_all = addr == LLDB_INVALID_ADDRESS; + llvm::ListSeparator separator; + auto callback = [&](llvm::DWARFLocationExpression loc) -> bool { + if (loc.Range && + (dump_all || (loc.Range->LowPC <= addr && addr < loc.Range->HighPC))) { + uint32_t addr_size = m_data.GetAddressByteSize(); + DataExtractor data = ToDataExtractor(loc, m_data.GetByteOrder(), + m_data.GetAddressByteSize()); + s->AsRawOstream() << separator; + s->PutCString("["); + s->AsRawOstream() << llvm::format_hex(loc.Range->LowPC, + 2 + 2 * addr_size); + s->PutCString(", "); + s->AsRawOstream() << llvm::format_hex(loc.Range->HighPC, + 2 + 2 * addr_size); + s->PutCString(") -> "); + DumpLocation(s, data, level, abi); + return dump_all; + } + return true; + }; + if (!GetLocationExpressions(load_function_start, callback)) + return false; + return true; +} + +bool DWARFExpression::GetLocationExpressions( + addr_t load_function_start, + llvm::function_ref<bool(llvm::DWARFLocationExpression)> callback) const { + if (load_function_start == LLDB_INVALID_ADDRESS) + return false; + + Log *log = GetLog(LLDBLog::Expressions); std::unique_ptr<llvm::DWARFLocationTable> loctable_up = m_dwarf_cu->GetLocationTable(m_data); - llvm::Optional<DataExtractor> result; + uint64_t offset = 0; auto lookup_addr = [&](uint32_t index) -> llvm::Optional<llvm::object::SectionedAddress> { @@ -2697,19 +2813,32 @@ DWARFExpression::GetLocationExpression(addr_t load_function_start, addr_t slide = load_function_start - m_loclist_addresses->func_file_addr; loc->Range->LowPC += slide; loc->Range->HighPC += slide; - - if (loc->Range->LowPC <= addr && addr < loc->Range->HighPC) - result = ToDataExtractor(*loc, m_data.GetByteOrder(), - m_data.GetAddressByteSize()); } - return !result; + return callback(*loc); }; - llvm::Error E = loctable_up->visitAbsoluteLocationList( + llvm::Error error = loctable_up->visitAbsoluteLocationList( offset, llvm::object::SectionedAddress{m_loclist_addresses->cu_file_addr}, lookup_addr, process_list); - if (E) - LLDB_LOG_ERROR(log, std::move(E), "{0}"); - return result; + if (error) { + LLDB_LOG_ERROR(log, std::move(error), "{0}"); + return false; + } + return true; +} + +llvm::Optional<DataExtractor> +DWARFExpression::GetLocationExpression(addr_t load_function_start, + addr_t addr) const { + llvm::Optional<DataExtractor> data; + auto callback = [&](llvm::DWARFLocationExpression loc) { + if (loc.Range && loc.Range->LowPC <= addr && addr < loc.Range->HighPC) { + data = ToDataExtractor(loc, m_data.GetByteOrder(), + m_data.GetAddressByteSize()); + } + return !data; + }; + GetLocationExpressions(load_function_start, callback); + return data; } bool DWARFExpression::MatchesOperand(StackFrame &frame, @@ -2732,10 +2861,11 @@ bool DWARFExpression::MatchesOperand(StackFrame &frame, if (load_function_start == LLDB_INVALID_ADDRESS) return false; - addr_t pc = frame.GetFrameCodeAddress().GetLoadAddress( + addr_t pc = frame.GetFrameCodeAddressForSymbolication().GetLoadAddress( frame.CalculateTarget().get()); - if (llvm::Optional<DataExtractor> expr = GetLocationExpression(load_function_start, pc)) + if (llvm::Optional<DataExtractor> expr = + GetLocationExpression(load_function_start, pc)) opcodes = std::move(*expr); else return false; |
