| 607 | } |
| 608 | |
| 609 | std::vector<CacheSymbol> SharedCacheMachOHeader::ReadExportSymbolTrie(VirtualMemory& vm) const |
| 610 | { |
| 611 | // nothing to do if there’s no export‐trie |
| 612 | if (exportTrie.datasize == 0 || exportTrie.dataoff == 0) |
| 613 | return {}; |
| 614 | std::vector<CacheSymbol> symbols = {}; |
| 615 | try { |
| 616 | auto [begin, end] = vm.ReadSpan(GetLinkEditFileBase() + exportTrie.dataoff, exportTrie.datasize); |
| 617 | const uint8_t *cursor = begin; |
| 618 | |
| 619 | struct Node |
| 620 | { |
| 621 | const uint8_t* cursor; |
| 622 | std::string text; |
| 623 | }; |
| 624 | std::vector<Node> stack; |
| 625 | stack.reserve(64); |
| 626 | stack.push_back({ /* cursor */ begin, /* text */ "" }); |
| 627 | |
| 628 | while (!stack.empty()) |
| 629 | { |
| 630 | Node node = std::move(stack.back()); |
| 631 | stack.pop_back(); |
| 632 | |
| 633 | cursor = node.cursor; |
| 634 | const std::string currentText = std::move(node.text); |
| 635 | |
| 636 | if (cursor > end) |
| 637 | { |
| 638 | LogError("Export Trie: Cursor left trie during initial bounds check"); |
| 639 | throw ReadException(); |
| 640 | } |
| 641 | |
| 642 | uint64_t terminalSize = readValidULEB128(cursor, end); |
| 643 | const uint8_t* childCursor = cursor + terminalSize; |
| 644 | |
| 645 | // If there's terminal data, define the symbol |
| 646 | if (terminalSize != 0) |
| 647 | { |
| 648 | AddExportTerminalSymbol(symbols, currentText, cursor, end); |
| 649 | } |
| 650 | |
| 651 | cursor = childCursor; |
| 652 | if (cursor > end) |
| 653 | { |
| 654 | LogError("Export Trie: Cursor left trie while moving to child offset"); |
| 655 | throw ReadException(); |
| 656 | } |
| 657 | |
| 658 | uint8_t childCount = *cursor; |
| 659 | cursor++; |
| 660 | if (cursor > end) |
| 661 | { |
| 662 | LogError("Export Trie: Cursor left trie while reading child count"); |
| 663 | throw ReadException(); |
| 664 | } |
| 665 | |
| 666 | std::vector<Node> children; |
no test coverage detected