UniqueCStringMap<T> objects are a std::vector<UniqueCStringMap::Entry> objects where the Entry object contains a ConstString + T. The values in the vector are sorted first by ConstString and then by the T value. ConstString objects are simply uniqued "const char *" values and when we compare we use the actual string pointer as the value we sort by. This caused a problem when we saved the symbol table name indexes and debug info indexes to disk in one process when they were sorted, and then loaded them into another process when decoding them from the cache files. Why? Because the order in which the ConstString objects were created are now completely different and the string pointers will no longer be sorted in the new process the cache was loaded into. The unit tests created for the initial patch didn't catch the encoding and decoding issues of UniqueCStringMap<T> because they were happening in the same process and encoding and decoding would end up createing sorted UniqueCStringMap<T> objects due to the constant string pool being exactly the same. This patch does the sort and also reserves the right amount of entries in the UniqueCStringMap::m_map prior to adding them all to avoid doing multiple allocations. Added a unit test that loads an object file from yaml, and then I created a cache file for the original file and removed the cache file's signature mod time check since we will generate an object file from the YAML, and use that as the object file for the Symtab object. Then we load the cache data from the array of symtab cache bytes so that the ConstString "const char *" values will not match the current process, and verify we can lookup the 4 names from the object file in the symbol table. Differential Revision: https://reviews.llvm.org/D124572
151 lines
5.2 KiB
C++
151 lines
5.2 KiB
C++
//===-- NameToDIE.cpp -----------------------------------------------------===//
|
|
//
|
|
// 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 "NameToDIE.h"
|
|
#include "DWARFUnit.h"
|
|
#include "lldb/Core/DataFileCache.h"
|
|
#include "lldb/Symbol/ObjectFile.h"
|
|
#include "lldb/Utility/ConstString.h"
|
|
#include "lldb/Utility/DataEncoder.h"
|
|
#include "lldb/Utility/DataExtractor.h"
|
|
#include "lldb/Utility/RegularExpression.h"
|
|
#include "lldb/Utility/Stream.h"
|
|
#include "lldb/Utility/StreamString.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
void NameToDIE::Finalize() {
|
|
m_map.Sort(std::less<DIERef>());
|
|
m_map.SizeToFit();
|
|
}
|
|
|
|
void NameToDIE::Insert(ConstString name, const DIERef &die_ref) {
|
|
m_map.Append(name, die_ref);
|
|
}
|
|
|
|
bool NameToDIE::Find(ConstString name,
|
|
llvm::function_ref<bool(DIERef ref)> callback) const {
|
|
for (const auto &entry : m_map.equal_range(name))
|
|
if (!callback(entry.value))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool NameToDIE::Find(const RegularExpression ®ex,
|
|
llvm::function_ref<bool(DIERef ref)> callback) const {
|
|
for (const auto &entry : m_map)
|
|
if (regex.Execute(entry.cstring.GetCString())) {
|
|
if (!callback(entry.value))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void NameToDIE::FindAllEntriesForUnit(
|
|
DWARFUnit &s_unit, llvm::function_ref<bool(DIERef ref)> callback) const {
|
|
lldbassert(!s_unit.GetSymbolFileDWARF().GetDwoNum());
|
|
const DWARFUnit &ns_unit = s_unit.GetNonSkeletonUnit();
|
|
const uint32_t size = m_map.GetSize();
|
|
for (uint32_t i = 0; i < size; ++i) {
|
|
const DIERef &die_ref = m_map.GetValueAtIndexUnchecked(i);
|
|
if (ns_unit.GetSymbolFileDWARF().GetDwoNum() == die_ref.dwo_num() &&
|
|
ns_unit.GetDebugSection() == die_ref.section() &&
|
|
ns_unit.GetOffset() <= die_ref.die_offset() &&
|
|
die_ref.die_offset() < ns_unit.GetNextUnitOffset()) {
|
|
if (!callback(die_ref))
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void NameToDIE::Dump(Stream *s) {
|
|
const uint32_t size = m_map.GetSize();
|
|
for (uint32_t i = 0; i < size; ++i) {
|
|
s->Format("{0} \"{1}\"\n", m_map.GetValueAtIndexUnchecked(i),
|
|
m_map.GetCStringAtIndexUnchecked(i));
|
|
}
|
|
}
|
|
|
|
void NameToDIE::ForEach(
|
|
std::function<bool(ConstString name, const DIERef &die_ref)> const
|
|
&callback) const {
|
|
const uint32_t size = m_map.GetSize();
|
|
for (uint32_t i = 0; i < size; ++i) {
|
|
if (!callback(m_map.GetCStringAtIndexUnchecked(i),
|
|
m_map.GetValueAtIndexUnchecked(i)))
|
|
break;
|
|
}
|
|
}
|
|
|
|
void NameToDIE::Append(const NameToDIE &other) {
|
|
const uint32_t size = other.m_map.GetSize();
|
|
for (uint32_t i = 0; i < size; ++i) {
|
|
m_map.Append(other.m_map.GetCStringAtIndexUnchecked(i),
|
|
other.m_map.GetValueAtIndexUnchecked(i));
|
|
}
|
|
}
|
|
|
|
constexpr llvm::StringLiteral kIdentifierNameToDIE("N2DI");
|
|
|
|
bool NameToDIE::Decode(const DataExtractor &data, lldb::offset_t *offset_ptr,
|
|
const StringTableReader &strtab) {
|
|
m_map.Clear();
|
|
llvm::StringRef identifier((const char *)data.GetData(offset_ptr, 4), 4);
|
|
if (identifier != kIdentifierNameToDIE)
|
|
return false;
|
|
const uint32_t count = data.GetU32(offset_ptr);
|
|
m_map.Reserve(count);
|
|
for (uint32_t i = 0; i < count; ++i) {
|
|
llvm::StringRef str(strtab.Get(data.GetU32(offset_ptr)));
|
|
// No empty strings allowed in the name to DIE maps.
|
|
if (str.empty())
|
|
return false;
|
|
if (llvm::Optional<DIERef> die_ref = DIERef::Decode(data, offset_ptr))
|
|
m_map.Append(ConstString(str), die_ref.getValue());
|
|
else
|
|
return false;
|
|
}
|
|
// We must sort the UniqueCStringMap after decoding it since it is a vector
|
|
// of UniqueCStringMap::Entry objects which contain a ConstString and type T.
|
|
// ConstString objects are sorted by "const char *" and then type T and
|
|
// the "const char *" are point values that will depend on the order in which
|
|
// ConstString objects are created and in which of the 256 string pools they
|
|
// are created in. So after we decode all of the entries, we must sort the
|
|
// name map to ensure name lookups succeed. If we encode and decode within
|
|
// the same process we wouldn't need to sort, so unit testing didn't catch
|
|
// this issue when first checked in.
|
|
m_map.Sort(std::less<DIERef>());
|
|
return true;
|
|
}
|
|
|
|
void NameToDIE::Encode(DataEncoder &encoder, ConstStringTable &strtab) const {
|
|
encoder.AppendData(kIdentifierNameToDIE);
|
|
encoder.AppendU32(m_map.GetSize());
|
|
for (const auto &entry : m_map) {
|
|
// Make sure there are no empty strings.
|
|
assert((bool)entry.cstring);
|
|
encoder.AppendU32(strtab.Add(entry.cstring));
|
|
entry.value.Encode(encoder);
|
|
}
|
|
}
|
|
|
|
bool NameToDIE::operator==(const NameToDIE &rhs) const {
|
|
const size_t size = m_map.GetSize();
|
|
if (size != rhs.m_map.GetSize())
|
|
return false;
|
|
for (size_t i = 0; i < size; ++i) {
|
|
if (m_map.GetCStringAtIndex(i) != rhs.m_map.GetCStringAtIndex(i))
|
|
return false;
|
|
if (m_map.GetValueRefAtIndexUnchecked(i) !=
|
|
rhs.m_map.GetValueRefAtIndexUnchecked(i))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|