1 | //===- SymbolRecord.h -------------------------------------------*- C++ -*-===// |
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 | #ifndef LLVM_DEBUGINFO_CODEVIEW_SYMBOLRECORD_H |
10 | #define LLVM_DEBUGINFO_CODEVIEW_SYMBOLRECORD_H |
11 | |
12 | #include "llvm/ADT/APSInt.h" |
13 | #include "llvm/ADT/ArrayRef.h" |
14 | #include "llvm/ADT/StringRef.h" |
15 | #include "llvm/ADT/iterator.h" |
16 | #include "llvm/ADT/iterator_range.h" |
17 | #include "llvm/DebugInfo/CodeView/CVRecord.h" |
18 | #include "llvm/DebugInfo/CodeView/CodeView.h" |
19 | #include "llvm/DebugInfo/CodeView/RecordSerialization.h" |
20 | #include "llvm/DebugInfo/CodeView/TypeIndex.h" |
21 | #include "llvm/Support/BinaryStreamArray.h" |
22 | #include "llvm/Support/Endian.h" |
23 | #include <cstdint> |
24 | #include <vector> |
25 | |
26 | namespace llvm { |
27 | namespace codeview { |
28 | |
29 | class SymbolRecord { |
30 | protected: |
31 | explicit SymbolRecord(SymbolRecordKind Kind) : Kind(Kind) {} |
32 | |
33 | public: |
34 | SymbolRecordKind getKind() const { return Kind; } |
35 | |
36 | SymbolRecordKind Kind; |
37 | }; |
38 | |
39 | // S_GPROC32, S_LPROC32, S_GPROC32_ID, S_LPROC32_ID, S_LPROC32_DPC or |
40 | // S_LPROC32_DPC_ID |
41 | class ProcSym : public SymbolRecord { |
42 | static constexpr uint32_t RelocationOffset = 32; |
43 | |
44 | public: |
45 | explicit ProcSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
46 | ProcSym(SymbolRecordKind Kind, uint32_t RecordOffset) |
47 | : SymbolRecord(Kind), RecordOffset(RecordOffset) {} |
48 | |
49 | uint32_t getRelocationOffset() const { |
50 | return RecordOffset + RelocationOffset; |
51 | } |
52 | |
53 | uint32_t Parent = 0; |
54 | uint32_t End = 0; |
55 | uint32_t Next = 0; |
56 | uint32_t CodeSize = 0; |
57 | uint32_t DbgStart = 0; |
58 | uint32_t DbgEnd = 0; |
59 | TypeIndex FunctionType; |
60 | uint32_t CodeOffset = 0; |
61 | uint16_t Segment = 0; |
62 | ProcSymFlags Flags = ProcSymFlags::None; |
63 | StringRef Name; |
64 | |
65 | uint32_t RecordOffset = 0; |
66 | }; |
67 | |
68 | // S_THUNK32 |
69 | class Thunk32Sym : public SymbolRecord { |
70 | public: |
71 | explicit Thunk32Sym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
72 | Thunk32Sym(SymbolRecordKind Kind, uint32_t RecordOffset) |
73 | : SymbolRecord(Kind), RecordOffset(RecordOffset) {} |
74 | |
75 | uint32_t Parent = 0; |
76 | uint32_t End = 0; |
77 | uint32_t Next = 0; |
78 | uint32_t Offset = 0; |
79 | uint16_t Segment = 0; |
80 | uint16_t Length = 0; |
81 | ThunkOrdinal Thunk = ThunkOrdinal::Standard; |
82 | StringRef Name; |
83 | ArrayRef<uint8_t> VariantData; |
84 | |
85 | uint32_t RecordOffset = 0; |
86 | }; |
87 | |
88 | // S_TRAMPOLINE |
89 | class TrampolineSym : public SymbolRecord { |
90 | public: |
91 | explicit TrampolineSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
92 | TrampolineSym(SymbolRecordKind Kind, uint32_t RecordOffset) |
93 | : SymbolRecord(Kind), RecordOffset(RecordOffset) {} |
94 | |
95 | TrampolineType Type; |
96 | uint16_t Size = 0; |
97 | uint32_t ThunkOffset = 0; |
98 | uint32_t TargetOffset = 0; |
99 | uint16_t ThunkSection = 0; |
100 | uint16_t TargetSection = 0; |
101 | |
102 | uint32_t RecordOffset = 0; |
103 | }; |
104 | |
105 | // S_SECTION |
106 | class SectionSym : public SymbolRecord { |
107 | public: |
108 | explicit SectionSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
109 | SectionSym(SymbolRecordKind Kind, uint32_t RecordOffset) |
110 | : SymbolRecord(Kind), RecordOffset(RecordOffset) {} |
111 | |
112 | uint16_t SectionNumber = 0; |
113 | uint8_t Alignment = 0; |
114 | uint32_t Rva = 0; |
115 | uint32_t Length = 0; |
116 | uint32_t Characteristics = 0; |
117 | StringRef Name; |
118 | |
119 | uint32_t RecordOffset = 0; |
120 | }; |
121 | |
122 | // S_COFFGROUP |
123 | class CoffGroupSym : public SymbolRecord { |
124 | public: |
125 | explicit CoffGroupSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
126 | CoffGroupSym(SymbolRecordKind Kind, uint32_t RecordOffset) |
127 | : SymbolRecord(Kind), RecordOffset(RecordOffset) {} |
128 | |
129 | uint32_t Size = 0; |
130 | uint32_t Characteristics = 0; |
131 | uint32_t Offset = 0; |
132 | uint16_t Segment = 0; |
133 | StringRef Name; |
134 | |
135 | uint32_t RecordOffset = 0; |
136 | }; |
137 | |
138 | class ScopeEndSym : public SymbolRecord { |
139 | public: |
140 | explicit ScopeEndSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
141 | ScopeEndSym(SymbolRecordKind Kind, uint32_t RecordOffset) |
142 | : SymbolRecord(Kind), RecordOffset(RecordOffset) {} |
143 | |
144 | uint32_t RecordOffset = 0; |
145 | }; |
146 | |
147 | class JumpTableSym : public SymbolRecord { |
148 | public: |
149 | explicit JumpTableSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
150 | JumpTableSym(uint32_t RecordOffset) |
151 | : SymbolRecord(SymbolRecordKind::JumpTableSym), |
152 | RecordOffset(RecordOffset) {} |
153 | |
154 | uint32_t BaseOffset = 0; |
155 | uint16_t BaseSegment = 0; |
156 | |
157 | JumpTableEntrySize SwitchType; |
158 | uint32_t BranchOffset = 0; |
159 | uint32_t TableOffset = 0; |
160 | uint16_t BranchSegment = 0; |
161 | uint16_t TableSegment = 0; |
162 | |
163 | uint32_t EntriesCount = 0; |
164 | |
165 | uint32_t RecordOffset = 0; |
166 | }; |
167 | |
168 | class CallerSym : public SymbolRecord { |
169 | public: |
170 | explicit CallerSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
171 | CallerSym(SymbolRecordKind Kind, uint32_t RecordOffset) |
172 | : SymbolRecord(Kind), RecordOffset(RecordOffset) {} |
173 | |
174 | std::vector<TypeIndex> Indices; |
175 | |
176 | uint32_t RecordOffset = 0; |
177 | }; |
178 | |
179 | struct DecodedAnnotation { |
180 | StringRef Name; |
181 | ArrayRef<uint8_t> Bytes; |
182 | BinaryAnnotationsOpCode OpCode = BinaryAnnotationsOpCode::Invalid; |
183 | uint32_t U1 = 0; |
184 | uint32_t U2 = 0; |
185 | int32_t S1 = 0; |
186 | }; |
187 | |
188 | struct BinaryAnnotationIterator |
189 | : public iterator_facade_base<BinaryAnnotationIterator, |
190 | std::forward_iterator_tag, |
191 | DecodedAnnotation> { |
192 | BinaryAnnotationIterator() = default; |
193 | BinaryAnnotationIterator(ArrayRef<uint8_t> Annotations) : Data(Annotations) {} |
194 | BinaryAnnotationIterator(const BinaryAnnotationIterator &Other) |
195 | : Data(Other.Data) {} |
196 | |
197 | bool operator==(BinaryAnnotationIterator Other) const { |
198 | return Data == Other.Data; |
199 | } |
200 | |
201 | BinaryAnnotationIterator &operator=(const BinaryAnnotationIterator Other) { |
202 | Data = Other.Data; |
203 | return *this; |
204 | } |
205 | |
206 | BinaryAnnotationIterator &operator++() { |
207 | if (!ParseCurrentAnnotation()) { |
208 | *this = BinaryAnnotationIterator(); |
209 | return *this; |
210 | } |
211 | Data = Next; |
212 | Next = ArrayRef<uint8_t>(); |
213 | Current.reset(); |
214 | return *this; |
215 | } |
216 | |
217 | const DecodedAnnotation &operator*() { |
218 | ParseCurrentAnnotation(); |
219 | return *Current; |
220 | } |
221 | |
222 | private: |
223 | static uint32_t GetCompressedAnnotation(ArrayRef<uint8_t> &Annotations) { |
224 | if (Annotations.empty()) |
225 | return -1; |
226 | |
227 | uint8_t FirstByte = Annotations.front(); |
228 | Annotations = Annotations.drop_front(); |
229 | |
230 | if ((FirstByte & 0x80) == 0x00) |
231 | return FirstByte; |
232 | |
233 | if (Annotations.empty()) |
234 | return -1; |
235 | |
236 | uint8_t SecondByte = Annotations.front(); |
237 | Annotations = Annotations.drop_front(); |
238 | |
239 | if ((FirstByte & 0xC0) == 0x80) |
240 | return ((FirstByte & 0x3F) << 8) | SecondByte; |
241 | |
242 | if (Annotations.empty()) |
243 | return -1; |
244 | |
245 | uint8_t ThirdByte = Annotations.front(); |
246 | Annotations = Annotations.drop_front(); |
247 | |
248 | if (Annotations.empty()) |
249 | return -1; |
250 | |
251 | uint8_t FourthByte = Annotations.front(); |
252 | Annotations = Annotations.drop_front(); |
253 | |
254 | if ((FirstByte & 0xE0) == 0xC0) |
255 | return ((FirstByte & 0x1F) << 24) | (SecondByte << 16) | |
256 | (ThirdByte << 8) | FourthByte; |
257 | |
258 | return -1; |
259 | } |
260 | |
261 | static int32_t DecodeSignedOperand(uint32_t Operand) { |
262 | if (Operand & 1) |
263 | return -(Operand >> 1); |
264 | return Operand >> 1; |
265 | } |
266 | |
267 | static int32_t DecodeSignedOperand(ArrayRef<uint8_t> &Annotations) { |
268 | return DecodeSignedOperand(Operand: GetCompressedAnnotation(Annotations)); |
269 | } |
270 | |
271 | bool ParseCurrentAnnotation() { |
272 | if (Current) |
273 | return true; |
274 | |
275 | Next = Data; |
276 | uint32_t Op = GetCompressedAnnotation(Annotations&: Next); |
277 | DecodedAnnotation Result; |
278 | Result.OpCode = static_cast<BinaryAnnotationsOpCode>(Op); |
279 | switch (Result.OpCode) { |
280 | case BinaryAnnotationsOpCode::Invalid: |
281 | Result.Name = "Invalid" ; |
282 | Next = ArrayRef<uint8_t>(); |
283 | break; |
284 | case BinaryAnnotationsOpCode::CodeOffset: |
285 | Result.Name = "CodeOffset" ; |
286 | Result.U1 = GetCompressedAnnotation(Annotations&: Next); |
287 | break; |
288 | case BinaryAnnotationsOpCode::ChangeCodeOffsetBase: |
289 | Result.Name = "ChangeCodeOffsetBase" ; |
290 | Result.U1 = GetCompressedAnnotation(Annotations&: Next); |
291 | break; |
292 | case BinaryAnnotationsOpCode::ChangeCodeOffset: |
293 | Result.Name = "ChangeCodeOffset" ; |
294 | Result.U1 = GetCompressedAnnotation(Annotations&: Next); |
295 | break; |
296 | case BinaryAnnotationsOpCode::ChangeCodeLength: |
297 | Result.Name = "ChangeCodeLength" ; |
298 | Result.U1 = GetCompressedAnnotation(Annotations&: Next); |
299 | break; |
300 | case BinaryAnnotationsOpCode::ChangeFile: |
301 | Result.Name = "ChangeFile" ; |
302 | Result.U1 = GetCompressedAnnotation(Annotations&: Next); |
303 | break; |
304 | case BinaryAnnotationsOpCode::ChangeLineEndDelta: |
305 | Result.Name = "ChangeLineEndDelta" ; |
306 | Result.U1 = GetCompressedAnnotation(Annotations&: Next); |
307 | break; |
308 | case BinaryAnnotationsOpCode::ChangeRangeKind: |
309 | Result.Name = "ChangeRangeKind" ; |
310 | Result.U1 = GetCompressedAnnotation(Annotations&: Next); |
311 | break; |
312 | case BinaryAnnotationsOpCode::ChangeColumnStart: |
313 | Result.Name = "ChangeColumnStart" ; |
314 | Result.U1 = GetCompressedAnnotation(Annotations&: Next); |
315 | break; |
316 | case BinaryAnnotationsOpCode::ChangeColumnEnd: |
317 | Result.Name = "ChangeColumnEnd" ; |
318 | Result.U1 = GetCompressedAnnotation(Annotations&: Next); |
319 | break; |
320 | case BinaryAnnotationsOpCode::ChangeLineOffset: |
321 | Result.Name = "ChangeLineOffset" ; |
322 | Result.S1 = DecodeSignedOperand(Annotations&: Next); |
323 | break; |
324 | case BinaryAnnotationsOpCode::ChangeColumnEndDelta: |
325 | Result.Name = "ChangeColumnEndDelta" ; |
326 | Result.S1 = DecodeSignedOperand(Annotations&: Next); |
327 | break; |
328 | case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset: { |
329 | Result.Name = "ChangeCodeOffsetAndLineOffset" ; |
330 | uint32_t Annotation = GetCompressedAnnotation(Annotations&: Next); |
331 | Result.S1 = DecodeSignedOperand(Operand: Annotation >> 4); |
332 | Result.U1 = Annotation & 0xf; |
333 | break; |
334 | } |
335 | case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset: { |
336 | Result.Name = "ChangeCodeLengthAndCodeOffset" ; |
337 | Result.U1 = GetCompressedAnnotation(Annotations&: Next); |
338 | Result.U2 = GetCompressedAnnotation(Annotations&: Next); |
339 | break; |
340 | } |
341 | } |
342 | Result.Bytes = Data.take_front(N: Data.size() - Next.size()); |
343 | Current = Result; |
344 | return true; |
345 | } |
346 | |
347 | std::optional<DecodedAnnotation> Current; |
348 | ArrayRef<uint8_t> Data; |
349 | ArrayRef<uint8_t> Next; |
350 | }; |
351 | |
352 | // S_INLINESITE |
353 | class InlineSiteSym : public SymbolRecord { |
354 | public: |
355 | explicit InlineSiteSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
356 | explicit InlineSiteSym(uint32_t RecordOffset) |
357 | : SymbolRecord(SymbolRecordKind::InlineSiteSym), |
358 | RecordOffset(RecordOffset) {} |
359 | |
360 | iterator_range<BinaryAnnotationIterator> annotations() const { |
361 | return make_range(x: BinaryAnnotationIterator(AnnotationData), |
362 | y: BinaryAnnotationIterator()); |
363 | } |
364 | |
365 | uint32_t Parent = 0; |
366 | uint32_t End = 0; |
367 | TypeIndex Inlinee; |
368 | std::vector<uint8_t> AnnotationData; |
369 | |
370 | uint32_t RecordOffset = 0; |
371 | }; |
372 | |
373 | struct { |
374 | ulittle32_t ; |
375 | ulittle32_t ; |
376 | ulittle16_t ; |
377 | // char Name[]; |
378 | }; |
379 | |
380 | // S_PUB32 |
381 | class PublicSym32 : public SymbolRecord { |
382 | public: |
383 | PublicSym32() : SymbolRecord(SymbolRecordKind::PublicSym32) {} |
384 | explicit PublicSym32(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
385 | explicit PublicSym32(uint32_t RecordOffset) |
386 | : SymbolRecord(SymbolRecordKind::PublicSym32), |
387 | RecordOffset(RecordOffset) {} |
388 | |
389 | PublicSymFlags Flags = PublicSymFlags::None; |
390 | uint32_t Offset = 0; |
391 | uint16_t Segment = 0; |
392 | StringRef Name; |
393 | |
394 | uint32_t RecordOffset = 0; |
395 | }; |
396 | |
397 | // S_REGISTER |
398 | class RegisterSym : public SymbolRecord { |
399 | public: |
400 | explicit RegisterSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
401 | explicit RegisterSym(uint32_t RecordOffset) |
402 | : SymbolRecord(SymbolRecordKind::RegisterSym), |
403 | RecordOffset(RecordOffset) {} |
404 | |
405 | TypeIndex Index; |
406 | RegisterId Register; |
407 | StringRef Name; |
408 | |
409 | uint32_t RecordOffset = 0; |
410 | }; |
411 | |
412 | // S_PROCREF, S_LPROCREF |
413 | class ProcRefSym : public SymbolRecord { |
414 | public: |
415 | explicit ProcRefSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
416 | explicit ProcRefSym(uint32_t RecordOffset) |
417 | : SymbolRecord(SymbolRecordKind::ProcRefSym), RecordOffset(RecordOffset) { |
418 | } |
419 | |
420 | uint32_t SumName = 0; |
421 | uint32_t SymOffset = 0; |
422 | uint16_t Module = 0; |
423 | StringRef Name; |
424 | |
425 | uint16_t modi() const { return Module - 1; } |
426 | uint32_t RecordOffset = 0; |
427 | }; |
428 | |
429 | // S_LOCAL |
430 | class LocalSym : public SymbolRecord { |
431 | public: |
432 | explicit LocalSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
433 | explicit LocalSym(uint32_t RecordOffset) |
434 | : SymbolRecord(SymbolRecordKind::LocalSym), RecordOffset(RecordOffset) {} |
435 | |
436 | TypeIndex Type; |
437 | LocalSymFlags Flags = LocalSymFlags::None; |
438 | StringRef Name; |
439 | |
440 | uint32_t RecordOffset = 0; |
441 | }; |
442 | |
443 | struct LocalVariableAddrRange { |
444 | uint32_t OffsetStart = 0; |
445 | uint16_t ISectStart = 0; |
446 | uint16_t Range = 0; |
447 | }; |
448 | |
449 | struct LocalVariableAddrGap { |
450 | uint16_t GapStartOffset = 0; |
451 | uint16_t Range = 0; |
452 | }; |
453 | |
454 | enum : uint16_t { MaxDefRange = 0xf000 }; |
455 | |
456 | // S_DEFRANGE |
457 | class DefRangeSym : public SymbolRecord { |
458 | static constexpr uint32_t RelocationOffset = 8; |
459 | |
460 | public: |
461 | explicit DefRangeSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
462 | explicit DefRangeSym(uint32_t RecordOffset) |
463 | : SymbolRecord(SymbolRecordKind::DefRangeSym), |
464 | RecordOffset(RecordOffset) {} |
465 | |
466 | uint32_t getRelocationOffset() const { |
467 | return RecordOffset + RelocationOffset; |
468 | } |
469 | |
470 | uint32_t Program = 0; |
471 | LocalVariableAddrRange Range; |
472 | std::vector<LocalVariableAddrGap> Gaps; |
473 | |
474 | uint32_t RecordOffset = 0; |
475 | }; |
476 | |
477 | // S_DEFRANGE_SUBFIELD |
478 | class DefRangeSubfieldSym : public SymbolRecord { |
479 | static constexpr uint32_t RelocationOffset = 12; |
480 | |
481 | public: |
482 | explicit DefRangeSubfieldSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
483 | explicit DefRangeSubfieldSym(uint32_t RecordOffset) |
484 | : SymbolRecord(SymbolRecordKind::DefRangeSubfieldSym), |
485 | RecordOffset(RecordOffset) {} |
486 | |
487 | uint32_t getRelocationOffset() const { |
488 | return RecordOffset + RelocationOffset; |
489 | } |
490 | |
491 | uint32_t Program = 0; |
492 | uint16_t OffsetInParent = 0; |
493 | LocalVariableAddrRange Range; |
494 | std::vector<LocalVariableAddrGap> Gaps; |
495 | |
496 | uint32_t RecordOffset = 0; |
497 | }; |
498 | |
499 | struct { |
500 | ulittle16_t ; |
501 | ulittle16_t ; |
502 | }; |
503 | |
504 | // S_DEFRANGE_REGISTER |
505 | class DefRangeRegisterSym : public SymbolRecord { |
506 | public: |
507 | explicit DefRangeRegisterSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
508 | explicit DefRangeRegisterSym(uint32_t RecordOffset) |
509 | : SymbolRecord(SymbolRecordKind::DefRangeRegisterSym), |
510 | RecordOffset(RecordOffset) {} |
511 | |
512 | uint32_t getRelocationOffset() const { return RecordOffset + sizeof(DefRangeRegisterHeader); } |
513 | |
514 | DefRangeRegisterHeader Hdr; |
515 | LocalVariableAddrRange Range; |
516 | std::vector<LocalVariableAddrGap> Gaps; |
517 | |
518 | uint32_t RecordOffset = 0; |
519 | }; |
520 | |
521 | struct { |
522 | ulittle16_t ; |
523 | ulittle16_t ; |
524 | ulittle32_t ; |
525 | }; |
526 | |
527 | // S_DEFRANGE_SUBFIELD_REGISTER |
528 | class DefRangeSubfieldRegisterSym : public SymbolRecord { |
529 | public: |
530 | explicit DefRangeSubfieldRegisterSym(SymbolRecordKind Kind) |
531 | : SymbolRecord(Kind) {} |
532 | explicit DefRangeSubfieldRegisterSym(uint32_t RecordOffset) |
533 | : SymbolRecord(SymbolRecordKind::DefRangeSubfieldRegisterSym), |
534 | RecordOffset(RecordOffset) {} |
535 | |
536 | uint32_t getRelocationOffset() const { return RecordOffset + sizeof(DefRangeSubfieldRegisterHeader); } |
537 | |
538 | DefRangeSubfieldRegisterHeader Hdr; |
539 | LocalVariableAddrRange Range; |
540 | std::vector<LocalVariableAddrGap> Gaps; |
541 | |
542 | uint32_t RecordOffset = 0; |
543 | }; |
544 | |
545 | struct { |
546 | little32_t ; |
547 | }; |
548 | |
549 | // S_DEFRANGE_FRAMEPOINTER_REL |
550 | class DefRangeFramePointerRelSym : public SymbolRecord { |
551 | static constexpr uint32_t RelocationOffset = 8; |
552 | |
553 | public: |
554 | explicit DefRangeFramePointerRelSym(SymbolRecordKind Kind) |
555 | : SymbolRecord(Kind) {} |
556 | explicit DefRangeFramePointerRelSym(uint32_t RecordOffset) |
557 | : SymbolRecord(SymbolRecordKind::DefRangeFramePointerRelSym), |
558 | RecordOffset(RecordOffset) {} |
559 | |
560 | uint32_t getRelocationOffset() const { |
561 | return RecordOffset + RelocationOffset; |
562 | } |
563 | |
564 | DefRangeFramePointerRelHeader Hdr; |
565 | LocalVariableAddrRange Range; |
566 | std::vector<LocalVariableAddrGap> Gaps; |
567 | |
568 | uint32_t RecordOffset = 0; |
569 | }; |
570 | |
571 | struct { |
572 | ulittle16_t ; |
573 | ulittle16_t ; |
574 | little32_t ; |
575 | }; |
576 | |
577 | // S_DEFRANGE_REGISTER_REL |
578 | class DefRangeRegisterRelSym : public SymbolRecord { |
579 | public: |
580 | explicit DefRangeRegisterRelSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
581 | explicit DefRangeRegisterRelSym(uint32_t RecordOffset) |
582 | : SymbolRecord(SymbolRecordKind::DefRangeRegisterRelSym), |
583 | RecordOffset(RecordOffset) {} |
584 | |
585 | // The flags implement this notional bitfield: |
586 | // uint16_t IsSubfield : 1; |
587 | // uint16_t Padding : 3; |
588 | // uint16_t OffsetInParent : 12; |
589 | enum : uint16_t { |
590 | IsSubfieldFlag = 1, |
591 | OffsetInParentShift = 4, |
592 | }; |
593 | |
594 | bool hasSpilledUDTMember() const { return Hdr.Flags & IsSubfieldFlag; } |
595 | uint16_t offsetInParent() const { return Hdr.Flags >> OffsetInParentShift; } |
596 | |
597 | uint32_t getRelocationOffset() const { return RecordOffset + sizeof(DefRangeRegisterRelHeader); } |
598 | |
599 | DefRangeRegisterRelHeader Hdr; |
600 | LocalVariableAddrRange Range; |
601 | std::vector<LocalVariableAddrGap> Gaps; |
602 | |
603 | uint32_t RecordOffset = 0; |
604 | }; |
605 | |
606 | // S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE |
607 | class DefRangeFramePointerRelFullScopeSym : public SymbolRecord { |
608 | public: |
609 | explicit DefRangeFramePointerRelFullScopeSym(SymbolRecordKind Kind) |
610 | : SymbolRecord(Kind) {} |
611 | explicit DefRangeFramePointerRelFullScopeSym(uint32_t RecordOffset) |
612 | : SymbolRecord(SymbolRecordKind::DefRangeFramePointerRelFullScopeSym), |
613 | RecordOffset(RecordOffset) {} |
614 | |
615 | int32_t Offset = 0; |
616 | |
617 | uint32_t RecordOffset = 0; |
618 | }; |
619 | |
620 | // S_BLOCK32 |
621 | class BlockSym : public SymbolRecord { |
622 | static constexpr uint32_t RelocationOffset = 16; |
623 | |
624 | public: |
625 | explicit BlockSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
626 | explicit BlockSym(uint32_t RecordOffset) |
627 | : SymbolRecord(SymbolRecordKind::BlockSym), RecordOffset(RecordOffset) {} |
628 | |
629 | uint32_t getRelocationOffset() const { |
630 | return RecordOffset + RelocationOffset; |
631 | } |
632 | |
633 | uint32_t Parent = 0; |
634 | uint32_t End = 0; |
635 | uint32_t CodeSize = 0; |
636 | uint32_t CodeOffset = 0; |
637 | uint16_t Segment = 0; |
638 | StringRef Name; |
639 | |
640 | uint32_t RecordOffset = 0; |
641 | }; |
642 | |
643 | // S_LABEL32 |
644 | class LabelSym : public SymbolRecord { |
645 | static constexpr uint32_t RelocationOffset = 4; |
646 | |
647 | public: |
648 | explicit LabelSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
649 | explicit LabelSym(uint32_t RecordOffset) |
650 | : SymbolRecord(SymbolRecordKind::LabelSym), RecordOffset(RecordOffset) {} |
651 | |
652 | uint32_t getRelocationOffset() const { |
653 | return RecordOffset + RelocationOffset; |
654 | } |
655 | |
656 | uint32_t CodeOffset = 0; |
657 | uint16_t Segment = 0; |
658 | ProcSymFlags Flags = ProcSymFlags::None; |
659 | StringRef Name; |
660 | |
661 | uint32_t RecordOffset = 0; |
662 | }; |
663 | |
664 | // S_OBJNAME |
665 | class ObjNameSym : public SymbolRecord { |
666 | public: |
667 | explicit ObjNameSym() : SymbolRecord(SymbolRecordKind::ObjNameSym) {} |
668 | explicit ObjNameSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
669 | explicit ObjNameSym(uint32_t RecordOffset) |
670 | : SymbolRecord(SymbolRecordKind::ObjNameSym), RecordOffset(RecordOffset) { |
671 | } |
672 | |
673 | uint32_t Signature = 0; |
674 | StringRef Name; |
675 | |
676 | uint32_t RecordOffset = 0; |
677 | }; |
678 | |
679 | // S_ENVBLOCK |
680 | class EnvBlockSym : public SymbolRecord { |
681 | public: |
682 | explicit EnvBlockSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
683 | explicit EnvBlockSym(uint32_t RecordOffset) |
684 | : SymbolRecord(SymbolRecordKind::EnvBlockSym), |
685 | RecordOffset(RecordOffset) {} |
686 | |
687 | std::vector<StringRef> Fields; |
688 | |
689 | uint32_t RecordOffset = 0; |
690 | }; |
691 | |
692 | // S_EXPORT |
693 | class ExportSym : public SymbolRecord { |
694 | public: |
695 | explicit ExportSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
696 | explicit ExportSym(uint32_t RecordOffset) |
697 | : SymbolRecord(SymbolRecordKind::ExportSym), RecordOffset(RecordOffset) {} |
698 | |
699 | uint16_t Ordinal = 0; |
700 | ExportFlags Flags = ExportFlags::None; |
701 | StringRef Name; |
702 | |
703 | uint32_t RecordOffset = 0; |
704 | }; |
705 | |
706 | // S_FILESTATIC |
707 | class FileStaticSym : public SymbolRecord { |
708 | public: |
709 | explicit FileStaticSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
710 | explicit FileStaticSym(uint32_t RecordOffset) |
711 | : SymbolRecord(SymbolRecordKind::FileStaticSym), |
712 | RecordOffset(RecordOffset) {} |
713 | |
714 | TypeIndex Index; |
715 | uint32_t ModFilenameOffset = 0; |
716 | LocalSymFlags Flags = LocalSymFlags::None; |
717 | StringRef Name; |
718 | |
719 | uint32_t RecordOffset = 0; |
720 | }; |
721 | |
722 | // S_COMPILE2 |
723 | class Compile2Sym : public SymbolRecord { |
724 | public: |
725 | explicit Compile2Sym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
726 | explicit Compile2Sym(uint32_t RecordOffset) |
727 | : SymbolRecord(SymbolRecordKind::Compile2Sym), |
728 | RecordOffset(RecordOffset) {} |
729 | |
730 | CompileSym2Flags Flags = CompileSym2Flags::None; |
731 | CPUType Machine; |
732 | uint16_t VersionFrontendMajor = 0; |
733 | uint16_t VersionFrontendMinor = 0; |
734 | uint16_t VersionFrontendBuild = 0; |
735 | uint16_t VersionBackendMajor = 0; |
736 | uint16_t VersionBackendMinor = 0; |
737 | uint16_t VersionBackendBuild = 0; |
738 | StringRef Version; |
739 | std::vector<StringRef> ; |
740 | |
741 | uint8_t getLanguage() const { return static_cast<uint32_t>(Flags) & 0xFF; } |
742 | uint32_t getFlags() const { return static_cast<uint32_t>(Flags) & ~0xFF; } |
743 | |
744 | uint32_t RecordOffset = 0; |
745 | }; |
746 | |
747 | // S_COMPILE3 |
748 | class Compile3Sym : public SymbolRecord { |
749 | public: |
750 | Compile3Sym() : SymbolRecord(SymbolRecordKind::Compile3Sym) {} |
751 | explicit Compile3Sym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
752 | explicit Compile3Sym(uint32_t RecordOffset) |
753 | : SymbolRecord(SymbolRecordKind::Compile3Sym), |
754 | RecordOffset(RecordOffset) {} |
755 | |
756 | CompileSym3Flags Flags = CompileSym3Flags::None; |
757 | CPUType Machine; |
758 | uint16_t VersionFrontendMajor = 0; |
759 | uint16_t VersionFrontendMinor = 0; |
760 | uint16_t VersionFrontendBuild = 0; |
761 | uint16_t VersionFrontendQFE = 0; |
762 | uint16_t VersionBackendMajor = 0; |
763 | uint16_t VersionBackendMinor = 0; |
764 | uint16_t VersionBackendBuild = 0; |
765 | uint16_t VersionBackendQFE = 0; |
766 | StringRef Version; |
767 | |
768 | void setLanguage(SourceLanguage Lang) { |
769 | Flags = CompileSym3Flags((uint32_t(Flags) & 0xFFFFFF00) | uint32_t(Lang)); |
770 | } |
771 | |
772 | SourceLanguage getLanguage() const { |
773 | return static_cast<SourceLanguage>(static_cast<uint32_t>(Flags) & 0xFF); |
774 | } |
775 | CompileSym3Flags getFlags() const { |
776 | return static_cast<CompileSym3Flags>(static_cast<uint32_t>(Flags) & ~0xFF); |
777 | } |
778 | |
779 | bool hasOptimizations() const { |
780 | return CompileSym3Flags::None != |
781 | (getFlags() & (CompileSym3Flags::PGO | CompileSym3Flags::LTCG)); |
782 | } |
783 | |
784 | uint32_t RecordOffset = 0; |
785 | }; |
786 | |
787 | // S_FRAMEPROC |
788 | class FrameProcSym : public SymbolRecord { |
789 | public: |
790 | explicit FrameProcSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
791 | explicit FrameProcSym(uint32_t RecordOffset) |
792 | : SymbolRecord(SymbolRecordKind::FrameProcSym), |
793 | RecordOffset(RecordOffset) {} |
794 | |
795 | uint32_t TotalFrameBytes = 0; |
796 | uint32_t PaddingFrameBytes = 0; |
797 | uint32_t OffsetToPadding = 0; |
798 | uint32_t BytesOfCalleeSavedRegisters = 0; |
799 | uint32_t OffsetOfExceptionHandler = 0; |
800 | uint16_t SectionIdOfExceptionHandler = 0; |
801 | FrameProcedureOptions Flags = FrameProcedureOptions::None; |
802 | |
803 | /// Extract the register this frame uses to refer to local variables. |
804 | RegisterId getLocalFramePtrReg(CPUType CPU) const { |
805 | return decodeFramePtrReg( |
806 | EncodedReg: EncodedFramePtrReg((uint32_t(Flags) >> 14U) & 0x3U), CPU); |
807 | } |
808 | |
809 | /// Extract the register this frame uses to refer to parameters. |
810 | RegisterId getParamFramePtrReg(CPUType CPU) const { |
811 | return decodeFramePtrReg( |
812 | EncodedReg: EncodedFramePtrReg((uint32_t(Flags) >> 16U) & 0x3U), CPU); |
813 | } |
814 | |
815 | uint32_t RecordOffset = 0; |
816 | |
817 | private: |
818 | }; |
819 | |
820 | // S_CALLSITEINFO |
821 | class CallSiteInfoSym : public SymbolRecord { |
822 | static constexpr uint32_t RelocationOffset = 4; |
823 | |
824 | public: |
825 | explicit CallSiteInfoSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
826 | explicit CallSiteInfoSym(uint32_t RecordOffset) |
827 | : SymbolRecord(SymbolRecordKind::CallSiteInfoSym) {} |
828 | |
829 | uint32_t getRelocationOffset() const { |
830 | return RecordOffset + RelocationOffset; |
831 | } |
832 | |
833 | uint32_t CodeOffset = 0; |
834 | uint16_t Segment = 0; |
835 | TypeIndex Type; |
836 | |
837 | uint32_t RecordOffset = 0; |
838 | }; |
839 | |
840 | // S_HEAPALLOCSITE |
841 | class HeapAllocationSiteSym : public SymbolRecord { |
842 | static constexpr uint32_t RelocationOffset = 4; |
843 | |
844 | public: |
845 | explicit HeapAllocationSiteSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
846 | explicit HeapAllocationSiteSym(uint32_t RecordOffset) |
847 | : SymbolRecord(SymbolRecordKind::HeapAllocationSiteSym), |
848 | RecordOffset(RecordOffset) {} |
849 | |
850 | uint32_t getRelocationOffset() const { |
851 | return RecordOffset + RelocationOffset; |
852 | } |
853 | |
854 | uint32_t CodeOffset = 0; |
855 | uint16_t Segment = 0; |
856 | uint16_t CallInstructionSize = 0; |
857 | TypeIndex Type; |
858 | |
859 | uint32_t RecordOffset = 0; |
860 | }; |
861 | |
862 | // S_FRAMECOOKIE |
863 | class FrameCookieSym : public SymbolRecord { |
864 | static constexpr uint32_t RelocationOffset = 4; |
865 | |
866 | public: |
867 | explicit FrameCookieSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
868 | explicit FrameCookieSym(uint32_t RecordOffset) |
869 | : SymbolRecord(SymbolRecordKind::FrameCookieSym) {} |
870 | |
871 | uint32_t getRelocationOffset() const { |
872 | return RecordOffset + RelocationOffset; |
873 | } |
874 | |
875 | uint32_t CodeOffset = 0; |
876 | uint16_t Register = 0; |
877 | FrameCookieKind CookieKind; |
878 | uint8_t Flags = 0; |
879 | |
880 | uint32_t RecordOffset = 0; |
881 | }; |
882 | |
883 | // S_UDT, S_COBOLUDT |
884 | class UDTSym : public SymbolRecord { |
885 | public: |
886 | explicit UDTSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
887 | explicit UDTSym(uint32_t RecordOffset) |
888 | : SymbolRecord(SymbolRecordKind::UDTSym) {} |
889 | |
890 | TypeIndex Type; |
891 | StringRef Name; |
892 | |
893 | uint32_t RecordOffset = 0; |
894 | }; |
895 | |
896 | // S_BUILDINFO |
897 | class BuildInfoSym : public SymbolRecord { |
898 | public: |
899 | explicit BuildInfoSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
900 | explicit BuildInfoSym(uint32_t RecordOffset) |
901 | : SymbolRecord(SymbolRecordKind::BuildInfoSym), |
902 | RecordOffset(RecordOffset) {} |
903 | |
904 | TypeIndex BuildId; |
905 | |
906 | uint32_t RecordOffset = 0; |
907 | }; |
908 | |
909 | // S_BPREL32 |
910 | class BPRelativeSym : public SymbolRecord { |
911 | public: |
912 | explicit BPRelativeSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
913 | explicit BPRelativeSym(uint32_t RecordOffset) |
914 | : SymbolRecord(SymbolRecordKind::BPRelativeSym), |
915 | RecordOffset(RecordOffset) {} |
916 | |
917 | int32_t Offset = 0; |
918 | TypeIndex Type; |
919 | StringRef Name; |
920 | |
921 | uint32_t RecordOffset = 0; |
922 | }; |
923 | |
924 | // S_REGREL32 |
925 | class RegRelativeSym : public SymbolRecord { |
926 | public: |
927 | explicit RegRelativeSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
928 | explicit RegRelativeSym(uint32_t RecordOffset) |
929 | : SymbolRecord(SymbolRecordKind::RegRelativeSym), |
930 | RecordOffset(RecordOffset) {} |
931 | |
932 | uint32_t Offset = 0; |
933 | TypeIndex Type; |
934 | RegisterId Register; |
935 | StringRef Name; |
936 | |
937 | uint32_t RecordOffset = 0; |
938 | }; |
939 | |
940 | // S_CONSTANT, S_MANCONSTANT |
941 | class ConstantSym : public SymbolRecord { |
942 | public: |
943 | explicit ConstantSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
944 | explicit ConstantSym(uint32_t RecordOffset) |
945 | : SymbolRecord(SymbolRecordKind::ConstantSym), |
946 | RecordOffset(RecordOffset) {} |
947 | |
948 | TypeIndex Type; |
949 | APSInt Value; |
950 | StringRef Name; |
951 | |
952 | uint32_t RecordOffset = 0; |
953 | }; |
954 | |
955 | // S_LDATA32, S_GDATA32, S_LMANDATA, S_GMANDATA |
956 | class DataSym : public SymbolRecord { |
957 | static constexpr uint32_t RelocationOffset = 8; |
958 | |
959 | public: |
960 | explicit DataSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
961 | explicit DataSym(uint32_t RecordOffset) |
962 | : SymbolRecord(SymbolRecordKind::DataSym), RecordOffset(RecordOffset) {} |
963 | |
964 | uint32_t getRelocationOffset() const { |
965 | return RecordOffset + RelocationOffset; |
966 | } |
967 | |
968 | TypeIndex Type; |
969 | uint32_t DataOffset = 0; |
970 | uint16_t Segment = 0; |
971 | StringRef Name; |
972 | |
973 | uint32_t RecordOffset = 0; |
974 | }; |
975 | |
976 | // S_LTHREAD32, S_GTHREAD32 |
977 | class ThreadLocalDataSym : public SymbolRecord { |
978 | static constexpr uint32_t RelocationOffset = 8; |
979 | |
980 | public: |
981 | explicit ThreadLocalDataSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
982 | explicit ThreadLocalDataSym(uint32_t RecordOffset) |
983 | : SymbolRecord(SymbolRecordKind::ThreadLocalDataSym), |
984 | RecordOffset(RecordOffset) {} |
985 | |
986 | uint32_t getRelocationOffset() const { |
987 | return RecordOffset + RelocationOffset; |
988 | } |
989 | |
990 | TypeIndex Type; |
991 | uint32_t DataOffset = 0; |
992 | uint16_t Segment = 0; |
993 | StringRef Name; |
994 | |
995 | uint32_t RecordOffset = 0; |
996 | }; |
997 | |
998 | // S_UNAMESPACE |
999 | class UsingNamespaceSym : public SymbolRecord { |
1000 | public: |
1001 | explicit UsingNamespaceSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
1002 | explicit UsingNamespaceSym(uint32_t RecordOffset) |
1003 | : SymbolRecord(SymbolRecordKind::UsingNamespaceSym), |
1004 | RecordOffset(RecordOffset) {} |
1005 | |
1006 | StringRef Name; |
1007 | |
1008 | uint32_t RecordOffset = 0; |
1009 | }; |
1010 | |
1011 | // S_ANNOTATION |
1012 | class AnnotationSym : public SymbolRecord { |
1013 | public: |
1014 | explicit AnnotationSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {} |
1015 | explicit AnnotationSym(uint32_t RecordOffset) |
1016 | : SymbolRecord(SymbolRecordKind::AnnotationSym), |
1017 | RecordOffset(RecordOffset) {} |
1018 | |
1019 | uint32_t CodeOffset = 0; |
1020 | uint16_t Segment = 0; |
1021 | std::vector<StringRef> Strings; |
1022 | |
1023 | uint32_t RecordOffset = 0; |
1024 | }; |
1025 | |
1026 | Expected<CVSymbol> readSymbolFromStream(BinaryStreamRef Stream, |
1027 | uint32_t Offset); |
1028 | |
1029 | } // end namespace codeview |
1030 | } // end namespace llvm |
1031 | |
1032 | #endif // LLVM_DEBUGINFO_CODEVIEW_SYMBOLRECORD_H |
1033 | |