<html><head><meta http-equiv="Content-Type" content="text/html charset=windows-1252"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div>Fixed in r216809.</div><br><div><div>On Aug 29, 2014, at 6:54 PM, Sean Silva <<a href="mailto:chisophugis@gmail.com">chisophugis@gmail.com</a>> wrote:</div><blockquote type="cite"><div dir="ltr"><span style="font-family:arial,sans-serif;font-size:13px">+ if (!CumulativeString.str().</span><span style="font-family:arial,sans-serif;font-size:13px">equals(CumulativeString.str())</span><span style="font-family:arial,sans-serif;font-size:13px">)</span><br style="font-family:arial,sans-serif;font-size:13px">
<span style="font-family:arial,sans-serif;font-size:13px">+ return false;</span><br><div><span style="font-family:arial,sans-serif;font-size:13px"><br></span></div><div><span style="font-family:arial,sans-serif;font-size:13px">Bug? Do we have test coverage for this?</span></div></div></blockquote><div>Yes bug. (Hey, would be great if the compiler had enough insight into that expression to realize it is a self-comparison and issue a warning like it does for “if (x != x)” ).</div><div><br></div><div>In normal for() iterations that code is never exercised because you are just comparing against the end() iterator which has an empty stack and no cumulative string. </div><div><br></div><br><blockquote type="cite"><div dir="ltr">
<div><span style="font-family:arial,sans-serif;font-size:13px"><br></span></div><div><span style="font-family:arial,sans-serif;font-size:13px"><br></span></div><div><span style="font-family:arial,sans-serif;font-size:13px">+ State.Address = readULEB128(State.Current);</span><br style="font-family:arial,sans-serif;font-size:13px">
<span style="font-family:arial,sans-serif;font-size:13px">+ if (State.Flags & MachO::EXPORT_SYMBOL_FLAGS_</span><span style="font-family:arial,sans-serif;font-size:13px">STUB_AND_RESOLVER)</span><br style="font-family:arial,sans-serif;font-size:13px">
<span style="font-family:arial,sans-serif;font-size:13px">+ State.Other = readULEB128(State.Current);</span><br style="font-family:arial,sans-serif;font-size:13px"><span style="font-family:arial,sans-serif;font-size:13px">+ }</span><span style="font-family:arial,sans-serif;font-size:13px"><br>
</span></div><div><span style="font-family:arial,sans-serif;font-size:13px"><br></span></div><div><span style="font-family:arial,sans-serif;font-size:13px">How did the `if` get all the way over there.</span></div></div></blockquote><div>Some how a TAB slipped in. Not sure how.</div><div><br></div><div>-Nick</div><div><br></div><div><br></div><blockquote type="cite"><div class="gmail_extra"><br><br><div class="gmail_quote">On Fri, Aug 29, 2014 at 5:20 PM, Nick Kledzik <span dir="ltr"><<a href="mailto:kledzik@apple.com" target="_blank">kledzik@apple.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: kledzik<br>
Date: Fri Aug 29 19:20:14 2014<br>
New Revision: 216808<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=216808&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=216808&view=rev</a><br>
Log:<br>
Object/llvm-objdump: allow dumping of mach-o exports trie<br>
<br>
MachOObjectFile in lib/Object currently has no support for parsing the rebase,<br>
binding, and export information from the LC_DYLD_INFO load command in final<br>
linked mach-o images. This patch adds support for parsing the exports trie data<br>
structure. It also adds an option to llvm-objdump to dump that export info.<br>
<br>
I did the exports parsing first because it is the hardest. The information is<br>
encoded in a trie structure, but the standard ObjectFile way to inspect content<br>
is through iterators. So I needed to make an iterator that would do a<br>
non-recursive walk through the trie and maintain the concatenation of edges<br>
needed for the current string prefix.<br>
<br>
I plan to add similar support in MachOObjectFile and llvm-objdump to<br>
parse/display the rebasing and binding info too.<br>
<br>
Added:<br>
llvm/trunk/test/tools/llvm-objdump/Inputs/exports-trie.macho-x86_64 (with props)<br>
llvm/trunk/test/tools/llvm-objdump/macho-exports-trie.test<br>
Modified:<br>
llvm/trunk/include/llvm/Object/MachO.h<br>
llvm/trunk/include/llvm/Support/MachO.h<br>
llvm/trunk/lib/Object/MachOObjectFile.cpp<br>
llvm/trunk/tools/llvm-objdump/MachODump.cpp<br>
llvm/trunk/tools/llvm-objdump/llvm-objdump.cpp<br>
llvm/trunk/tools/llvm-objdump/llvm-objdump.h<br>
<br>
Modified: llvm/trunk/include/llvm/Object/MachO.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Object/MachO.h?rev=216808&r1=216807&r2=216808&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Object/MachO.h?rev=216808&r1=216807&r2=216808&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/Object/MachO.h (original)<br>
+++ llvm/trunk/include/llvm/Object/MachO.h Fri Aug 29 19:20:14 2014<br>
@@ -49,6 +49,57 @@ public:<br>
};<br>
typedef content_iterator<DiceRef> dice_iterator;<br>
<br>
+/// ExportEntry encapsulates the current-state-of-the-walk used when doing a<br>
+/// non-recursive walk of the trie data structure. This allows you to iterate<br>
+/// across all exported symbols using:<br>
+/// for (const llvm::object::ExportEntry &AnExport : Obj->exports()) {<br>
+/// }<br>
+class ExportEntry {<br>
+public:<br>
+ ExportEntry(ArrayRef<uint8_t> Trie);<br>
+<br>
+ StringRef name() const;<br>
+ uint64_t flags() const;<br>
+ uint64_t address() const;<br>
+ uint64_t other() const;<br>
+ StringRef otherName() const;<br>
+ uint32_t nodeOffset() const;<br>
+<br>
+ bool operator==(const ExportEntry &) const;<br>
+<br>
+ void moveNext();<br>
+<br>
+private:<br>
+ friend class MachOObjectFile;<br>
+ void moveToFirst();<br>
+ void moveToEnd();<br>
+ uint64_t readULEB128(const uint8_t *&p);<br>
+ void pushDownUntilBottom();<br>
+ void pushNode(uint64_t Offset);<br>
+<br>
+ // Represents a node in the mach-o exports trie.<br>
+ struct NodeState {<br>
+ NodeState(const uint8_t *Ptr);<br>
+ const uint8_t *Start;<br>
+ const uint8_t *Current;<br>
+ uint64_t Flags;<br>
+ uint64_t Address;<br>
+ uint64_t Other;<br>
+ const char *ImportName;<br>
+ unsigned ChildCount;<br>
+ unsigned NextChildIndex;<br>
+ unsigned ParentStringLength;<br>
+ bool IsExportNode;<br>
+ };<br>
+<br>
+ ArrayRef<uint8_t> Trie;<br>
+ SmallString<256> CumulativeString;<br>
+ SmallVector<NodeState, 16> Stack;<br>
+ bool Malformed;<br>
+ bool Done;<br>
+};<br>
+typedef content_iterator<ExportEntry> export_iterator;<br>
+<br>
class MachOObjectFile : public ObjectFile {<br>
public:<br>
struct LoadCommandInfo {<br>
@@ -119,7 +170,7 @@ public:<br>
bool &Result) const override;<br>
<br>
// MachO specific.<br>
- std::error_code getLibraryShortNameByIndex(unsigned Index, StringRef &Res);<br>
+ std::error_code getLibraryShortNameByIndex(unsigned Index, StringRef &) const;<br>
<br>
// TODO: Would be useful to have an iterator based version<br>
// of the load command interface too.<br>
@@ -144,6 +195,12 @@ public:<br>
<br>
dice_iterator begin_dices() const;<br>
dice_iterator end_dices() const;<br>
+<br>
+ /// For use iterating over all exported symbols.<br>
+ iterator_range<export_iterator> exports() const;<br>
+<br>
+ /// For use examining a trie not in a MachOObjectFile.<br>
+ static iterator_range<export_iterator> exports(ArrayRef<uint8_t> Trie);<br>
<br>
// In a MachO file, sections have a segment name. This is used in the .o<br>
// files. They have a single segment, but this field specifies which segment<br>
@@ -207,6 +264,11 @@ public:<br>
MachO::symtab_command getSymtabLoadCommand() const;<br>
MachO::dysymtab_command getDysymtabLoadCommand() const;<br>
MachO::linkedit_data_command getDataInCodeLoadCommand() const;<br>
+ ArrayRef<uint8_t> getDyldInfoRebaseOpcodes() const;<br>
+ ArrayRef<uint8_t> getDyldInfoBindOpcodes() const;<br>
+ ArrayRef<uint8_t> getDyldInfoWeakBindOpcodes() const;<br>
+ ArrayRef<uint8_t> getDyldInfoLazyBindOpcodes() const;<br>
+ ArrayRef<uint8_t> getDyldInfoExportsTrie() const;<br>
<br>
StringRef getStringTableData() const;<br>
bool is64Bit() const;<br>
@@ -237,10 +299,11 @@ private:<br>
typedef SmallVector<const char*, 1> LibraryList;<br>
LibraryList Libraries;<br>
typedef SmallVector<StringRef, 1> LibraryShortName;<br>
- LibraryShortName LibrariesShortNames;<br>
+ mutable LibraryShortName LibrariesShortNames;<br>
const char *SymtabLoadCmd;<br>
const char *DysymtabLoadCmd;<br>
const char *DataInCodeLoadCmd;<br>
+ const char *DyldInfoLoadCmd;<br>
};<br>
<br>
/// DiceRef<br>
<br>
Modified: llvm/trunk/include/llvm/Support/MachO.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/MachO.h?rev=216808&r1=216807&r2=216808&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/MachO.h?rev=216808&r1=216807&r2=216808&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/Support/MachO.h (original)<br>
+++ llvm/trunk/include/llvm/Support/MachO.h Fri Aug 29 19:20:14 2014<br>
@@ -322,13 +322,13 @@ namespace llvm {<br>
};<br>
<br>
enum {<br>
+ EXPORT_SYMBOL_FLAGS_KIND_MASK = 0x03u,<br>
EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION = 0x04u,<br>
EXPORT_SYMBOL_FLAGS_REEXPORT = 0x08u,<br>
EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER = 0x10u<br>
};<br>
<br>
enum ExportSymbolKind {<br>
- EXPORT_SYMBOL_FLAGS_KIND_MASK = 0x03u,<br>
EXPORT_SYMBOL_FLAGS_KIND_REGULAR = 0x00u,<br>
EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL = 0x01u,<br>
EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE = 0x02u<br>
<br>
Modified: llvm/trunk/lib/Object/MachOObjectFile.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/MachOObjectFile.cpp?rev=216808&r1=216807&r2=216808&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/MachOObjectFile.cpp?rev=216808&r1=216807&r2=216808&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Object/MachOObjectFile.cpp (original)<br>
+++ llvm/trunk/lib/Object/MachOObjectFile.cpp Fri Aug 29 19:20:14 2014<br>
@@ -19,6 +19,8 @@<br>
#include "llvm/Support/DataExtractor.h"<br>
#include "llvm/Support/Format.h"<br>
#include "llvm/Support/Host.h"<br>
+#include "llvm/Support/LEB128.h"<br>
+#include "llvm/Support/MachO.h"<br>
#include "llvm/Support/MemoryBuffer.h"<br>
#include "llvm/Support/raw_ostream.h"<br>
#include <cctype><br>
@@ -226,7 +228,7 @@ MachOObjectFile::MachOObjectFile(MemoryB<br>
bool Is64bits, std::error_code &EC)<br>
: ObjectFile(getMachOType(IsLittleEndian, Is64bits), Object),<br>
SymtabLoadCmd(nullptr), DysymtabLoadCmd(nullptr),<br>
- DataInCodeLoadCmd(nullptr) {<br>
+ DataInCodeLoadCmd(nullptr), DyldInfoLoadCmd(nullptr) {<br>
uint32_t LoadCommandCount = this->getHeader().ncmds;<br>
MachO::LoadCommandType SegmentLoadType = is64Bit() ?<br>
MachO::LC_SEGMENT_64 : MachO::LC_SEGMENT;<br>
@@ -242,6 +244,10 @@ MachOObjectFile::MachOObjectFile(MemoryB<br>
} else if (Load.C.cmd == MachO::LC_DATA_IN_CODE) {<br>
assert(!DataInCodeLoadCmd && "Multiple data in code tables");<br>
DataInCodeLoadCmd = Load.Ptr;<br>
+ } else if (Load.C.cmd == MachO::LC_DYLD_INFO ||<br>
+ Load.C.cmd == MachO::LC_DYLD_INFO_ONLY) {<br>
+ assert(!DyldInfoLoadCmd && "Multiple dyldinfo load commands");<br>
+ DyldInfoLoadCmd = Load.Ptr;<br>
} else if (Load.C.cmd == SegmentLoadType) {<br>
uint32_t NumSections = getSegmentLoadCommandNumSections(this, Load);<br>
for (unsigned J = 0; J < NumSections; ++J) {<br>
@@ -1159,7 +1165,7 @@ guess_qtx:<br>
// It is passed the index (0 - based) of the library as translated from<br>
// GET_LIBRARY_ORDINAL (1 - based).<br>
std::error_code MachOObjectFile::getLibraryShortNameByIndex(unsigned Index,<br>
- StringRef &Res) {<br>
+ StringRef &Res) const {<br>
if (Index >= Libraries.size())<br>
return object_error::parse_failed;<br>
<br>
@@ -1505,6 +1511,183 @@ dice_iterator MachOObjectFile::end_dices<br>
return dice_iterator(DiceRef(DRI, this));<br>
}<br>
<br>
+ExportEntry::ExportEntry(ArrayRef<uint8_t> T)<br>
+ : Trie(T), Malformed(false), Done(false) { }<br>
+<br>
+void ExportEntry::moveToFirst() {<br>
+ pushNode(0);<br>
+ pushDownUntilBottom();<br>
+}<br>
+<br>
+void ExportEntry::moveToEnd() {<br>
+ Stack.clear();<br>
+ Done = true;<br>
+}<br>
+<br>
+bool ExportEntry::operator==(const ExportEntry &Other) const {<br>
+ // Common case, one at end, other iterating from begin.<br>
+ if (Done || Other.Done)<br>
+ return (Done == Other.Done);<br>
+ // Not equal if different stack sizes.<br>
+ if (Stack.size() != Other.Stack.size())<br>
+ return false;<br>
+ // Not equal if different cumulative strings.<br>
+ if (!CumulativeString.str().equals(CumulativeString.str()))<br>
+ return false;<br>
+ // Equal if all nodes in both stacks match.<br>
+ for (unsigned i=0; i < Stack.size(); ++i) {<br>
+ if (Stack[i].Start != Other.Stack[i].Start)<br>
+ return false;<br>
+ }<br>
+ return true;<br>
+}<br>
+<br>
+uint64_t ExportEntry::readULEB128(const uint8_t *&p) {<br>
+ unsigned count;<br>
+ uint64_t result = decodeULEB128(p, &count);<br>
+ p += count;<br>
+ if (p > Trie.end()) {<br>
+ p = Trie.end();<br>
+ Malformed = true;<br>
+ }<br>
+ return result;<br>
+}<br>
+<br>
+StringRef ExportEntry::name() const {<br>
+ return CumulativeString.str();<br>
+}<br>
+<br>
+uint64_t ExportEntry::flags() const {<br>
+ return Stack.back().Flags;<br>
+}<br>
+<br>
+uint64_t ExportEntry::address() const {<br>
+ return Stack.back().Address;<br>
+}<br>
+<br>
+uint64_t ExportEntry::other() const {<br>
+ return Stack.back().Other;<br>
+}<br>
+<br>
+StringRef ExportEntry::otherName() const {<br>
+ const char* ImportName = Stack.back().ImportName;<br>
+ if (ImportName)<br>
+ return StringRef(ImportName);<br>
+ return StringRef();<br>
+}<br>
+<br>
+uint32_t ExportEntry::nodeOffset() const {<br>
+ return Stack.back().Start - Trie.begin();<br>
+}<br>
+<br>
+ExportEntry::NodeState::NodeState(const uint8_t *Ptr)<br>
+ : Start(Ptr), Current(Ptr), Flags(0), Address(0), Other(0),<br>
+ ImportName(nullptr), ChildCount(0), NextChildIndex(0),<br>
+ ParentStringLength(0), IsExportNode(false) {<br>
+}<br>
+<br>
+void ExportEntry::pushNode(uint64_t offset) {<br>
+ const uint8_t *Ptr = Trie.begin() + offset;<br>
+ NodeState State(Ptr);<br>
+ uint64_t ExportInfoSize = readULEB128(State.Current);<br>
+ State.IsExportNode = (ExportInfoSize != 0);<br>
+ const uint8_t* Children = State.Current + ExportInfoSize;<br>
+ if (State.IsExportNode) {<br>
+ State.Flags = readULEB128(State.Current);<br>
+ if (State.Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT) {<br>
+ State.Address = 0;<br>
+ State.Other = readULEB128(State.Current); // dylib ordinal<br>
+ State.ImportName = reinterpret_cast<const char*>(State.Current);<br>
+ } else {<br>
+ State.Address = readULEB128(State.Current);<br>
+ if (State.Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER)<br>
+ State.Other = readULEB128(State.Current);<br>
+ }<br>
+ }<br>
+ State.ChildCount = *Children;<br>
+ State.Current = Children + 1;<br>
+ State.NextChildIndex = 0;<br>
+ State.ParentStringLength = CumulativeString.size();<br>
+ Stack.push_back(State);<br>
+}<br>
+<br>
+void ExportEntry::pushDownUntilBottom() {<br>
+ while (Stack.back().NextChildIndex < Stack.back().ChildCount) {<br>
+ NodeState &Top = Stack.back();<br>
+ CumulativeString.resize(Top.ParentStringLength);<br>
+ for (;*Top.Current != 0; Top.Current++) {<br>
+ char c = *Top.Current;<br>
+ CumulativeString.push_back(c);<br>
+ }<br>
+ Top.Current += 1;<br>
+ uint64_t childNodeIndex = readULEB128(Top.Current);<br>
+ Top.NextChildIndex += 1;<br>
+ pushNode(childNodeIndex);<br>
+ }<br>
+ if (!Stack.back().IsExportNode) {<br>
+ Malformed = true;<br>
+ moveToEnd();<br>
+ }<br>
+}<br>
+<br>
+// We have a trie data structure and need a way to walk it that is compatible<br>
+// with the C++ iterator model. The solution is a non-recursive depth first<br>
+// traversal where the iterator contains a stack of parent nodes along with a<br>
+// string that is the accumulation of all edge strings along the parent chain<br>
+// to this point.<br>
+//<br>
+// There is one “export†node for each exported symbol. But because some<br>
+// symbols may be a prefix of another symbol (e.g. _dup and _dup2), an export<br>
+// node may have child nodes too.<br>
+//<br>
+// The algorithm for moveNext() is to keep moving down the leftmost unvisited<br>
+// child until hitting a node with no children (which is an export node or<br>
+// else the trie is malformed). On the way down, each node is pushed on the<br>
+// stack ivar. If there is no more ways down, it pops up one and tries to go<br>
+// down a sibling path until a childless node is reached.<br>
+void ExportEntry::moveNext() {<br>
+ if (Stack.empty() || !Stack.back().IsExportNode) {<br>
+ Malformed = true;<br>
+ moveToEnd();<br>
+ return;<br>
+ }<br>
+<br>
+ Stack.pop_back();<br>
+ while (!Stack.empty()) {<br>
+ NodeState &Top = Stack.back();<br>
+ if (Top.NextChildIndex < Top.ChildCount) {<br>
+ pushDownUntilBottom();<br>
+ // Now at the next export node.<br>
+ return;<br>
+ } else {<br>
+ if (Top.IsExportNode) {<br>
+ // This node has no children but is itself an export node.<br>
+ CumulativeString.resize(Top.ParentStringLength);<br>
+ return;<br>
+ }<br>
+ Stack.pop_back();<br>
+ }<br>
+ }<br>
+ Done = true;<br>
+}<br>
+<br>
+iterator_range<export_iterator><br>
+MachOObjectFile::exports(ArrayRef<uint8_t> Trie) {<br>
+ ExportEntry Start(Trie);<br>
+ Start.moveToFirst();<br>
+<br>
+ ExportEntry Finish(Trie);<br>
+ Finish.moveToEnd();<br>
+<br>
+ return iterator_range<export_iterator>(export_iterator(Start),<br>
+ export_iterator(Finish));<br>
+}<br>
+<br>
+iterator_range<export_iterator> MachOObjectFile::exports() const {<br>
+ return exports(getDyldInfoExportsTrie());<br>
+}<br>
+<br>
+<br>
StringRef<br>
MachOObjectFile::getSectionFinalSegmentName(DataRefImpl Sec) const {<br>
ArrayRef<char> Raw = getSectionRawFinalSegmentName(Sec);<br>
@@ -1748,6 +1931,62 @@ MachOObjectFile::getDataInCodeLoadComman<br>
return Cmd;<br>
}<br>
<br>
+ArrayRef<uint8_t> MachOObjectFile::getDyldInfoRebaseOpcodes() const {<br>
+ if (!DyldInfoLoadCmd)<br>
+ return ArrayRef<uint8_t>();<br>
+<br>
+ MachO::dyld_info_command DyldInfo<br>
+ = getStruct<MachO::dyld_info_command>(this, DyldInfoLoadCmd);<br>
+ const uint8_t *Ptr = reinterpret_cast<const uint8_t*>(<br>
+ getPtr(this, DyldInfo.rebase_off));<br>
+ return ArrayRef<uint8_t>(Ptr, DyldInfo.rebase_size);<br>
+}<br>
+<br>
+ArrayRef<uint8_t> MachOObjectFile::getDyldInfoBindOpcodes() const {<br>
+ if (!DyldInfoLoadCmd)<br>
+ return ArrayRef<uint8_t>();<br>
+<br>
+ MachO::dyld_info_command DyldInfo<br>
+ = getStruct<MachO::dyld_info_command>(this, DyldInfoLoadCmd);<br>
+ const uint8_t *Ptr = reinterpret_cast<const uint8_t*>(<br>
+ getPtr(this, DyldInfo.bind_off));<br>
+ return ArrayRef<uint8_t>(Ptr, DyldInfo.bind_size);<br>
+}<br>
+<br>
+ArrayRef<uint8_t> MachOObjectFile::getDyldInfoWeakBindOpcodes() const {<br>
+ if (!DyldInfoLoadCmd)<br>
+ return ArrayRef<uint8_t>();<br>
+<br>
+ MachO::dyld_info_command DyldInfo<br>
+ = getStruct<MachO::dyld_info_command>(this, DyldInfoLoadCmd);<br>
+ const uint8_t *Ptr = reinterpret_cast<const uint8_t*>(<br>
+ getPtr(this, DyldInfo.weak_bind_off));<br>
+ return ArrayRef<uint8_t>(Ptr, DyldInfo.weak_bind_size);<br>
+}<br>
+<br>
+ArrayRef<uint8_t> MachOObjectFile::getDyldInfoLazyBindOpcodes() const {<br>
+ if (!DyldInfoLoadCmd)<br>
+ return ArrayRef<uint8_t>();<br>
+<br>
+ MachO::dyld_info_command DyldInfo<br>
+ = getStruct<MachO::dyld_info_command>(this, DyldInfoLoadCmd);<br>
+ const uint8_t *Ptr = reinterpret_cast<const uint8_t*>(<br>
+ getPtr(this, DyldInfo.lazy_bind_off));<br>
+ return ArrayRef<uint8_t>(Ptr, DyldInfo.lazy_bind_size);<br>
+}<br>
+<br>
+ArrayRef<uint8_t> MachOObjectFile::getDyldInfoExportsTrie() const {<br>
+ if (!DyldInfoLoadCmd)<br>
+ return ArrayRef<uint8_t>();<br>
+<br>
+ MachO::dyld_info_command DyldInfo<br>
+ = getStruct<MachO::dyld_info_command>(this, DyldInfoLoadCmd);<br>
+ const uint8_t *Ptr = reinterpret_cast<const uint8_t*>(<br>
+ getPtr(this, DyldInfo.export_off));<br>
+ return ArrayRef<uint8_t>(Ptr, DyldInfo.export_size);<br>
+}<br>
+<br>
+<br>
StringRef MachOObjectFile::getStringTableData() const {<br>
MachO::symtab_command S = getSymtabLoadCommand();<br>
return getData().substr(S.stroff, S.strsize);<br>
<br>
Added: llvm/trunk/test/tools/llvm-objdump/Inputs/exports-trie.macho-x86_64<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objdump/Inputs/exports-trie.macho-x86_64?rev=216808&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objdump/Inputs/exports-trie.macho-x86_64?rev=216808&view=auto</a><br>
==============================================================================<br>
Binary file - no diff available.<br>
<br>
Propchange: llvm/trunk/test/tools/llvm-objdump/Inputs/exports-trie.macho-x86_64<br>
------------------------------------------------------------------------------<br>
svn:executable = *<br>
<br>
Propchange: llvm/trunk/test/tools/llvm-objdump/Inputs/exports-trie.macho-x86_64<br>
------------------------------------------------------------------------------<br>
svn:mime-type = application/octet-stream<br>
<br>
Added: llvm/trunk/test/tools/llvm-objdump/macho-exports-trie.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objdump/macho-exports-trie.test?rev=216808&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objdump/macho-exports-trie.test?rev=216808&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/tools/llvm-objdump/macho-exports-trie.test (added)<br>
+++ llvm/trunk/test/tools/llvm-objdump/macho-exports-trie.test Fri Aug 29 19:20:14 2014<br>
@@ -0,0 +1,11 @@<br>
+# RUN: llvm-objdump -macho -exports-trie -arch x86_64 \<br>
+# RUN: %p/Inputs/exports-trie.macho-x86_64 2>/dev/null | FileCheck %s<br>
+<br>
+<br>
+# CHECK:[re-export] _malloc (from libSystem)<br>
+# CHECK:[re-export] _myfree (_free from libSystem)<br>
+# CHECK:0x00000F70 _myWeakweak_def]<br>
+# CHECK:0x00001018 _myTLVper-thread]<br>
+# CHECK:0x12345678 _myAbsabsolute]<br>
+# CHECK:0x00000F60 _foo<br>
+<br>
<br>
Modified: llvm/trunk/tools/llvm-objdump/MachODump.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objdump/MachODump.cpp?rev=216808&r1=216807&r2=216808&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objdump/MachODump.cpp?rev=216808&r1=216807&r2=216808&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-objdump/MachODump.cpp (original)<br>
+++ llvm/trunk/tools/llvm-objdump/MachODump.cpp Fri Aug 29 19:20:14 2014<br>
@@ -1783,3 +1783,63 @@ void llvm::printMachOFileHeader(const ob<br>
getAndPrintMachHeader(file, ncmds, filetype, cputype, true);<br>
PrintLoadCommands(file, ncmds, filetype, cputype, true);<br>
}<br>
+<br>
+//===----------------------------------------------------------------------===//<br>
+// export trie dumping<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+void llvm::printMachOExportsTrie(const object::MachOObjectFile *Obj) {<br>
+ for (const llvm::object::ExportEntry &entry : Obj->exports()) {<br>
+ uint64_t Flags = entry.flags();<br>
+ bool ReExport = (Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);<br>
+ bool WeakDef = (Flags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);<br>
+ bool ThreadLocal = ((Flags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==<br>
+ MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL);<br>
+ bool Abs = ((Flags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==<br>
+ MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);<br>
+ bool Resolver = (Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);<br>
+ if (ReExport)<br>
+ outs() << "[re-export] ";<br>
+ else<br>
+ outs()<br>
+ << format("0x%08llX ", entry.address()); // FIXME:add in base address<br>
+ outs() << <a href="http://entry.name/" target="_blank">entry.name</a>();<br>
+ if (WeakDef || ThreadLocal || Resolver || Abs) {<br>
+ bool needComma = false;<br>
+ printf(" [");<br>
+ if (WeakDef) {<br>
+ outs() << "weak_def";<br>
+ needComma = true;<br>
+ }<br>
+ if (ThreadLocal) {<br>
+ if (needComma)<br>
+ outs() << ", ";<br>
+ outs() << "per-thread";<br>
+ needComma = true;<br>
+ }<br>
+ if (Abs) {<br>
+ if (needComma)<br>
+ outs() << ", ";<br>
+ outs() << "absolute";<br>
+ needComma = true;<br>
+ }<br>
+ if (Resolver) {<br>
+ if (needComma)<br>
+ outs() << ", ";<br>
+ outs() << format("resolver=0x%08llX", entry.other());<br>
+ needComma = true;<br>
+ }<br>
+ outs() << "]";<br>
+ }<br>
+ if (ReExport) {<br>
+ StringRef DylibName = "unknown";<br>
+ int ordinal = entry.other() - 1;<br>
+ Obj->getLibraryShortNameByIndex(ordinal, DylibName);<br>
+ if (entry.otherName().empty())<br>
+ outs() << " (from " << DylibName << ")";<br>
+ else<br>
+ outs() << " (" << entry.otherName() << " from " << DylibName << ")";<br>
+ }<br>
+ outs() << "\n";<br>
+ }<br>
+}<br>
<br>
Modified: llvm/trunk/tools/llvm-objdump/llvm-objdump.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objdump/llvm-objdump.cpp?rev=216808&r1=216807&r2=216808&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objdump/llvm-objdump.cpp?rev=216808&r1=216807&r2=216808&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-objdump/llvm-objdump.cpp (original)<br>
+++ llvm/trunk/tools/llvm-objdump/llvm-objdump.cpp Fri Aug 29 19:20:14 2014<br>
@@ -85,6 +85,9 @@ static cl::opt<bool><br>
SymbolTable("t", cl::desc("Display the symbol table"));<br>
<br>
static cl::opt<bool><br>
+ExportsTrie("exports-trie", cl::desc("Display mach-o exported symbols"));<br>
+<br>
+static cl::opt<bool><br>
MachOOpt("macho", cl::desc("Use MachO specific object file parser"));<br>
static cl::alias<br>
MachOm("m", cl::desc("Alias for --macho"), cl::aliasopt(MachOOpt));<br>
@@ -829,6 +832,17 @@ static void PrintUnwindInfo(const Object<br>
}<br>
}<br>
<br>
+static void printExportsTrie(const ObjectFile *o) {<br>
+ outs() << "Exports trie:\n";<br>
+ if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))<br>
+ printMachOExportsTrie(MachO);<br>
+ else {<br>
+ errs() << "This operation is only currently supported "<br>
+ "for Mach-O executable files.\n";<br>
+ return;<br>
+ }<br>
+}<br>
+<br>
static void printPrivateFileHeader(const ObjectFile *o) {<br>
if (o->isELF()) {<br>
printELFFileHeader(o);<br>
@@ -858,6 +872,8 @@ static void DumpObject(const ObjectFile<br>
PrintUnwindInfo(o);<br>
if (PrivateHeaders)<br>
printPrivateFileHeader(o);<br>
+ if (ExportsTrie)<br>
+ printExportsTrie(o);<br>
}<br>
<br>
/// @brief Dump each object file in \a a;<br>
@@ -939,7 +955,8 @@ int main(int argc, char **argv) {<br>
&& !SectionContents<br>
&& !SymbolTable<br>
&& !UnwindInfo<br>
- && !PrivateHeaders) {<br>
+ && !PrivateHeaders<br>
+ && !ExportsTrie) {<br>
cl::PrintHelpMessage();<br>
return 2;<br>
}<br>
<br>
Modified: llvm/trunk/tools/llvm-objdump/llvm-objdump.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objdump/llvm-objdump.h?rev=216808&r1=216807&r2=216808&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objdump/llvm-objdump.h?rev=216808&r1=216807&r2=216808&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-objdump/llvm-objdump.h (original)<br>
+++ llvm/trunk/tools/llvm-objdump/llvm-objdump.h Fri Aug 29 19:20:14 2014<br>
@@ -35,7 +35,7 @@ void DumpBytes(StringRef bytes);<br>
void DisassembleInputMachO(StringRef Filename);<br>
void printCOFFUnwindInfo(const object::COFFObjectFile* o);<br>
void printMachOUnwindInfo(const object::MachOObjectFile* o);<br>
-<br>
+void printMachOExportsTrie(const object::MachOObjectFile* o);<br>
void printELFFileHeader(const object::ObjectFile *o);<br>
void printCOFFFileHeader(const object::ObjectFile *o);<br>
void printMachOFileHeader(const object::ObjectFile *o);<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div>
</blockquote></div><br></body></html>