Files
clang-p2996/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp
Pavel Labath 7db8b5c4bd ObjectFilePECOFF: Create a "container" section spanning the entire module image
Summary:
This is coming from the discussion in D55356 (the most interesting part
happened on the mailing list, so it isn't reflected on the review page).

In short the issue is that lldb assumes that all bytes of a module image
in memory will be backed by a "section". This isn't the case for PECOFF
files because the initial bytes of the module image will contain the
file header, which does not correspond to any normal section in the
file. In particular, this means it is not possible to implement
GetBaseAddress function for PECOFF files, because that's supposed point
to the first byte of that header.

If my (limited) understanding of how PECOFF files work is correct, then
the OS is expecded to load the entire module into one continuous chunk
of memory. The address of that chunk (+/- ASLR) is given by the "image
base" field in the COFF header, and it's size by "image size". All of
the COFF sections are then loaded into this range.

If that's true, then we can model this behavior in lldb by creating a
"container" section to represent the entire module image, and then place
other sections inside that. This would make be consistent with how MachO
and ELF files are modelled (except that those can have multiple
top-level containers as they can be loaded into multiple discontinuous
chunks of memory).

This change required a small number of fixups in the PDB plugins, which
assumed a certain order of sections within the object file (which
obivously changes now). I fix this by changing the lookup code to use
section IDs (which are unchanged) instead of indexes. This has the nice
benefit of removing spurious -1s in the plugins as the section IDs in
the pdbs match the 1-based section IDs in the COFF plugin.

Besides making the implementation of GetBaseAddress possible, this also
improves the lookup of addresses in the gaps between the object file
sections, which will now be correctly resolved as belonging to the
object file.

Reviewers: zturner, amccarth, stella.stamenova, clayborg, lemo

Reviewed By: clayborg, lemo

Subscribers: JDevlieghere, abidh, lldb-commits

Tags: #lldb

Differential Revision: https://reviews.llvm.org/D56537

llvm-svn: 353916
2019-02-13 07:17:24 +00:00

182 lines
5.5 KiB
C++

//===-- PDBLocationToDWARFExpression.cpp ------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "PDBLocationToDWARFExpression.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/StreamBuffer.h"
#include "lldb/Core/dwarf.h"
#include "lldb/Expression/DWARFExpression.h"
#include "lldb/Symbol/Variable.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/DebugInfo/PDB/IPDBSession.h"
#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
#include "Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.h"
#include "Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.h"
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::npdb;
using namespace llvm::pdb;
static std::unique_ptr<IPDBFrameData>
GetCorrespondingFrameData(const IPDBSession &session,
const Variable::RangeList &ranges) {
auto enumFrameData = session.getFrameData();
if (!enumFrameData)
return nullptr;
std::unique_ptr<IPDBFrameData> found;
while (auto fd = enumFrameData->getNext()) {
Range<lldb::addr_t, lldb::addr_t> fdRange(fd->getVirtualAddress(),
fd->getLengthBlock());
for (size_t i = 0; i < ranges.GetSize(); i++) {
auto range = ranges.GetEntryAtIndex(i);
if (!range)
continue;
if (!range->DoesIntersect(fdRange))
continue;
found = std::move(fd);
break;
}
}
return found;
}
static bool EmitVFrameEvaluationDWARFExpression(
llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream) {
// VFrame value always stored in $TO pseudo-register
return TranslateFPOProgramToDWARFExpression(program, "$T0", arch_type,
stream);
}
DWARFExpression ConvertPDBLocationToDWARFExpression(
ModuleSP module, const PDBSymbolData &symbol,
const Variable::RangeList &ranges, bool &is_constant) {
is_constant = true;
if (!module)
return DWARFExpression(nullptr);
const ArchSpec &architecture = module->GetArchitecture();
llvm::Triple::ArchType arch_type = architecture.GetMachine();
ByteOrder byte_order = architecture.GetByteOrder();
uint32_t address_size = architecture.GetAddressByteSize();
uint32_t byte_size = architecture.GetDataByteSize();
if (byte_order == eByteOrderInvalid || address_size == 0)
return DWARFExpression(nullptr);
RegisterKind register_kind = eRegisterKindDWARF;
StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order);
switch (symbol.getLocationType()) {
case PDB_LocType::Static:
case PDB_LocType::TLS: {
stream.PutHex8(DW_OP_addr);
SectionList *section_list = module->GetSectionList();
if (!section_list)
return DWARFExpression(nullptr);
uint32_t section_id = symbol.getAddressSection();
auto section = section_list->FindSectionByID(section_id);
if (!section)
return DWARFExpression(nullptr);
uint32_t offset = symbol.getAddressOffset();
stream.PutMaxHex64(section->GetFileAddress() + offset, address_size,
byte_order);
is_constant = false;
break;
}
case PDB_LocType::RegRel: {
uint32_t reg_num;
auto reg_id = symbol.getRegisterId();
if (reg_id == llvm::codeview::RegisterId::VFRAME) {
if (auto fd = GetCorrespondingFrameData(symbol.getSession(), ranges)) {
if (EmitVFrameEvaluationDWARFExpression(fd->getProgram(), arch_type,
stream)) {
int32_t offset = symbol.getOffset();
stream.PutHex8(DW_OP_consts);
stream.PutSLEB128(offset);
stream.PutHex8(DW_OP_plus);
register_kind = eRegisterKindLLDB;
is_constant = false;
break;
}
}
register_kind = eRegisterKindGeneric;
reg_num = LLDB_REGNUM_GENERIC_FP;
} else {
register_kind = eRegisterKindLLDB;
reg_num = GetLLDBRegisterNumber(arch_type, reg_id);
if (reg_num == LLDB_INVALID_REGNUM)
return DWARFExpression(nullptr);
}
if (reg_num > 31) {
stream.PutHex8(DW_OP_bregx);
stream.PutULEB128(reg_num);
} else
stream.PutHex8(DW_OP_breg0 + reg_num);
int32_t offset = symbol.getOffset();
stream.PutSLEB128(offset);
is_constant = false;
break;
}
case PDB_LocType::Enregistered: {
register_kind = eRegisterKindLLDB;
uint32_t reg_num = GetLLDBRegisterNumber(arch_type, symbol.getRegisterId());
if (reg_num == LLDB_INVALID_REGNUM)
return DWARFExpression(nullptr);
if (reg_num > 31) {
stream.PutHex8(DW_OP_regx);
stream.PutULEB128(reg_num);
} else
stream.PutHex8(DW_OP_reg0 + reg_num);
is_constant = false;
break;
}
case PDB_LocType::Constant: {
Variant value = symbol.getValue();
stream.PutRawBytes(&value.Value, sizeof(value.Value),
endian::InlHostByteOrder());
break;
}
default:
return DWARFExpression(nullptr);
}
DataBufferSP buffer =
std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());
DataExtractor extractor(buffer, byte_order, address_size, byte_size);
DWARFExpression result(module, extractor, nullptr, 0, buffer->GetByteSize());
result.SetRegisterKind(register_kind);
return result;
}