Mercurial > hg > CbC > CbC_llvm
comparison tools/dsymutil/DwarfStreamer.cpp @ 147:c2174574ed3a
LLVM 10
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Wed, 14 Aug 2019 16:55:33 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
134:3a76565eade5 | 147:c2174574ed3a |
---|---|
1 //===- tools/dsymutil/DwarfStreamer.cpp - Dwarf Streamer ------------------===// | |
2 // | |
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
4 // See https://llvm.org/LICENSE.txt for license information. | |
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
6 // | |
7 //===----------------------------------------------------------------------===// | |
8 | |
9 #include "DwarfStreamer.h" | |
10 #include "CompileUnit.h" | |
11 #include "LinkUtils.h" | |
12 #include "MachOUtils.h" | |
13 #include "llvm/ADT/Triple.h" | |
14 #include "llvm/DebugInfo/DWARF/DWARFContext.h" | |
15 #include "llvm/MC/MCTargetOptions.h" | |
16 #include "llvm/MC/MCTargetOptionsCommandFlags.inc" | |
17 #include "llvm/Support/LEB128.h" | |
18 #include "llvm/Support/TargetRegistry.h" | |
19 #include "llvm/Target/TargetMachine.h" | |
20 #include "llvm/Target/TargetOptions.h" | |
21 | |
22 namespace llvm { | |
23 namespace dsymutil { | |
24 | |
25 /// Retrieve the section named \a SecName in \a Obj. | |
26 /// | |
27 /// To accommodate for platform discrepancies, the name passed should be | |
28 /// (for example) 'debug_info' to match either '__debug_info' or '.debug_info'. | |
29 /// This function will strip the initial platform-specific characters. | |
30 static Optional<object::SectionRef> | |
31 getSectionByName(const object::ObjectFile &Obj, StringRef SecName) { | |
32 for (const object::SectionRef &Section : Obj.sections()) { | |
33 StringRef SectionName; | |
34 Section.getName(SectionName); | |
35 SectionName = SectionName.substr(SectionName.find_first_not_of("._")); | |
36 if (SectionName != SecName) | |
37 continue; | |
38 return Section; | |
39 } | |
40 return None; | |
41 } | |
42 | |
43 bool DwarfStreamer::init(Triple TheTriple) { | |
44 std::string ErrorStr; | |
45 std::string TripleName; | |
46 StringRef Context = "dwarf streamer init"; | |
47 | |
48 // Get the target. | |
49 const Target *TheTarget = | |
50 TargetRegistry::lookupTarget(TripleName, TheTriple, ErrorStr); | |
51 if (!TheTarget) | |
52 return error(ErrorStr, Context); | |
53 TripleName = TheTriple.getTriple(); | |
54 | |
55 // Create all the MC Objects. | |
56 MRI.reset(TheTarget->createMCRegInfo(TripleName)); | |
57 if (!MRI) | |
58 return error(Twine("no register info for target ") + TripleName, Context); | |
59 | |
60 MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName)); | |
61 if (!MAI) | |
62 return error("no asm info for target " + TripleName, Context); | |
63 | |
64 MOFI.reset(new MCObjectFileInfo); | |
65 MC.reset(new MCContext(MAI.get(), MRI.get(), MOFI.get())); | |
66 MOFI->InitMCObjectFileInfo(TheTriple, /*PIC*/ false, *MC); | |
67 | |
68 MSTI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", "")); | |
69 if (!MSTI) | |
70 return error("no subtarget info for target " + TripleName, Context); | |
71 | |
72 MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags(); | |
73 MAB = TheTarget->createMCAsmBackend(*MSTI, *MRI, MCOptions); | |
74 if (!MAB) | |
75 return error("no asm backend for target " + TripleName, Context); | |
76 | |
77 MII.reset(TheTarget->createMCInstrInfo()); | |
78 if (!MII) | |
79 return error("no instr info info for target " + TripleName, Context); | |
80 | |
81 MCE = TheTarget->createMCCodeEmitter(*MII, *MRI, *MC); | |
82 if (!MCE) | |
83 return error("no code emitter for target " + TripleName, Context); | |
84 | |
85 switch (Options.FileType) { | |
86 case OutputFileType::Assembly: { | |
87 MIP = TheTarget->createMCInstPrinter(TheTriple, MAI->getAssemblerDialect(), | |
88 *MAI, *MII, *MRI); | |
89 MS = TheTarget->createAsmStreamer( | |
90 *MC, llvm::make_unique<formatted_raw_ostream>(OutFile), true, true, MIP, | |
91 std::unique_ptr<MCCodeEmitter>(MCE), std::unique_ptr<MCAsmBackend>(MAB), | |
92 true); | |
93 break; | |
94 } | |
95 case OutputFileType::Object: { | |
96 MS = TheTarget->createMCObjectStreamer( | |
97 TheTriple, *MC, std::unique_ptr<MCAsmBackend>(MAB), | |
98 MAB->createObjectWriter(OutFile), std::unique_ptr<MCCodeEmitter>(MCE), | |
99 *MSTI, MCOptions.MCRelaxAll, MCOptions.MCIncrementalLinkerCompatible, | |
100 /*DWARFMustBeAtTheEnd*/ false); | |
101 break; | |
102 } | |
103 } | |
104 | |
105 if (!MS) | |
106 return error("no object streamer for target " + TripleName, Context); | |
107 | |
108 // Finally create the AsmPrinter we'll use to emit the DIEs. | |
109 TM.reset(TheTarget->createTargetMachine(TripleName, "", "", TargetOptions(), | |
110 None)); | |
111 if (!TM) | |
112 return error("no target machine for target " + TripleName, Context); | |
113 | |
114 Asm.reset(TheTarget->createAsmPrinter(*TM, std::unique_ptr<MCStreamer>(MS))); | |
115 if (!Asm) | |
116 return error("no asm printer for target " + TripleName, Context); | |
117 | |
118 RangesSectionSize = 0; | |
119 LocSectionSize = 0; | |
120 LineSectionSize = 0; | |
121 FrameSectionSize = 0; | |
122 | |
123 return true; | |
124 } | |
125 | |
126 bool DwarfStreamer::finish(const DebugMap &DM, SymbolMapTranslator &T) { | |
127 bool Result = true; | |
128 if (DM.getTriple().isOSDarwin() && !DM.getBinaryPath().empty() && | |
129 Options.FileType == OutputFileType::Object) | |
130 Result = MachOUtils::generateDsymCompanion(DM, T, *MS, OutFile); | |
131 else | |
132 MS->Finish(); | |
133 return Result; | |
134 } | |
135 | |
136 void DwarfStreamer::switchToDebugInfoSection(unsigned DwarfVersion) { | |
137 MS->SwitchSection(MOFI->getDwarfInfoSection()); | |
138 MC->setDwarfVersion(DwarfVersion); | |
139 } | |
140 | |
141 /// Emit the compilation unit header for \p Unit in the debug_info section. | |
142 /// | |
143 /// A Dwarf section header is encoded as: | |
144 /// uint32_t Unit length (omitting this field) | |
145 /// uint16_t Version | |
146 /// uint32_t Abbreviation table offset | |
147 /// uint8_t Address size | |
148 /// | |
149 /// Leading to a total of 11 bytes. | |
150 void DwarfStreamer::emitCompileUnitHeader(CompileUnit &Unit) { | |
151 unsigned Version = Unit.getOrigUnit().getVersion(); | |
152 switchToDebugInfoSection(Version); | |
153 | |
154 /// The start of the unit within its section. | |
155 Unit.setLabelBegin(Asm->createTempSymbol("cu_begin")); | |
156 Asm->OutStreamer->EmitLabel(Unit.getLabelBegin()); | |
157 | |
158 // Emit size of content not including length itself. The size has already | |
159 // been computed in CompileUnit::computeOffsets(). Subtract 4 to that size to | |
160 // account for the length field. | |
161 Asm->emitInt32(Unit.getNextUnitOffset() - Unit.getStartOffset() - 4); | |
162 Asm->emitInt16(Version); | |
163 | |
164 // We share one abbreviations table across all units so it's always at the | |
165 // start of the section. | |
166 Asm->emitInt32(0); | |
167 Asm->emitInt8(Unit.getOrigUnit().getAddressByteSize()); | |
168 | |
169 // Remember this CU. | |
170 EmittedUnits.push_back({Unit.getUniqueID(), Unit.getLabelBegin()}); | |
171 } | |
172 | |
173 /// Emit the \p Abbrevs array as the shared abbreviation table | |
174 /// for the linked Dwarf file. | |
175 void DwarfStreamer::emitAbbrevs( | |
176 const std::vector<std::unique_ptr<DIEAbbrev>> &Abbrevs, | |
177 unsigned DwarfVersion) { | |
178 MS->SwitchSection(MOFI->getDwarfAbbrevSection()); | |
179 MC->setDwarfVersion(DwarfVersion); | |
180 Asm->emitDwarfAbbrevs(Abbrevs); | |
181 } | |
182 | |
183 /// Recursively emit the DIE tree rooted at \p Die. | |
184 void DwarfStreamer::emitDIE(DIE &Die) { | |
185 MS->SwitchSection(MOFI->getDwarfInfoSection()); | |
186 Asm->emitDwarfDIE(Die); | |
187 } | |
188 | |
189 /// Emit the debug_str section stored in \p Pool. | |
190 void DwarfStreamer::emitStrings(const NonRelocatableStringpool &Pool) { | |
191 Asm->OutStreamer->SwitchSection(MOFI->getDwarfStrSection()); | |
192 std::vector<DwarfStringPoolEntryRef> Entries = Pool.getEntriesForEmission(); | |
193 for (auto Entry : Entries) { | |
194 // Emit the string itself. | |
195 Asm->OutStreamer->EmitBytes(Entry.getString()); | |
196 // Emit a null terminator. | |
197 Asm->emitInt8(0); | |
198 } | |
199 } | |
200 | |
201 void DwarfStreamer::emitDebugNames( | |
202 AccelTable<DWARF5AccelTableStaticData> &Table) { | |
203 if (EmittedUnits.empty()) | |
204 return; | |
205 | |
206 // Build up data structures needed to emit this section. | |
207 std::vector<MCSymbol *> CompUnits; | |
208 DenseMap<unsigned, size_t> UniqueIdToCuMap; | |
209 unsigned Id = 0; | |
210 for (auto &CU : EmittedUnits) { | |
211 CompUnits.push_back(CU.LabelBegin); | |
212 // We might be omitting CUs, so we need to remap them. | |
213 UniqueIdToCuMap[CU.ID] = Id++; | |
214 } | |
215 | |
216 Asm->OutStreamer->SwitchSection(MOFI->getDwarfDebugNamesSection()); | |
217 emitDWARF5AccelTable( | |
218 Asm.get(), Table, CompUnits, | |
219 [&UniqueIdToCuMap](const DWARF5AccelTableStaticData &Entry) { | |
220 return UniqueIdToCuMap[Entry.getCUIndex()]; | |
221 }); | |
222 } | |
223 | |
224 void DwarfStreamer::emitAppleNamespaces( | |
225 AccelTable<AppleAccelTableStaticOffsetData> &Table) { | |
226 Asm->OutStreamer->SwitchSection(MOFI->getDwarfAccelNamespaceSection()); | |
227 auto *SectionBegin = Asm->createTempSymbol("namespac_begin"); | |
228 Asm->OutStreamer->EmitLabel(SectionBegin); | |
229 emitAppleAccelTable(Asm.get(), Table, "namespac", SectionBegin); | |
230 } | |
231 | |
232 void DwarfStreamer::emitAppleNames( | |
233 AccelTable<AppleAccelTableStaticOffsetData> &Table) { | |
234 Asm->OutStreamer->SwitchSection(MOFI->getDwarfAccelNamesSection()); | |
235 auto *SectionBegin = Asm->createTempSymbol("names_begin"); | |
236 Asm->OutStreamer->EmitLabel(SectionBegin); | |
237 emitAppleAccelTable(Asm.get(), Table, "names", SectionBegin); | |
238 } | |
239 | |
240 void DwarfStreamer::emitAppleObjc( | |
241 AccelTable<AppleAccelTableStaticOffsetData> &Table) { | |
242 Asm->OutStreamer->SwitchSection(MOFI->getDwarfAccelObjCSection()); | |
243 auto *SectionBegin = Asm->createTempSymbol("objc_begin"); | |
244 Asm->OutStreamer->EmitLabel(SectionBegin); | |
245 emitAppleAccelTable(Asm.get(), Table, "objc", SectionBegin); | |
246 } | |
247 | |
248 void DwarfStreamer::emitAppleTypes( | |
249 AccelTable<AppleAccelTableStaticTypeData> &Table) { | |
250 Asm->OutStreamer->SwitchSection(MOFI->getDwarfAccelTypesSection()); | |
251 auto *SectionBegin = Asm->createTempSymbol("types_begin"); | |
252 Asm->OutStreamer->EmitLabel(SectionBegin); | |
253 emitAppleAccelTable(Asm.get(), Table, "types", SectionBegin); | |
254 } | |
255 | |
256 /// Emit the swift_ast section stored in \p Buffers. | |
257 void DwarfStreamer::emitSwiftAST(StringRef Buffer) { | |
258 MCSection *SwiftASTSection = MOFI->getDwarfSwiftASTSection(); | |
259 SwiftASTSection->setAlignment(1 << 5); | |
260 MS->SwitchSection(SwiftASTSection); | |
261 MS->EmitBytes(Buffer); | |
262 } | |
263 | |
264 /// Emit the debug_range section contents for \p FuncRange by | |
265 /// translating the original \p Entries. The debug_range section | |
266 /// format is totally trivial, consisting just of pairs of address | |
267 /// sized addresses describing the ranges. | |
268 void DwarfStreamer::emitRangesEntries( | |
269 int64_t UnitPcOffset, uint64_t OrigLowPc, | |
270 const FunctionIntervals::const_iterator &FuncRange, | |
271 const std::vector<DWARFDebugRangeList::RangeListEntry> &Entries, | |
272 unsigned AddressSize) { | |
273 MS->SwitchSection(MC->getObjectFileInfo()->getDwarfRangesSection()); | |
274 | |
275 // Offset each range by the right amount. | |
276 int64_t PcOffset = Entries.empty() ? 0 : FuncRange.value() + UnitPcOffset; | |
277 for (const auto &Range : Entries) { | |
278 if (Range.isBaseAddressSelectionEntry(AddressSize)) { | |
279 warn("unsupported base address selection operation", | |
280 "emitting debug_ranges"); | |
281 break; | |
282 } | |
283 // Do not emit empty ranges. | |
284 if (Range.StartAddress == Range.EndAddress) | |
285 continue; | |
286 | |
287 // All range entries should lie in the function range. | |
288 if (!(Range.StartAddress + OrigLowPc >= FuncRange.start() && | |
289 Range.EndAddress + OrigLowPc <= FuncRange.stop())) | |
290 warn("inconsistent range data.", "emitting debug_ranges"); | |
291 MS->EmitIntValue(Range.StartAddress + PcOffset, AddressSize); | |
292 MS->EmitIntValue(Range.EndAddress + PcOffset, AddressSize); | |
293 RangesSectionSize += 2 * AddressSize; | |
294 } | |
295 | |
296 // Add the terminator entry. | |
297 MS->EmitIntValue(0, AddressSize); | |
298 MS->EmitIntValue(0, AddressSize); | |
299 RangesSectionSize += 2 * AddressSize; | |
300 } | |
301 | |
302 /// Emit the debug_aranges contribution of a unit and | |
303 /// if \p DoDebugRanges is true the debug_range contents for a | |
304 /// compile_unit level DW_AT_ranges attribute (Which are basically the | |
305 /// same thing with a different base address). | |
306 /// Just aggregate all the ranges gathered inside that unit. | |
307 void DwarfStreamer::emitUnitRangesEntries(CompileUnit &Unit, | |
308 bool DoDebugRanges) { | |
309 unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize(); | |
310 // Gather the ranges in a vector, so that we can simplify them. The | |
311 // IntervalMap will have coalesced the non-linked ranges, but here | |
312 // we want to coalesce the linked addresses. | |
313 std::vector<std::pair<uint64_t, uint64_t>> Ranges; | |
314 const auto &FunctionRanges = Unit.getFunctionRanges(); | |
315 for (auto Range = FunctionRanges.begin(), End = FunctionRanges.end(); | |
316 Range != End; ++Range) | |
317 Ranges.push_back(std::make_pair(Range.start() + Range.value(), | |
318 Range.stop() + Range.value())); | |
319 | |
320 // The object addresses where sorted, but again, the linked | |
321 // addresses might end up in a different order. | |
322 llvm::sort(Ranges); | |
323 | |
324 if (!Ranges.empty()) { | |
325 MS->SwitchSection(MC->getObjectFileInfo()->getDwarfARangesSection()); | |
326 | |
327 MCSymbol *BeginLabel = Asm->createTempSymbol("Barange"); | |
328 MCSymbol *EndLabel = Asm->createTempSymbol("Earange"); | |
329 | |
330 unsigned HeaderSize = | |
331 sizeof(int32_t) + // Size of contents (w/o this field | |
332 sizeof(int16_t) + // DWARF ARange version number | |
333 sizeof(int32_t) + // Offset of CU in the .debug_info section | |
334 sizeof(int8_t) + // Pointer Size (in bytes) | |
335 sizeof(int8_t); // Segment Size (in bytes) | |
336 | |
337 unsigned TupleSize = AddressSize * 2; | |
338 unsigned Padding = OffsetToAlignment(HeaderSize, TupleSize); | |
339 | |
340 Asm->EmitLabelDifference(EndLabel, BeginLabel, 4); // Arange length | |
341 Asm->OutStreamer->EmitLabel(BeginLabel); | |
342 Asm->emitInt16(dwarf::DW_ARANGES_VERSION); // Version number | |
343 Asm->emitInt32(Unit.getStartOffset()); // Corresponding unit's offset | |
344 Asm->emitInt8(AddressSize); // Address size | |
345 Asm->emitInt8(0); // Segment size | |
346 | |
347 Asm->OutStreamer->emitFill(Padding, 0x0); | |
348 | |
349 for (auto Range = Ranges.begin(), End = Ranges.end(); Range != End; | |
350 ++Range) { | |
351 uint64_t RangeStart = Range->first; | |
352 MS->EmitIntValue(RangeStart, AddressSize); | |
353 while ((Range + 1) != End && Range->second == (Range + 1)->first) | |
354 ++Range; | |
355 MS->EmitIntValue(Range->second - RangeStart, AddressSize); | |
356 } | |
357 | |
358 // Emit terminator | |
359 Asm->OutStreamer->EmitIntValue(0, AddressSize); | |
360 Asm->OutStreamer->EmitIntValue(0, AddressSize); | |
361 Asm->OutStreamer->EmitLabel(EndLabel); | |
362 } | |
363 | |
364 if (!DoDebugRanges) | |
365 return; | |
366 | |
367 MS->SwitchSection(MC->getObjectFileInfo()->getDwarfRangesSection()); | |
368 // Offset each range by the right amount. | |
369 int64_t PcOffset = -Unit.getLowPc(); | |
370 // Emit coalesced ranges. | |
371 for (auto Range = Ranges.begin(), End = Ranges.end(); Range != End; ++Range) { | |
372 MS->EmitIntValue(Range->first + PcOffset, AddressSize); | |
373 while (Range + 1 != End && Range->second == (Range + 1)->first) | |
374 ++Range; | |
375 MS->EmitIntValue(Range->second + PcOffset, AddressSize); | |
376 RangesSectionSize += 2 * AddressSize; | |
377 } | |
378 | |
379 // Add the terminator entry. | |
380 MS->EmitIntValue(0, AddressSize); | |
381 MS->EmitIntValue(0, AddressSize); | |
382 RangesSectionSize += 2 * AddressSize; | |
383 } | |
384 | |
385 /// Emit location lists for \p Unit and update attributes to point to the new | |
386 /// entries. | |
387 void DwarfStreamer::emitLocationsForUnit( | |
388 const CompileUnit &Unit, DWARFContext &Dwarf, | |
389 std::function<void(StringRef, SmallVectorImpl<uint8_t> &)> ProcessExpr) { | |
390 const auto &Attributes = Unit.getLocationAttributes(); | |
391 | |
392 if (Attributes.empty()) | |
393 return; | |
394 | |
395 MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLocSection()); | |
396 | |
397 unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize(); | |
398 const DWARFSection &InputSec = Dwarf.getDWARFObj().getLocSection(); | |
399 DataExtractor Data(InputSec.Data, Dwarf.isLittleEndian(), AddressSize); | |
400 DWARFUnit &OrigUnit = Unit.getOrigUnit(); | |
401 auto OrigUnitDie = OrigUnit.getUnitDIE(false); | |
402 int64_t UnitPcOffset = 0; | |
403 if (auto OrigLowPc = dwarf::toAddress(OrigUnitDie.find(dwarf::DW_AT_low_pc))) | |
404 UnitPcOffset = int64_t(*OrigLowPc) - Unit.getLowPc(); | |
405 | |
406 SmallVector<uint8_t, 32> Buffer; | |
407 for (const auto &Attr : Attributes) { | |
408 uint64_t Offset = Attr.first.get(); | |
409 Attr.first.set(LocSectionSize); | |
410 // This is the quantity to add to the old location address to get | |
411 // the correct address for the new one. | |
412 int64_t LocPcOffset = Attr.second + UnitPcOffset; | |
413 while (Data.isValidOffset(Offset)) { | |
414 uint64_t Low = Data.getUnsigned(&Offset, AddressSize); | |
415 uint64_t High = Data.getUnsigned(&Offset, AddressSize); | |
416 LocSectionSize += 2 * AddressSize; | |
417 if (Low == 0 && High == 0) { | |
418 Asm->OutStreamer->EmitIntValue(0, AddressSize); | |
419 Asm->OutStreamer->EmitIntValue(0, AddressSize); | |
420 break; | |
421 } | |
422 Asm->OutStreamer->EmitIntValue(Low + LocPcOffset, AddressSize); | |
423 Asm->OutStreamer->EmitIntValue(High + LocPcOffset, AddressSize); | |
424 uint64_t Length = Data.getU16(&Offset); | |
425 Asm->OutStreamer->EmitIntValue(Length, 2); | |
426 // Copy the bytes into to the buffer, process them, emit them. | |
427 Buffer.reserve(Length); | |
428 Buffer.resize(0); | |
429 StringRef Input = InputSec.Data.substr(Offset, Length); | |
430 ProcessExpr(Input, Buffer); | |
431 Asm->OutStreamer->EmitBytes( | |
432 StringRef((const char *)Buffer.data(), Length)); | |
433 Offset += Length; | |
434 LocSectionSize += Length + 2; | |
435 } | |
436 } | |
437 } | |
438 | |
439 void DwarfStreamer::emitLineTableForUnit(MCDwarfLineTableParams Params, | |
440 StringRef PrologueBytes, | |
441 unsigned MinInstLength, | |
442 std::vector<DWARFDebugLine::Row> &Rows, | |
443 unsigned PointerSize) { | |
444 // Switch to the section where the table will be emitted into. | |
445 MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLineSection()); | |
446 MCSymbol *LineStartSym = MC->createTempSymbol(); | |
447 MCSymbol *LineEndSym = MC->createTempSymbol(); | |
448 | |
449 // The first 4 bytes is the total length of the information for this | |
450 // compilation unit (not including these 4 bytes for the length). | |
451 Asm->EmitLabelDifference(LineEndSym, LineStartSym, 4); | |
452 Asm->OutStreamer->EmitLabel(LineStartSym); | |
453 // Copy Prologue. | |
454 MS->EmitBytes(PrologueBytes); | |
455 LineSectionSize += PrologueBytes.size() + 4; | |
456 | |
457 SmallString<128> EncodingBuffer; | |
458 raw_svector_ostream EncodingOS(EncodingBuffer); | |
459 | |
460 if (Rows.empty()) { | |
461 // We only have the dummy entry, dsymutil emits an entry with a 0 | |
462 // address in that case. | |
463 MCDwarfLineAddr::Encode(*MC, Params, std::numeric_limits<int64_t>::max(), 0, | |
464 EncodingOS); | |
465 MS->EmitBytes(EncodingOS.str()); | |
466 LineSectionSize += EncodingBuffer.size(); | |
467 MS->EmitLabel(LineEndSym); | |
468 return; | |
469 } | |
470 | |
471 // Line table state machine fields | |
472 unsigned FileNum = 1; | |
473 unsigned LastLine = 1; | |
474 unsigned Column = 0; | |
475 unsigned IsStatement = 1; | |
476 unsigned Isa = 0; | |
477 uint64_t Address = -1ULL; | |
478 | |
479 unsigned RowsSinceLastSequence = 0; | |
480 | |
481 for (unsigned Idx = 0; Idx < Rows.size(); ++Idx) { | |
482 auto &Row = Rows[Idx]; | |
483 | |
484 int64_t AddressDelta; | |
485 if (Address == -1ULL) { | |
486 MS->EmitIntValue(dwarf::DW_LNS_extended_op, 1); | |
487 MS->EmitULEB128IntValue(PointerSize + 1); | |
488 MS->EmitIntValue(dwarf::DW_LNE_set_address, 1); | |
489 MS->EmitIntValue(Row.Address.Address, PointerSize); | |
490 LineSectionSize += 2 + PointerSize + getULEB128Size(PointerSize + 1); | |
491 AddressDelta = 0; | |
492 } else { | |
493 AddressDelta = (Row.Address.Address - Address) / MinInstLength; | |
494 } | |
495 | |
496 // FIXME: code copied and transformed from MCDwarf.cpp::EmitDwarfLineTable. | |
497 // We should find a way to share this code, but the current compatibility | |
498 // requirement with classic dsymutil makes it hard. Revisit that once this | |
499 // requirement is dropped. | |
500 | |
501 if (FileNum != Row.File) { | |
502 FileNum = Row.File; | |
503 MS->EmitIntValue(dwarf::DW_LNS_set_file, 1); | |
504 MS->EmitULEB128IntValue(FileNum); | |
505 LineSectionSize += 1 + getULEB128Size(FileNum); | |
506 } | |
507 if (Column != Row.Column) { | |
508 Column = Row.Column; | |
509 MS->EmitIntValue(dwarf::DW_LNS_set_column, 1); | |
510 MS->EmitULEB128IntValue(Column); | |
511 LineSectionSize += 1 + getULEB128Size(Column); | |
512 } | |
513 | |
514 // FIXME: We should handle the discriminator here, but dsymutil doesn't | |
515 // consider it, thus ignore it for now. | |
516 | |
517 if (Isa != Row.Isa) { | |
518 Isa = Row.Isa; | |
519 MS->EmitIntValue(dwarf::DW_LNS_set_isa, 1); | |
520 MS->EmitULEB128IntValue(Isa); | |
521 LineSectionSize += 1 + getULEB128Size(Isa); | |
522 } | |
523 if (IsStatement != Row.IsStmt) { | |
524 IsStatement = Row.IsStmt; | |
525 MS->EmitIntValue(dwarf::DW_LNS_negate_stmt, 1); | |
526 LineSectionSize += 1; | |
527 } | |
528 if (Row.BasicBlock) { | |
529 MS->EmitIntValue(dwarf::DW_LNS_set_basic_block, 1); | |
530 LineSectionSize += 1; | |
531 } | |
532 | |
533 if (Row.PrologueEnd) { | |
534 MS->EmitIntValue(dwarf::DW_LNS_set_prologue_end, 1); | |
535 LineSectionSize += 1; | |
536 } | |
537 | |
538 if (Row.EpilogueBegin) { | |
539 MS->EmitIntValue(dwarf::DW_LNS_set_epilogue_begin, 1); | |
540 LineSectionSize += 1; | |
541 } | |
542 | |
543 int64_t LineDelta = int64_t(Row.Line) - LastLine; | |
544 if (!Row.EndSequence) { | |
545 MCDwarfLineAddr::Encode(*MC, Params, LineDelta, AddressDelta, EncodingOS); | |
546 MS->EmitBytes(EncodingOS.str()); | |
547 LineSectionSize += EncodingBuffer.size(); | |
548 EncodingBuffer.resize(0); | |
549 Address = Row.Address.Address; | |
550 LastLine = Row.Line; | |
551 RowsSinceLastSequence++; | |
552 } else { | |
553 if (LineDelta) { | |
554 MS->EmitIntValue(dwarf::DW_LNS_advance_line, 1); | |
555 MS->EmitSLEB128IntValue(LineDelta); | |
556 LineSectionSize += 1 + getSLEB128Size(LineDelta); | |
557 } | |
558 if (AddressDelta) { | |
559 MS->EmitIntValue(dwarf::DW_LNS_advance_pc, 1); | |
560 MS->EmitULEB128IntValue(AddressDelta); | |
561 LineSectionSize += 1 + getULEB128Size(AddressDelta); | |
562 } | |
563 MCDwarfLineAddr::Encode(*MC, Params, std::numeric_limits<int64_t>::max(), | |
564 0, EncodingOS); | |
565 MS->EmitBytes(EncodingOS.str()); | |
566 LineSectionSize += EncodingBuffer.size(); | |
567 EncodingBuffer.resize(0); | |
568 Address = -1ULL; | |
569 LastLine = FileNum = IsStatement = 1; | |
570 RowsSinceLastSequence = Column = Isa = 0; | |
571 } | |
572 } | |
573 | |
574 if (RowsSinceLastSequence) { | |
575 MCDwarfLineAddr::Encode(*MC, Params, std::numeric_limits<int64_t>::max(), 0, | |
576 EncodingOS); | |
577 MS->EmitBytes(EncodingOS.str()); | |
578 LineSectionSize += EncodingBuffer.size(); | |
579 EncodingBuffer.resize(0); | |
580 } | |
581 | |
582 MS->EmitLabel(LineEndSym); | |
583 } | |
584 | |
585 /// Copy the debug_line over to the updated binary while unobfuscating the file | |
586 /// names and directories. | |
587 void DwarfStreamer::translateLineTable(DataExtractor Data, uint64_t Offset) { | |
588 MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLineSection()); | |
589 StringRef Contents = Data.getData(); | |
590 | |
591 // We have to deconstruct the line table header, because it contains to | |
592 // length fields that will need to be updated when we change the length of | |
593 // the files and directories in there. | |
594 unsigned UnitLength = Data.getU32(&Offset); | |
595 uint64_t UnitEnd = Offset + UnitLength; | |
596 MCSymbol *BeginLabel = MC->createTempSymbol(); | |
597 MCSymbol *EndLabel = MC->createTempSymbol(); | |
598 unsigned Version = Data.getU16(&Offset); | |
599 | |
600 if (Version > 5) { | |
601 warn("Unsupported line table version: dropping contents and not " | |
602 "unobfsucating line table."); | |
603 return; | |
604 } | |
605 | |
606 Asm->EmitLabelDifference(EndLabel, BeginLabel, 4); | |
607 Asm->OutStreamer->EmitLabel(BeginLabel); | |
608 Asm->emitInt16(Version); | |
609 LineSectionSize += 6; | |
610 | |
611 MCSymbol *HeaderBeginLabel = MC->createTempSymbol(); | |
612 MCSymbol *HeaderEndLabel = MC->createTempSymbol(); | |
613 Asm->EmitLabelDifference(HeaderEndLabel, HeaderBeginLabel, 4); | |
614 Asm->OutStreamer->EmitLabel(HeaderBeginLabel); | |
615 Offset += 4; | |
616 LineSectionSize += 4; | |
617 | |
618 uint64_t AfterHeaderLengthOffset = Offset; | |
619 // Skip to the directories. | |
620 Offset += (Version >= 4) ? 5 : 4; | |
621 unsigned OpcodeBase = Data.getU8(&Offset); | |
622 Offset += OpcodeBase - 1; | |
623 Asm->OutStreamer->EmitBytes(Contents.slice(AfterHeaderLengthOffset, Offset)); | |
624 LineSectionSize += Offset - AfterHeaderLengthOffset; | |
625 | |
626 // Offset points to the first directory. | |
627 while (const char *Dir = Data.getCStr(&Offset)) { | |
628 if (Dir[0] == 0) | |
629 break; | |
630 | |
631 StringRef Translated = Options.Translator(Dir); | |
632 Asm->OutStreamer->EmitBytes(Translated); | |
633 Asm->emitInt8(0); | |
634 LineSectionSize += Translated.size() + 1; | |
635 } | |
636 Asm->emitInt8(0); | |
637 LineSectionSize += 1; | |
638 | |
639 while (const char *File = Data.getCStr(&Offset)) { | |
640 if (File[0] == 0) | |
641 break; | |
642 | |
643 StringRef Translated = Options.Translator(File); | |
644 Asm->OutStreamer->EmitBytes(Translated); | |
645 Asm->emitInt8(0); | |
646 LineSectionSize += Translated.size() + 1; | |
647 | |
648 uint64_t OffsetBeforeLEBs = Offset; | |
649 Asm->EmitULEB128(Data.getULEB128(&Offset)); | |
650 Asm->EmitULEB128(Data.getULEB128(&Offset)); | |
651 Asm->EmitULEB128(Data.getULEB128(&Offset)); | |
652 LineSectionSize += Offset - OffsetBeforeLEBs; | |
653 } | |
654 Asm->emitInt8(0); | |
655 LineSectionSize += 1; | |
656 | |
657 Asm->OutStreamer->EmitLabel(HeaderEndLabel); | |
658 | |
659 // Copy the actual line table program over. | |
660 Asm->OutStreamer->EmitBytes(Contents.slice(Offset, UnitEnd)); | |
661 LineSectionSize += UnitEnd - Offset; | |
662 | |
663 Asm->OutStreamer->EmitLabel(EndLabel); | |
664 Offset = UnitEnd; | |
665 } | |
666 | |
667 static void emitSectionContents(const object::ObjectFile &Obj, | |
668 StringRef SecName, MCStreamer *MS) { | |
669 if (auto Sec = getSectionByName(Obj, SecName)) { | |
670 if (Expected<StringRef> E = Sec->getContents()) | |
671 MS->EmitBytes(*E); | |
672 else | |
673 consumeError(E.takeError()); | |
674 } | |
675 } | |
676 | |
677 void DwarfStreamer::copyInvariantDebugSection(const object::ObjectFile &Obj) { | |
678 if (!Options.Translator) { | |
679 MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLineSection()); | |
680 emitSectionContents(Obj, "debug_line", MS); | |
681 } | |
682 | |
683 MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLocSection()); | |
684 emitSectionContents(Obj, "debug_loc", MS); | |
685 | |
686 MS->SwitchSection(MC->getObjectFileInfo()->getDwarfRangesSection()); | |
687 emitSectionContents(Obj, "debug_ranges", MS); | |
688 | |
689 MS->SwitchSection(MC->getObjectFileInfo()->getDwarfFrameSection()); | |
690 emitSectionContents(Obj, "debug_frame", MS); | |
691 | |
692 MS->SwitchSection(MC->getObjectFileInfo()->getDwarfARangesSection()); | |
693 emitSectionContents(Obj, "debug_aranges", MS); | |
694 } | |
695 | |
696 /// Emit the pubnames or pubtypes section contribution for \p | |
697 /// Unit into \p Sec. The data is provided in \p Names. | |
698 void DwarfStreamer::emitPubSectionForUnit( | |
699 MCSection *Sec, StringRef SecName, const CompileUnit &Unit, | |
700 const std::vector<CompileUnit::AccelInfo> &Names) { | |
701 if (Names.empty()) | |
702 return; | |
703 | |
704 // Start the dwarf pubnames section. | |
705 Asm->OutStreamer->SwitchSection(Sec); | |
706 MCSymbol *BeginLabel = Asm->createTempSymbol("pub" + SecName + "_begin"); | |
707 MCSymbol *EndLabel = Asm->createTempSymbol("pub" + SecName + "_end"); | |
708 | |
709 bool HeaderEmitted = false; | |
710 // Emit the pubnames for this compilation unit. | |
711 for (const auto &Name : Names) { | |
712 if (Name.SkipPubSection) | |
713 continue; | |
714 | |
715 if (!HeaderEmitted) { | |
716 // Emit the header. | |
717 Asm->EmitLabelDifference(EndLabel, BeginLabel, 4); // Length | |
718 Asm->OutStreamer->EmitLabel(BeginLabel); | |
719 Asm->emitInt16(dwarf::DW_PUBNAMES_VERSION); // Version | |
720 Asm->emitInt32(Unit.getStartOffset()); // Unit offset | |
721 Asm->emitInt32(Unit.getNextUnitOffset() - Unit.getStartOffset()); // Size | |
722 HeaderEmitted = true; | |
723 } | |
724 Asm->emitInt32(Name.Die->getOffset()); | |
725 | |
726 // Emit the string itself. | |
727 Asm->OutStreamer->EmitBytes(Name.Name.getString()); | |
728 // Emit a null terminator. | |
729 Asm->emitInt8(0); | |
730 } | |
731 | |
732 if (!HeaderEmitted) | |
733 return; | |
734 Asm->emitInt32(0); // End marker. | |
735 Asm->OutStreamer->EmitLabel(EndLabel); | |
736 } | |
737 | |
738 /// Emit .debug_pubnames for \p Unit. | |
739 void DwarfStreamer::emitPubNamesForUnit(const CompileUnit &Unit) { | |
740 emitPubSectionForUnit(MC->getObjectFileInfo()->getDwarfPubNamesSection(), | |
741 "names", Unit, Unit.getPubnames()); | |
742 } | |
743 | |
744 /// Emit .debug_pubtypes for \p Unit. | |
745 void DwarfStreamer::emitPubTypesForUnit(const CompileUnit &Unit) { | |
746 emitPubSectionForUnit(MC->getObjectFileInfo()->getDwarfPubTypesSection(), | |
747 "types", Unit, Unit.getPubtypes()); | |
748 } | |
749 | |
750 /// Emit a CIE into the debug_frame section. | |
751 void DwarfStreamer::emitCIE(StringRef CIEBytes) { | |
752 MS->SwitchSection(MC->getObjectFileInfo()->getDwarfFrameSection()); | |
753 | |
754 MS->EmitBytes(CIEBytes); | |
755 FrameSectionSize += CIEBytes.size(); | |
756 } | |
757 | |
758 /// Emit a FDE into the debug_frame section. \p FDEBytes | |
759 /// contains the FDE data without the length, CIE offset and address | |
760 /// which will be replaced with the parameter values. | |
761 void DwarfStreamer::emitFDE(uint32_t CIEOffset, uint32_t AddrSize, | |
762 uint32_t Address, StringRef FDEBytes) { | |
763 MS->SwitchSection(MC->getObjectFileInfo()->getDwarfFrameSection()); | |
764 | |
765 MS->EmitIntValue(FDEBytes.size() + 4 + AddrSize, 4); | |
766 MS->EmitIntValue(CIEOffset, 4); | |
767 MS->EmitIntValue(Address, AddrSize); | |
768 MS->EmitBytes(FDEBytes); | |
769 FrameSectionSize += FDEBytes.size() + 8 + AddrSize; | |
770 } | |
771 | |
772 } // namespace dsymutil | |
773 } // namespace llvm |