blob: 9a5e5453d5be1bbb2a902cd455a87ac7f86b7c62 [file] [log] [blame]
Frederic Riss231f7142014-12-12 17:31:24 +00001//===- tools/dsymutil/MachODebugMapParser.cpp - Parse STABS debug maps ----===//
2//
3// The LLVM Linker
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "DebugMap.h"
11#include "dsymutil.h"
12#include "llvm/Object/MachO.h"
13#include "llvm/Support/Path.h"
14#include "llvm/Support/raw_ostream.h"
15
16namespace {
17using namespace llvm;
18using namespace llvm::dsymutil;
19using namespace llvm::object;
20
21class MachODebugMapParser {
22public:
23 MachODebugMapParser(StringRef BinaryPath, StringRef PathPrefix = "")
24 : BinaryPath(BinaryPath), PathPrefix(PathPrefix) {}
25
26 /// \brief Parses and returns the DebugMap of the input binary.
27 /// \returns an error in case the provided BinaryPath doesn't exist
28 /// or isn't of a supported type.
29 ErrorOr<std::unique_ptr<DebugMap>> parse();
30
31private:
32 std::string BinaryPath;
33 std::string PathPrefix;
34
35 /// OwningBinary constructed from the BinaryPath.
36 object::OwningBinary<object::MachOObjectFile> MainOwningBinary;
37 /// Map of the binary symbol addresses.
38 StringMap<uint64_t> MainBinarySymbolAddresses;
39 /// The constructed DebugMap.
40 std::unique_ptr<DebugMap> Result;
41
42 /// Handle to the currently processed object file.
43 object::OwningBinary<object::MachOObjectFile> CurrentObjectFile;
44 /// Map of the currently processed object file symbol addresses.
45 StringMap<uint64_t> CurrentObjectAddresses;
46 /// Element of the debug map corresponfing to the current object file.
47 DebugMapObject *CurrentDebugMapObject;
48
49 void switchToNewDebugMapObject(StringRef Filename);
50 void resetParserState();
51 uint64_t getMainBinarySymbolAddress(StringRef Name);
52 void loadMainBinarySymbols();
53 void loadCurrentObjectFileSymbols();
54 void handleStabSymbolTableEntry(uint32_t StringIndex, uint8_t Type,
55 uint8_t SectionIndex, uint16_t Flags,
56 uint64_t Value);
57
58 template <typename STEType> void handleStabDebugMapEntry(const STEType &STE) {
59 handleStabSymbolTableEntry(STE.n_strx, STE.n_type, STE.n_sect, STE.n_desc,
60 STE.n_value);
61 }
62};
63
64static void Warning(const Twine &Msg) { errs() << "warning: " + Msg + "\n"; }
65}
66
67static ErrorOr<OwningBinary<MachOObjectFile>>
68createMachOBinary(StringRef File) {
69 auto MemBufOrErr = MemoryBuffer::getFile(File);
70 if (auto Error = MemBufOrErr.getError())
71 return Error;
72
73 MemoryBufferRef BufRef = (*MemBufOrErr)->getMemBufferRef();
74 auto MachOOrErr = ObjectFile::createMachOObjectFile(BufRef);
75 if (auto Error = MachOOrErr.getError())
76 return Error;
77
78 return OwningBinary<MachOObjectFile>(std::move(*MachOOrErr),
79 std::move(*MemBufOrErr));
80}
81
82/// Reset the parser state coresponding to the current object
83/// file. This is to be called after an object file is finished
84/// processing.
85void MachODebugMapParser::resetParserState() {
86 CurrentObjectFile = OwningBinary<object::MachOObjectFile>();
87 CurrentObjectAddresses.clear();
88 CurrentDebugMapObject = nullptr;
89}
90
91/// Create a new DebugMapObject. This function resets the state of the
92/// parser that was referring to the last object file and sets
93/// everything up to add symbols to the new one.
94void MachODebugMapParser::switchToNewDebugMapObject(StringRef Filename) {
95 resetParserState();
96
97 SmallString<80> Path(PathPrefix);
98 sys::path::append(Path, Filename);
99
100 auto MachOOrError = createMachOBinary(Path);
101 if (auto Error = MachOOrError.getError()) {
102 Warning(Twine("cannot open debug object \"") + Path.str() + "\": " +
103 Error.message() + "\n");
104 return;
105 }
106
107 CurrentObjectFile = std::move(*MachOOrError);
108 loadCurrentObjectFileSymbols();
109 CurrentDebugMapObject = &Result->addDebugMapObject(Path);
110}
111
112/// This main parsing routine tries to open the main binary and if
113/// successful iterates over the STAB entries. The real parsing is
114/// done in handleStabSymbolTableEntry.
115ErrorOr<std::unique_ptr<DebugMap>> MachODebugMapParser::parse() {
116 auto MainBinaryOrError = createMachOBinary(BinaryPath);
117 if (auto Error = MainBinaryOrError.getError())
118 return Error;
119
120 MainOwningBinary = std::move(*MainBinaryOrError);
121 loadMainBinarySymbols();
122 Result = make_unique<DebugMap>();
123 const auto &MainBinary = *MainOwningBinary.getBinary();
124 for (const SymbolRef &Symbol : MainBinary.symbols()) {
125 const DataRefImpl &DRI = Symbol.getRawDataRefImpl();
126 if (MainBinary.is64Bit())
127 handleStabDebugMapEntry(MainBinary.getSymbol64TableEntry(DRI));
128 else
129 handleStabDebugMapEntry(MainBinary.getSymbolTableEntry(DRI));
130 }
131
132 resetParserState();
133 return std::move(Result);
134}
135
136/// Interpret the STAB entries to fill the DebugMap.
137void MachODebugMapParser::handleStabSymbolTableEntry(uint32_t StringIndex,
138 uint8_t Type,
139 uint8_t SectionIndex,
140 uint16_t Flags,
141 uint64_t Value) {
142 if (!(Type & MachO::N_STAB))
143 return;
144
145 const MachOObjectFile &MachOBinary = *MainOwningBinary.getBinary();
146 const char *Name = &MachOBinary.getStringTableData().data()[StringIndex];
147
148 // An N_OSO entry represents the start of a new object file description.
149 if (Type == MachO::N_OSO)
150 return switchToNewDebugMapObject(Name);
151
152 // If the last N_OSO object file wasn't found,
153 // CurrentDebugMapObject will be null. Do not update anything
154 // until we find the next valid N_OSO entry.
155 if (!CurrentDebugMapObject)
156 return;
157
158 switch (Type) {
159 case MachO::N_GSYM:
160 // This is a global variable. We need to query the main binary
161 // symbol table to find its address as it might not be in the
162 // debug map (for common symbols).
163 Value = getMainBinarySymbolAddress(Name);
164 if (Value == UnknownAddressOrSize)
165 return;
166 break;
167 case MachO::N_FUN:
168 // Functions are scopes in STABS. They have an end marker that we
169 // need to ignore.
170 if (Name[0] == '\0')
171 return;
172 break;
173 case MachO::N_STSYM:
174 break;
175 default:
176 return;
177 }
178
179 auto ObjectSymIt = CurrentObjectAddresses.find(Name);
180 if (ObjectSymIt == CurrentObjectAddresses.end())
181 return Warning("could not find object file symbol for symbol " +
182 Twine(Name));
183 if (!CurrentDebugMapObject->addSymbol(Name, ObjectSymIt->getValue(), Value))
184 return Warning(Twine("failed to insert symbol '") + Name +
185 "' in the debug map.");
186}
187
188/// Load the current object file symbols into CurrentObjectAddresses.
189void MachODebugMapParser::loadCurrentObjectFileSymbols() {
190 CurrentObjectAddresses.clear();
191 const auto &Binary = *CurrentObjectFile.getBinary();
192
193 for (auto Sym : Binary.symbols()) {
194 StringRef Name;
195 uint64_t Addr;
196 if (Sym.getAddress(Addr) || Addr == UnknownAddressOrSize ||
197 Sym.getName(Name))
198 continue;
199 CurrentObjectAddresses[Name] = Addr;
200 }
201}
202
203/// Lookup a symbol address in the main binary symbol table. The
204/// parser only needs to query common symbols, thus not every symbol's
205/// address is available through this function.
206uint64_t MachODebugMapParser::getMainBinarySymbolAddress(StringRef Name) {
207 auto Sym = MainBinarySymbolAddresses.find(Name);
208 if (Sym == MainBinarySymbolAddresses.end())
209 return UnknownAddressOrSize;
210 return Sym->second;
211}
212
213/// Load the interesting main binary symbols' addresses into
214/// MainBinarySymbolAddresses.
215void MachODebugMapParser::loadMainBinarySymbols() {
216 const MachOObjectFile &Binary = *MainOwningBinary.getBinary();
217 section_iterator Section = Binary.section_end();
218 for (const auto &Sym : Binary.symbols()) {
219 SymbolRef::Type Type;
220 // Skip undefined and STAB entries.
221 if (Sym.getType(Type) || (Type & SymbolRef::ST_Debug) ||
222 (Type & SymbolRef::ST_Unknown))
223 continue;
224 StringRef Name;
225 uint64_t Addr;
226 // The only symbols of interest are the global variables. These
227 // are the only ones that need to be queried because the address
228 // of common data won't be described in the debug map. All other
229 // addresses should be fetched for the debug map.
230 if (Sym.getAddress(Addr) || Addr == UnknownAddressOrSize ||
231 !(Sym.getFlags() & SymbolRef::SF_Global) || Sym.getSection(Section) ||
232 Section->isText() || Sym.getName(Name) || Name.size() == 0 ||
233 Name[0] == '\0')
234 continue;
235 MainBinarySymbolAddresses[Name] = Addr;
236 }
237}
238
239namespace llvm {
240namespace dsymutil {
241llvm::ErrorOr<std::unique_ptr<DebugMap>> parseDebugMap(StringRef InputFile,
242 StringRef PrependPath) {
243 MachODebugMapParser Parser(InputFile, PrependPath);
244 return Parser.parse();
245}
246}
247}