summaryrefslogtreecommitdiff
path: root/view/sharedcache/core/SharedCache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'view/sharedcache/core/SharedCache.cpp')
-rw-r--r--view/sharedcache/core/SharedCache.cpp132
1 files changed, 65 insertions, 67 deletions
diff --git a/view/sharedcache/core/SharedCache.cpp b/view/sharedcache/core/SharedCache.cpp
index 9e43ce0b..6db1037d 100644
--- a/view/sharedcache/core/SharedCache.cpp
+++ b/view/sharedcache/core/SharedCache.cpp
@@ -156,14 +156,14 @@ BNSegmentFlag SegmentFlagsFromMachOProtections(int initProt, int maxProt) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-function"
-static int64_t readSLEB128(DataBuffer& buffer, size_t length, size_t& offset)
+static int64_t readSLEB128(const uint8_t*& current, const uint8_t* end)
{
uint8_t cur;
int64_t value = 0;
size_t shift = 0;
- while (offset < length)
+ while (current != end)
{
- cur = buffer[offset++];
+ cur = *current++;
value |= (cur & 0x7f) << shift;
shift += 7;
if ((cur & 0x80) == 0)
@@ -175,16 +175,16 @@ static int64_t readSLEB128(DataBuffer& buffer, size_t length, size_t& offset)
#pragma clang diagnostic pop
-static uint64_t readLEB128(DataBuffer& p, size_t end, size_t& offset)
+static uint64_t readLEB128(const uint8_t*& current, const uint8_t* end)
{
uint64_t result = 0;
int bit = 0;
do
{
- if (offset >= end)
+ if (current >= end)
return -1;
- uint64_t slice = p[offset] & 0x7f;
+ uint64_t slice = *current & 0x7f;
if (bit > 63)
return -1;
@@ -193,14 +193,14 @@ static uint64_t readLEB128(DataBuffer& p, size_t end, size_t& offset)
result |= (slice << bit);
bit += 7;
}
- } while (p[offset++] & 0x80);
+ } while (*current++ & 0x80);
return result;
}
-uint64_t readValidULEB128(DataBuffer& buffer, size_t& cursor)
+uint64_t readValidULEB128(const uint8_t*& current, const uint8_t* end)
{
- uint64_t value = readLEB128(buffer, buffer.GetLength(), cursor);
+ uint64_t value = readLEB128(current, end);
if ((int64_t)value == -1)
throw ReadException();
return value;
@@ -2281,7 +2281,7 @@ std::optional<SharedCacheMachOHeader> SharedCache::LoadHeaderForAddress(std::sha
}
void SharedCache::InitializeHeader(
- Ref<BinaryView> view, VM* vm, SharedCacheMachOHeader header, std::vector<MemoryRegion*> regionsToLoad)
+ Ref<BinaryView> view, VM* vm, const SharedCacheMachOHeader& header, std::vector<MemoryRegion*> regionsToLoad)
{
WillMutateState();
@@ -2552,9 +2552,11 @@ void SharedCache::InitializeHeader(
uint64_t curfunc = header.textBase;
uint64_t curOffset;
- while (i < header.functionStarts.funcsize)
+ auto current = static_cast<const uint8_t*>(funcStarts.GetData());
+ auto end = current + funcStarts.GetLength();
+ while (current != end)
{
- curOffset = readLEB128(funcStarts, header.functionStarts.funcsize, i);
+ curOffset = readLEB128(current, end);
bool addFunction = false;
for (const auto& region : regionsToLoad)
{
@@ -2709,98 +2711,94 @@ void SharedCache::InitializeHeader(
}
}
-struct ExportNode
-{
- std::string text;
- uint64_t offset;
- uint64_t flags;
-};
-
-void SharedCache::ReadExportNode(std::vector<Ref<Symbol>>& symbolList, SharedCacheMachOHeader& header, DataBuffer& buffer, uint64_t textBase,
- const std::string& currentText, size_t cursor, uint32_t endGuard)
+void SharedCache::ReadExportNode(std::vector<Ref<Symbol>>& symbolList, const SharedCacheMachOHeader& header,
+ const uint8_t* begin, const uint8_t* end, const uint8_t* current, uint64_t textBase, const std::string& currentText)
{
-
- if (cursor > endGuard)
+ if (current >= end)
throw ReadException();
- uint64_t terminalSize = readValidULEB128(buffer, cursor);
- uint64_t childOffset = cursor + terminalSize;
+ uint64_t terminalSize = readValidULEB128(current, end);
+ const uint8_t* child = current + terminalSize;
if (terminalSize != 0) {
uint64_t imageOffset = 0;
- uint64_t flags = readValidULEB128(buffer, cursor);
+ uint64_t flags = readValidULEB128(current, end);
if (!(flags & EXPORT_SYMBOL_FLAGS_REEXPORT))
{
- imageOffset = readValidULEB128(buffer, cursor);
- auto symbolType = m_dscView->GetAnalysisFunctionsForAddress(textBase + imageOffset).size() ? FunctionSymbol : DataSymbol;
+ imageOffset = readValidULEB128(current, end);
+ if (!currentText.empty() && textBase + imageOffset)
{
- if (!currentText.empty() && textBase + imageOffset)
+ uint32_t flags;
+ BNSymbolType type;
+ for (auto s : header.sections)
{
- uint32_t flags;
- BNSymbolType type;
- for (auto s : header.sections)
+ if (s.addr < textBase + imageOffset)
{
- if (s.addr < textBase + imageOffset)
+ if (s.addr + s.size > textBase + imageOffset)
{
- if (s.addr + s.size > textBase + imageOffset)
- {
- flags = s.flags;
- }
+ flags = s.flags;
+ break;
}
}
- if ((flags & S_ATTR_PURE_INSTRUCTIONS) == S_ATTR_PURE_INSTRUCTIONS
- || (flags & S_ATTR_SOME_INSTRUCTIONS) == S_ATTR_SOME_INSTRUCTIONS)
- type = FunctionSymbol;
- else
- type = DataSymbol;
+ }
+ if ((flags & S_ATTR_PURE_INSTRUCTIONS) == S_ATTR_PURE_INSTRUCTIONS
+ || (flags & S_ATTR_SOME_INSTRUCTIONS) == S_ATTR_SOME_INSTRUCTIONS)
+ type = FunctionSymbol;
+ else
+ type = DataSymbol;
#if EXPORT_TRIE_DEBUG
- // BNLogInfo("export: %s -> 0x%llx", n.text.c_str(), image.baseAddress + n.offset);
+ // BNLogInfo("export: %s -> 0x%llx", n.text.c_str(), image.baseAddress + n.offset);
#endif
- auto sym = new Symbol(type, currentText, textBase + imageOffset);
- symbolList.push_back(sym);
- }
+ // TODO: The usual `Symbol` constructors take a `NameSpace` and do unnecessary memory allocations
+ // to pass its fields down to the core API. Here we pass nullptr for the namespace which is treated
+ // the same, but avoids the memory allocations. Switch back to directly constructing a `Symbol`
+ // once it gains constructors without that overhead.
+ auto symbol = new Symbol(BNCreateSymbol(type, currentText.c_str(), currentText.c_str(),
+ currentText.c_str(), textBase + imageOffset, NoBinding, nullptr, 0));
+ symbolList.push_back(symbol);
}
}
}
- cursor = childOffset;
- uint8_t childCount = buffer[cursor];
- cursor++;
- if (cursor > endGuard)
- throw ReadException();
+ current = child;
+ uint8_t childCount = *current++;
+ std::string childText = currentText;
for (uint8_t i = 0; i < childCount; ++i)
{
- std::string childText;
- while (buffer[cursor] != 0 & cursor <= endGuard)
- childText.push_back(buffer[cursor++]);
- cursor++;
- if (cursor > endGuard)
+ if (current >= end)
+ throw ReadException();
+ auto it = std::find(current, end, 0);
+ childText.append(current, it);
+ current = it + 1;
+ if (current >= end)
throw ReadException();
- auto next = readValidULEB128(buffer, cursor);
+ auto next = readValidULEB128(current, end);
if (next == 0)
throw ReadException();
- ReadExportNode(symbolList, header, buffer, textBase, currentText + childText, next, endGuard);
+ ReadExportNode(symbolList, header, begin, end, begin + next, textBase, childText);
+ childText.resize(currentText.size());
}
}
-std::vector<Ref<Symbol>> SharedCache::ParseExportTrie(std::shared_ptr<MMappedFileAccessor> linkeditFile, SharedCacheMachOHeader header)
+std::vector<Ref<Symbol>> SharedCache::ParseExportTrie(std::shared_ptr<MMappedFileAccessor> linkeditFile, const SharedCacheMachOHeader& header)
{
- std::vector<Ref<Symbol>> symbols;
+ if (!header.exportTrie.datasize) {
+ return {};
+ }
+
try
{
- auto reader = linkeditFile;
-
- std::vector<ExportNode> nodes;
-
- DataBuffer buffer = reader->ReadBuffer(header.exportTrie.dataoff, header.exportTrie.datasize);
- ReadExportNode(symbols, header, buffer, header.textBase, "", 0, header.exportTrie.datasize);
+ std::vector<Ref<Symbol>> symbols;
+ auto [begin, end] = linkeditFile->ReadSpan(header.exportTrie.dataoff, header.exportTrie.datasize);
+ ReadExportNode(symbols, header, begin, end, begin, header.textBase, "");
+ return symbols;
}
catch (std::exception& e)
{
BNLogError("Failed to load Export Trie");
+ return {};
}
- return symbols;
}
std::vector<std::string> SharedCache::GetAvailableImages()