forked from OSchip/llvm-project
Fix DWARFUnit::GetUnitDIEPtrOnly stale pointer
GetUnitDIEPtrOnly() needs to return pointer to the first DIE. But the first element of m_die_array after ExtractDIEsIfNeeded(true) may move in memory after later ExtractDIEsIfNeeded(false). DWARFDebugInfoEntry::collection m_die_array is std::vector, its data may move during its expansion. Differential revision: https://reviews.llvm.org/D46810 llvm-svn: 333437
This commit is contained in:
parent
e7ae0f48f4
commit
1bbff4520e
|
@ -1825,3 +1825,15 @@ void DWARFDebugInfoEntry::DumpDIECollection(
|
|||
die_ref.HasChildren() ? " *" : "");
|
||||
}
|
||||
}
|
||||
|
||||
bool DWARFDebugInfoEntry::operator==(const DWARFDebugInfoEntry &rhs) const {
|
||||
return m_offset == rhs.m_offset && m_parent_idx == rhs.m_parent_idx &&
|
||||
m_sibling_idx == rhs.m_sibling_idx &&
|
||||
m_empty_children == rhs.m_empty_children &&
|
||||
m_abbr_idx == rhs.m_abbr_idx && m_has_children == rhs.m_has_children &&
|
||||
m_tag == rhs.m_tag;
|
||||
}
|
||||
|
||||
bool DWARFDebugInfoEntry::operator!=(const DWARFDebugInfoEntry &rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
|
|
@ -60,6 +60,10 @@ public:
|
|||
m_empty_children(false), m_abbr_idx(0), m_has_children(false),
|
||||
m_tag(0) {}
|
||||
|
||||
explicit operator bool() const { return m_offset != DW_INVALID_OFFSET; }
|
||||
bool operator==(const DWARFDebugInfoEntry &rhs) const;
|
||||
bool operator!=(const DWARFDebugInfoEntry &rhs) const;
|
||||
|
||||
void BuildAddressRangeTable(SymbolFileDWARF *dwarf2Data,
|
||||
const DWARFUnit *cu,
|
||||
DWARFDebugAranges *debug_aranges) const;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "lldb/Symbol/CompileUnit.h"
|
||||
#include "lldb/Symbol/LineTable.h"
|
||||
#include "lldb/Symbol/ObjectFile.h"
|
||||
#include "lldb/Utility/LLDBAssert.h"
|
||||
#include "lldb/Utility/StreamString.h"
|
||||
#include "lldb/Utility/Timer.h"
|
||||
|
||||
|
@ -35,19 +36,45 @@ DWARFUnit::DWARFUnit(SymbolFileDWARF *dwarf) : m_dwarf(dwarf) {}
|
|||
DWARFUnit::~DWARFUnit() {}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// ParseCompileUnitDIEsIfNeeded
|
||||
//
|
||||
// Parses first DIE of a compile unit.
|
||||
//----------------------------------------------------------------------
|
||||
void DWARFUnit::ExtractUnitDIEIfNeeded() {
|
||||
if (m_first_die)
|
||||
return; // Already parsed
|
||||
|
||||
static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
|
||||
Timer scoped_timer(
|
||||
func_cat, "%8.8x: DWARFUnit::ExtractUnitDIEIfNeeded()", m_offset);
|
||||
|
||||
// Set the offset to that of the first DIE and calculate the start of the
|
||||
// next compilation unit header.
|
||||
lldb::offset_t offset = GetFirstDIEOffset();
|
||||
|
||||
// We are in our compile unit, parse starting at the offset we were told to
|
||||
// parse
|
||||
const DWARFDataExtractor &data = GetData();
|
||||
DWARFFormValue::FixedFormSizes fixed_form_sizes =
|
||||
DWARFFormValue::GetFixedFormSizesForAddressSize(GetAddressByteSize(),
|
||||
IsDWARF64());
|
||||
if (offset < GetNextCompileUnitOffset() &&
|
||||
m_first_die.FastExtract(data, this, fixed_form_sizes, &offset)) {
|
||||
AddUnitDIE(m_first_die);
|
||||
return;
|
||||
}
|
||||
|
||||
ExtractDIEsEndCheck(offset);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Parses a compile unit and indexes its DIEs if it hasn't already been done.
|
||||
//----------------------------------------------------------------------
|
||||
size_t DWARFUnit::ExtractDIEsIfNeeded(bool cu_die_only) {
|
||||
const size_t initial_die_array_size = m_die_array.size();
|
||||
if ((cu_die_only && initial_die_array_size > 0) || initial_die_array_size > 1)
|
||||
bool DWARFUnit::ExtractDIEsIfNeeded() {
|
||||
if (!m_die_array.empty())
|
||||
return 0; // Already parsed
|
||||
|
||||
static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
|
||||
Timer scoped_timer(
|
||||
func_cat, "%8.8x: DWARFUnit::ExtractDIEsIfNeeded( cu_die_only = %i )",
|
||||
m_offset, cu_die_only);
|
||||
func_cat, "%8.8x: DWARFUnit::ExtractDIEsIfNeeded()", m_offset);
|
||||
|
||||
// Set the offset to that of the first DIE and calculate the start of the
|
||||
// next compilation unit header.
|
||||
|
@ -56,16 +83,14 @@ size_t DWARFUnit::ExtractDIEsIfNeeded(bool cu_die_only) {
|
|||
|
||||
DWARFDebugInfoEntry die;
|
||||
// Keep a flat array of the DIE for binary lookup by DIE offset
|
||||
if (!cu_die_only) {
|
||||
Log *log(
|
||||
LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO | DWARF_LOG_LOOKUPS));
|
||||
if (log) {
|
||||
m_dwarf->GetObjectFile()->GetModule()->LogMessageVerboseBacktrace(
|
||||
log,
|
||||
"DWARFUnit::ExtractDIEsIfNeeded () for compile unit at "
|
||||
".debug_info[0x%8.8x]",
|
||||
GetOffset());
|
||||
}
|
||||
Log *log(
|
||||
LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO | DWARF_LOG_LOOKUPS));
|
||||
if (log) {
|
||||
m_dwarf->GetObjectFile()->GetModule()->LogMessageVerboseBacktrace(
|
||||
log,
|
||||
"DWARFUnit::ExtractDIEsIfNeeded () for compile unit at "
|
||||
".debug_info[0x%8.8x]",
|
||||
GetOffset());
|
||||
}
|
||||
|
||||
uint32_t depth = 0;
|
||||
|
@ -90,16 +115,21 @@ size_t DWARFUnit::ExtractDIEsIfNeeded(bool cu_die_only) {
|
|||
|
||||
const bool null_die = die.IsNULL();
|
||||
if (depth == 0) {
|
||||
if (initial_die_array_size == 0)
|
||||
AddUnitDIE(die);
|
||||
uint64_t base_addr = die.GetAttributeValueAsAddress(
|
||||
m_dwarf, this, DW_AT_low_pc, LLDB_INVALID_ADDRESS);
|
||||
if (base_addr == LLDB_INVALID_ADDRESS)
|
||||
base_addr =
|
||||
die.GetAttributeValueAsAddress(m_dwarf, this, DW_AT_entry_pc, 0);
|
||||
SetBaseAddress(base_addr);
|
||||
if (cu_die_only)
|
||||
return 1;
|
||||
assert(m_die_array.empty() && "Compile unit DIE already added");
|
||||
|
||||
// The average bytes per DIE entry has been seen to be around 14-20 so
|
||||
// lets pre-reserve half of that since we are now stripping the NULL
|
||||
// tags.
|
||||
|
||||
// Only reserve the memory if we are adding children of the main
|
||||
// compile unit DIE. The compile unit DIE is always the first entry, so
|
||||
// if our size is 1, then we are adding the first compile unit child
|
||||
// DIE and should reserve the memory.
|
||||
m_die_array.reserve(GetDebugInfoSize() / 24);
|
||||
m_die_array.push_back(die);
|
||||
|
||||
if (!m_first_die)
|
||||
AddUnitDIE(m_die_array.front());
|
||||
} else {
|
||||
if (null_die) {
|
||||
if (prev_die_had_children) {
|
||||
|
@ -145,14 +175,9 @@ size_t DWARFUnit::ExtractDIEsIfNeeded(bool cu_die_only) {
|
|||
}
|
||||
}
|
||||
|
||||
// Give a little bit of info if we encounter corrupt DWARF (our offset should
|
||||
// always terminate at or before the start of the next compilation unit
|
||||
// header).
|
||||
if (offset > next_cu_offset) {
|
||||
m_dwarf->GetObjectFile()->GetModule()->ReportWarning(
|
||||
"DWARF compile unit extends beyond its bounds cu 0x%8.8x at "
|
||||
"0x%8.8" PRIx64 "\n",
|
||||
GetOffset(), offset);
|
||||
if (!m_die_array.empty()) {
|
||||
lldbassert(!m_first_die || m_first_die == m_die_array.front());
|
||||
m_first_die = m_die_array.front();
|
||||
}
|
||||
|
||||
// Since std::vector objects will double their size, we really need to make a
|
||||
|
@ -164,6 +189,34 @@ size_t DWARFUnit::ExtractDIEsIfNeeded(bool cu_die_only) {
|
|||
m_die_array.end());
|
||||
exact_size_die_array.swap(m_die_array);
|
||||
}
|
||||
|
||||
ExtractDIEsEndCheck(offset);
|
||||
|
||||
if (!m_dwo_symbol_file)
|
||||
return m_die_array.size();
|
||||
|
||||
DWARFUnit *dwo_cu = m_dwo_symbol_file->GetCompileUnit();
|
||||
size_t dwo_die_count = dwo_cu->ExtractDIEsIfNeeded();
|
||||
return m_die_array.size() + dwo_die_count -
|
||||
1; // We have 2 CU die, but we want to count it only as one
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Final checks for both ExtractUnitDIEIfNeeded() and ExtractDIEsIfNeeded().
|
||||
//--------------------------------------------------------------------------
|
||||
void DWARFUnit::ExtractDIEsEndCheck(lldb::offset_t offset) const {
|
||||
lldb::offset_t next_cu_offset = GetNextCompileUnitOffset();
|
||||
|
||||
// Give a little bit of info if we encounter corrupt DWARF (our offset should
|
||||
// always terminate at or before the start of the next compilation unit
|
||||
// header).
|
||||
if (offset > GetNextCompileUnitOffset()) {
|
||||
m_dwarf->GetObjectFile()->GetModule()->ReportWarning(
|
||||
"DWARF compile unit extends beyond its bounds cu 0x%8.8x at "
|
||||
"0x%8.8" PRIx64 "\n",
|
||||
GetOffset(), offset);
|
||||
}
|
||||
|
||||
Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO));
|
||||
if (log && log->GetVerbose()) {
|
||||
StreamString strm;
|
||||
|
@ -174,30 +227,16 @@ size_t DWARFUnit::ExtractDIEsIfNeeded(bool cu_die_only) {
|
|||
m_die_array[0].Dump(m_dwarf, this, strm, UINT32_MAX);
|
||||
log->PutString(strm.GetString());
|
||||
}
|
||||
|
||||
if (!m_dwo_symbol_file)
|
||||
return m_die_array.size();
|
||||
|
||||
DWARFUnit *dwo_cu = m_dwo_symbol_file->GetCompileUnit();
|
||||
size_t dwo_die_count = dwo_cu->ExtractDIEsIfNeeded(cu_die_only);
|
||||
return m_die_array.size() + dwo_die_count -
|
||||
1; // We have 2 CU die, but we want to count it only as one
|
||||
}
|
||||
|
||||
void DWARFUnit::AddUnitDIE(DWARFDebugInfoEntry &die) {
|
||||
assert(m_die_array.empty() && "Compile unit DIE already added");
|
||||
void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) {
|
||||
uint64_t base_addr = cu_die.GetAttributeValueAsAddress(
|
||||
m_dwarf, this, DW_AT_low_pc, LLDB_INVALID_ADDRESS);
|
||||
if (base_addr == LLDB_INVALID_ADDRESS)
|
||||
base_addr = cu_die.GetAttributeValueAsAddress(
|
||||
m_dwarf, this, DW_AT_entry_pc, 0);
|
||||
SetBaseAddress(base_addr);
|
||||
|
||||
// The average bytes per DIE entry has been seen to be around 14-20 so lets
|
||||
// pre-reserve half of that since we are now stripping the NULL tags.
|
||||
|
||||
// Only reserve the memory if we are adding children of the main compile unit
|
||||
// DIE. The compile unit DIE is always the first entry, so if our size is 1,
|
||||
// then we are adding the first compile unit child DIE and should reserve the
|
||||
// memory.
|
||||
m_die_array.reserve(GetDebugInfoSize() / 24);
|
||||
m_die_array.push_back(die);
|
||||
|
||||
const DWARFDebugInfoEntry &cu_die = m_die_array.front();
|
||||
std::unique_ptr<SymbolFileDWARFDwo> dwo_symbol_file =
|
||||
m_dwarf->GetDwoSymbolFileForCompileUnit(*this, cu_die);
|
||||
if (!dwo_symbol_file)
|
||||
|
@ -289,19 +328,8 @@ void DWARFUnit::SetAddrBase(dw_addr_t addr_base,
|
|||
}
|
||||
|
||||
void DWARFUnit::ClearDIEs() {
|
||||
if (m_die_array.size() > 1) {
|
||||
// std::vectors never get any smaller when resized to a smaller size, or
|
||||
// when clear() or erase() are called, the size will report that it is
|
||||
// smaller, but the memory allocated remains intact (call capacity() to see
|
||||
// this). So we need to create a temporary vector and swap the contents
|
||||
// which will cause just the internal pointers to be swapped so that when
|
||||
// "tmp_array" goes out of scope, it will destroy the contents.
|
||||
|
||||
// Save at least the compile unit DIE
|
||||
DWARFDebugInfoEntry::collection tmp_array;
|
||||
m_die_array.swap(tmp_array);
|
||||
m_die_array.push_back(tmp_array.front());
|
||||
}
|
||||
m_die_array.clear();
|
||||
m_die_array.shrink_to_fit();
|
||||
|
||||
if (m_dwo_symbol_file)
|
||||
m_dwo_symbol_file->GetCompileUnit()->ClearDIEs();
|
||||
|
@ -342,7 +370,7 @@ void DWARFUnit::BuildAddressRangeTable(SymbolFileDWARF *dwarf,
|
|||
// If the DIEs weren't parsed, then we don't want all dies for all compile
|
||||
// units to stay loaded when they weren't needed. So we can end up parsing
|
||||
// the DWARF and then throwing them all away to keep memory usage down.
|
||||
const bool clear_dies = ExtractDIEsIfNeeded(false) > 1;
|
||||
const bool clear_dies = ExtractDIEsIfNeeded();
|
||||
|
||||
die = DIEPtr();
|
||||
if (die)
|
||||
|
@ -447,7 +475,7 @@ DWARFUnit::GetDIE(dw_offset_t die_offset) {
|
|||
return GetDwoSymbolFile()->GetCompileUnit()->GetDIE(die_offset);
|
||||
|
||||
if (ContainsDIEOffset(die_offset)) {
|
||||
ExtractDIEsIfNeeded(false);
|
||||
ExtractDIEsIfNeeded();
|
||||
DWARFDebugInfoEntry::const_iterator end = m_die_array.cend();
|
||||
DWARFDebugInfoEntry::const_iterator pos =
|
||||
lower_bound(m_die_array.cbegin(), end, die_offset, CompareDIEOffset);
|
||||
|
|
|
@ -39,7 +39,8 @@ class DWARFUnit {
|
|||
public:
|
||||
virtual ~DWARFUnit();
|
||||
|
||||
size_t ExtractDIEsIfNeeded(bool cu_die_only);
|
||||
void ExtractUnitDIEIfNeeded();
|
||||
bool ExtractDIEsIfNeeded();
|
||||
DWARFDIE LookupAddress(const dw_addr_t address);
|
||||
size_t AppendDIEsWithTag(const dw_tag_t tag,
|
||||
DWARFDIECollection &matching_dies,
|
||||
|
@ -160,7 +161,7 @@ public:
|
|||
dw_offset_t GetBaseObjOffset() const;
|
||||
|
||||
die_iterator_range dies() {
|
||||
ExtractDIEsIfNeeded(false);
|
||||
ExtractDIEsIfNeeded();
|
||||
return die_iterator_range(m_die_array.begin(), m_die_array.end());
|
||||
}
|
||||
|
||||
|
@ -173,6 +174,10 @@ protected:
|
|||
void *m_user_data = nullptr;
|
||||
// The compile unit debug information entry item
|
||||
DWARFDebugInfoEntry::collection m_die_array;
|
||||
// GetUnitDIEPtrOnly() needs to return pointer to the first DIE.
|
||||
// But the first element of m_die_array after ExtractUnitDIEIfNeeded()
|
||||
// would possibly move in memory after later ExtractDIEsIfNeeded().
|
||||
DWARFDebugInfoEntry m_first_die;
|
||||
// A table similar to the .debug_aranges table, but this one points to the
|
||||
// exact DW_TAG_subprogram DIEs
|
||||
std::unique_ptr<DWARFDebugAranges> m_func_aranges_ap;
|
||||
|
@ -202,21 +207,22 @@ private:
|
|||
// Get the DWARF unit DWARF debug informration entry. Parse the single DIE
|
||||
// if needed.
|
||||
const DWARFDebugInfoEntry *GetUnitDIEPtrOnly() {
|
||||
ExtractDIEsIfNeeded(true);
|
||||
if (m_die_array.empty())
|
||||
ExtractUnitDIEIfNeeded();
|
||||
if (!m_first_die)
|
||||
return NULL;
|
||||
return &m_die_array[0];
|
||||
return &m_first_die;
|
||||
}
|
||||
|
||||
// Get all DWARF debug informration entries. Parse all DIEs if needed.
|
||||
const DWARFDebugInfoEntry *DIEPtr() {
|
||||
ExtractDIEsIfNeeded(false);
|
||||
ExtractDIEsIfNeeded();
|
||||
if (m_die_array.empty())
|
||||
return NULL;
|
||||
return &m_die_array[0];
|
||||
}
|
||||
|
||||
void AddUnitDIE(DWARFDebugInfoEntry &die);
|
||||
void AddUnitDIE(const DWARFDebugInfoEntry &cu_die);
|
||||
void ExtractDIEsEndCheck(lldb::offset_t offset) const;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DWARFUnit);
|
||||
};
|
||||
|
|
|
@ -50,9 +50,9 @@ void ManualDWARFIndex::Index() {
|
|||
auto extract_fn = [&debug_info, &clear_cu_dies](size_t cu_idx) {
|
||||
DWARFUnit *dwarf_cu = debug_info.GetCompileUnitAtIndex(cu_idx);
|
||||
if (dwarf_cu) {
|
||||
// dwarf_cu->ExtractDIEsIfNeeded(false) will return zero if the DIEs
|
||||
// dwarf_cu->ExtractDIEsIfNeeded() will return false if the DIEs
|
||||
// for a compile unit have already been parsed.
|
||||
if (dwarf_cu->ExtractDIEsIfNeeded(false) > 1)
|
||||
if (dwarf_cu->ExtractDIEsIfNeeded())
|
||||
clear_cu_dies[cu_idx] = true;
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue