blob: aa034cb683c532f014f40b741a095e12eec9a81e [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
Frederic Riss43988502015-01-05 21:29:28 +000010#include "BinaryHolder.h"
Frederic Riss231f7142014-12-12 17:31:24 +000011#include "DebugMap.h"
12#include "dsymutil.h"
13#include "llvm/Object/MachO.h"
14#include "llvm/Support/Path.h"
15#include "llvm/Support/raw_ostream.h"
16
17namespace {
18using namespace llvm;
19using namespace llvm::dsymutil;
20using namespace llvm::object;
21
22class MachODebugMapParser {
23public:
Frederic Riss43988502015-01-05 21:29:28 +000024 MachODebugMapParser(StringRef BinaryPath, StringRef PathPrefix = "",
25 bool Verbose = false)
Alexey Samsonovd927bd82014-12-18 00:45:32 +000026 : BinaryPath(BinaryPath), PathPrefix(PathPrefix),
Alexey Samsonovdb50b3d2015-01-07 21:13:30 +000027 MainBinaryHolder(Verbose), CurrentObjectHolder(Verbose),
28 CurrentDebugMapObject(nullptr) {}
Frederic Riss231f7142014-12-12 17:31:24 +000029
Frederic Riss4dd3e0c2015-08-05 18:27:44 +000030 /// \brief Parses and returns the DebugMaps of the input binary.
31 /// The binary contains multiple maps in case it is a universal
32 /// binary.
Frederic Riss231f7142014-12-12 17:31:24 +000033 /// \returns an error in case the provided BinaryPath doesn't exist
34 /// or isn't of a supported type.
Frederic Riss4dd3e0c2015-08-05 18:27:44 +000035 ErrorOr<std::vector<std::unique_ptr<DebugMap>>> parse();
Frederic Riss231f7142014-12-12 17:31:24 +000036
37private:
38 std::string BinaryPath;
39 std::string PathPrefix;
40
Frederic Riss43988502015-01-05 21:29:28 +000041 /// Owns the MemoryBuffer for the main binary.
42 BinaryHolder MainBinaryHolder;
Frederic Riss231f7142014-12-12 17:31:24 +000043 /// Map of the binary symbol addresses.
44 StringMap<uint64_t> MainBinarySymbolAddresses;
Frederic Riss896b2c52014-12-16 20:21:34 +000045 StringRef MainBinaryStrings;
Frederic Riss231f7142014-12-12 17:31:24 +000046 /// The constructed DebugMap.
47 std::unique_ptr<DebugMap> Result;
48
Frederic Riss43988502015-01-05 21:29:28 +000049 /// Owns the MemoryBuffer for the currently handled object file.
50 BinaryHolder CurrentObjectHolder;
Frederic Riss231f7142014-12-12 17:31:24 +000051 /// Map of the currently processed object file symbol addresses.
52 StringMap<uint64_t> CurrentObjectAddresses;
53 /// Element of the debug map corresponfing to the current object file.
54 DebugMapObject *CurrentDebugMapObject;
55
Frederic Riss912d0f12015-03-15 01:29:30 +000056 /// Holds function info while function scope processing.
57 const char *CurrentFunctionName;
58 uint64_t CurrentFunctionAddress;
59
Frederic Riss4dd3e0c2015-08-05 18:27:44 +000060 std::unique_ptr<DebugMap> parseOneBinary(const MachOObjectFile &MainBinary,
61 StringRef BinaryPath);
62
Frederic Riss9ccfddc2015-07-22 23:24:00 +000063 void switchToNewDebugMapObject(StringRef Filename, sys::TimeValue Timestamp);
Frederic Riss231f7142014-12-12 17:31:24 +000064 void resetParserState();
65 uint64_t getMainBinarySymbolAddress(StringRef Name);
Frederic Risseb85c8f2015-07-24 06:41:11 +000066 void loadMainBinarySymbols(const MachOObjectFile &MainBinary);
67 void loadCurrentObjectFileSymbols(const object::MachOObjectFile &Obj);
Frederic Riss231f7142014-12-12 17:31:24 +000068 void handleStabSymbolTableEntry(uint32_t StringIndex, uint8_t Type,
69 uint8_t SectionIndex, uint16_t Flags,
70 uint64_t Value);
71
72 template <typename STEType> void handleStabDebugMapEntry(const STEType &STE) {
73 handleStabSymbolTableEntry(STE.n_strx, STE.n_type, STE.n_sect, STE.n_desc,
74 STE.n_value);
75 }
76};
77
78static void Warning(const Twine &Msg) { errs() << "warning: " + Msg + "\n"; }
79}
80
Frederic Riss231f7142014-12-12 17:31:24 +000081/// Reset the parser state coresponding to the current object
82/// file. This is to be called after an object file is finished
83/// processing.
84void MachODebugMapParser::resetParserState() {
Frederic Riss231f7142014-12-12 17:31:24 +000085 CurrentObjectAddresses.clear();
86 CurrentDebugMapObject = nullptr;
87}
88
89/// Create a new DebugMapObject. This function resets the state of the
90/// parser that was referring to the last object file and sets
91/// everything up to add symbols to the new one.
Frederic Riss9ccfddc2015-07-22 23:24:00 +000092void MachODebugMapParser::switchToNewDebugMapObject(StringRef Filename,
93 sys::TimeValue Timestamp) {
Frederic Riss231f7142014-12-12 17:31:24 +000094 resetParserState();
95
96 SmallString<80> Path(PathPrefix);
97 sys::path::append(Path, Filename);
98
Frederic Riss9ccfddc2015-07-22 23:24:00 +000099 auto MachOOrError =
Frederic Risseb85c8f2015-07-24 06:41:11 +0000100 CurrentObjectHolder.GetFilesAs<MachOObjectFile>(Path, Timestamp);
Frederic Riss231f7142014-12-12 17:31:24 +0000101 if (auto Error = MachOOrError.getError()) {
102 Warning(Twine("cannot open debug object \"") + Path.str() + "\": " +
103 Error.message() + "\n");
104 return;
105 }
106
Frederic Risseb85c8f2015-07-24 06:41:11 +0000107 auto ErrOrAchObj =
108 CurrentObjectHolder.GetAs<MachOObjectFile>(Result->getTriple());
109 if (auto Err = ErrOrAchObj.getError()) {
110 return Warning(Twine("cannot open debug object \"") + Path.str() + "\": " +
111 Err.message() + "\n");
112 }
113
Frederic Riss9ccfddc2015-07-22 23:24:00 +0000114 CurrentDebugMapObject = &Result->addDebugMapObject(Path, Timestamp);
Frederic Risseb85c8f2015-07-24 06:41:11 +0000115 loadCurrentObjectFileSymbols(*ErrOrAchObj);
Frederic Riss231f7142014-12-12 17:31:24 +0000116}
117
Frederic Riss4dd3e0c2015-08-05 18:27:44 +0000118std::unique_ptr<DebugMap>
119MachODebugMapParser::parseOneBinary(const MachOObjectFile &MainBinary,
120 StringRef BinaryPath) {
Frederic Risseb85c8f2015-07-24 06:41:11 +0000121 loadMainBinarySymbols(MainBinary);
Frederic Riss65f0abf2015-07-24 06:41:04 +0000122 Result = make_unique<DebugMap>(BinaryHolder::getTriple(MainBinary));
Frederic Riss896b2c52014-12-16 20:21:34 +0000123 MainBinaryStrings = MainBinary.getStringTableData();
Frederic Riss231f7142014-12-12 17:31:24 +0000124 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
Frederic Riss4dd3e0c2015-08-05 18:27:44 +0000136/// This main parsing routine tries to open the main binary and if
137/// successful iterates over the STAB entries. The real parsing is
138/// done in handleStabSymbolTableEntry.
139ErrorOr<std::vector<std::unique_ptr<DebugMap>>> MachODebugMapParser::parse() {
140 auto MainBinOrError =
141 MainBinaryHolder.GetFilesAs<MachOObjectFile>(BinaryPath);
142 if (auto Error = MainBinOrError.getError())
143 return Error;
144
145 std::vector<std::unique_ptr<DebugMap>> Results;
146 for (const auto *Binary : *MainBinOrError)
147 Results.push_back(parseOneBinary(*Binary, BinaryPath));
148
149 return std::move(Results);
150}
151
Frederic Riss231f7142014-12-12 17:31:24 +0000152/// Interpret the STAB entries to fill the DebugMap.
153void MachODebugMapParser::handleStabSymbolTableEntry(uint32_t StringIndex,
154 uint8_t Type,
155 uint8_t SectionIndex,
156 uint16_t Flags,
157 uint64_t Value) {
158 if (!(Type & MachO::N_STAB))
159 return;
160
Frederic Riss896b2c52014-12-16 20:21:34 +0000161 const char *Name = &MainBinaryStrings.data()[StringIndex];
Frederic Riss231f7142014-12-12 17:31:24 +0000162
163 // An N_OSO entry represents the start of a new object file description.
Frederic Riss9ccfddc2015-07-22 23:24:00 +0000164 if (Type == MachO::N_OSO) {
165 sys::TimeValue Timestamp;
166 Timestamp.fromEpochTime(Value);
167 return switchToNewDebugMapObject(Name, Timestamp);
168 }
Frederic Riss231f7142014-12-12 17:31:24 +0000169
170 // If the last N_OSO object file wasn't found,
171 // CurrentDebugMapObject will be null. Do not update anything
172 // until we find the next valid N_OSO entry.
173 if (!CurrentDebugMapObject)
174 return;
175
Frederic Riss912d0f12015-03-15 01:29:30 +0000176 uint32_t Size = 0;
Frederic Riss231f7142014-12-12 17:31:24 +0000177 switch (Type) {
178 case MachO::N_GSYM:
179 // This is a global variable. We need to query the main binary
180 // symbol table to find its address as it might not be in the
181 // debug map (for common symbols).
182 Value = getMainBinarySymbolAddress(Name);
Frederic Riss231f7142014-12-12 17:31:24 +0000183 break;
184 case MachO::N_FUN:
Frederic Riss912d0f12015-03-15 01:29:30 +0000185 // Functions are scopes in STABS. They have an end marker that
186 // contains the function size.
187 if (Name[0] == '\0') {
188 Size = Value;
189 Value = CurrentFunctionAddress;
190 Name = CurrentFunctionName;
191 break;
192 } else {
193 CurrentFunctionName = Name;
194 CurrentFunctionAddress = Value;
Frederic Riss231f7142014-12-12 17:31:24 +0000195 return;
Frederic Riss912d0f12015-03-15 01:29:30 +0000196 }
Frederic Riss231f7142014-12-12 17:31:24 +0000197 case MachO::N_STSYM:
198 break;
199 default:
200 return;
201 }
202
203 auto ObjectSymIt = CurrentObjectAddresses.find(Name);
204 if (ObjectSymIt == CurrentObjectAddresses.end())
205 return Warning("could not find object file symbol for symbol " +
206 Twine(Name));
Frederic Riss912d0f12015-03-15 01:29:30 +0000207 if (!CurrentDebugMapObject->addSymbol(Name, ObjectSymIt->getValue(), Value,
208 Size))
Frederic Riss231f7142014-12-12 17:31:24 +0000209 return Warning(Twine("failed to insert symbol '") + Name +
210 "' in the debug map.");
211}
212
213/// Load the current object file symbols into CurrentObjectAddresses.
Frederic Risseb85c8f2015-07-24 06:41:11 +0000214void MachODebugMapParser::loadCurrentObjectFileSymbols(
215 const object::MachOObjectFile &Obj) {
Frederic Riss231f7142014-12-12 17:31:24 +0000216 CurrentObjectAddresses.clear();
Frederic Riss231f7142014-12-12 17:31:24 +0000217
Frederic Risseb85c8f2015-07-24 06:41:11 +0000218 for (auto Sym : Obj.symbols()) {
Rafael Espindolabe8b0ea2015-07-07 17:12:59 +0000219 uint64_t Addr = Sym.getValue();
Rafael Espindola5d0c2ff2015-07-02 20:55:21 +0000220 ErrorOr<StringRef> Name = Sym.getName();
221 if (!Name)
222 continue;
223 CurrentObjectAddresses[*Name] = Addr;
Frederic Riss231f7142014-12-12 17:31:24 +0000224 }
225}
226
227/// Lookup a symbol address in the main binary symbol table. The
228/// parser only needs to query common symbols, thus not every symbol's
229/// address is available through this function.
230uint64_t MachODebugMapParser::getMainBinarySymbolAddress(StringRef Name) {
231 auto Sym = MainBinarySymbolAddresses.find(Name);
232 if (Sym == MainBinarySymbolAddresses.end())
Rafael Espindolabe8b0ea2015-07-07 17:12:59 +0000233 return 0;
Frederic Riss231f7142014-12-12 17:31:24 +0000234 return Sym->second;
235}
236
237/// Load the interesting main binary symbols' addresses into
238/// MainBinarySymbolAddresses.
Frederic Risseb85c8f2015-07-24 06:41:11 +0000239void MachODebugMapParser::loadMainBinarySymbols(
240 const MachOObjectFile &MainBinary) {
Frederic Riss43988502015-01-05 21:29:28 +0000241 section_iterator Section = MainBinary.section_end();
Frederic Risseb85c8f2015-07-24 06:41:11 +0000242 MainBinarySymbolAddresses.clear();
Frederic Riss43988502015-01-05 21:29:28 +0000243 for (const auto &Sym : MainBinary.symbols()) {
Rafael Espindola2fa80cc2015-06-26 12:18:49 +0000244 SymbolRef::Type Type = Sym.getType();
Frederic Riss231f7142014-12-12 17:31:24 +0000245 // Skip undefined and STAB entries.
Rafael Espindola2fa80cc2015-06-26 12:18:49 +0000246 if ((Type & SymbolRef::ST_Debug) || (Type & SymbolRef::ST_Unknown))
Frederic Riss231f7142014-12-12 17:31:24 +0000247 continue;
Frederic Riss231f7142014-12-12 17:31:24 +0000248 // The only symbols of interest are the global variables. These
249 // are the only ones that need to be queried because the address
250 // of common data won't be described in the debug map. All other
251 // addresses should be fetched for the debug map.
Rafael Espindolabe8b0ea2015-07-07 17:12:59 +0000252 if (!(Sym.getFlags() & SymbolRef::SF_Global) || Sym.getSection(Section) ||
253 Section == MainBinary.section_end() || Section->isText())
Rafael Espindola5d0c2ff2015-07-02 20:55:21 +0000254 continue;
Rafael Espindolabe8b0ea2015-07-07 17:12:59 +0000255 uint64_t Addr = Sym.getValue();
Rafael Espindola5d0c2ff2015-07-02 20:55:21 +0000256 ErrorOr<StringRef> NameOrErr = Sym.getName();
257 if (!NameOrErr)
258 continue;
259 StringRef Name = *NameOrErr;
260 if (Name.size() == 0 || Name[0] == '\0')
Frederic Riss231f7142014-12-12 17:31:24 +0000261 continue;
262 MainBinarySymbolAddresses[Name] = Addr;
263 }
264}
265
266namespace llvm {
267namespace dsymutil {
Frederic Riss4dd3e0c2015-08-05 18:27:44 +0000268llvm::ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
269parseDebugMap(StringRef InputFile, StringRef PrependPath, bool Verbose,
270 bool InputIsYAML) {
Frederic Riss90e0bd92015-06-03 20:29:24 +0000271 if (!InputIsYAML) {
272 MachODebugMapParser Parser(InputFile, PrependPath, Verbose);
273 return Parser.parse();
274 } else {
Frederic Riss4d0ba662015-06-05 20:27:04 +0000275 return DebugMap::parseYAMLDebugMap(InputFile, PrependPath, Verbose);
Frederic Riss90e0bd92015-06-03 20:29:24 +0000276 }
Frederic Riss231f7142014-12-12 17:31:24 +0000277}
278}
279}