LLVM: lib/DebugInfo/DWARF/DWARFDebugLine.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
21#include
22#include
23#include
24#include
25#include
26#include
27
28using namespace llvm;
29using namespace dwarf;
30
32
33namespace {
34
35struct ContentDescriptor {
38};
39
41
42}
43
45 return Version >= 2 && Version <= 5;
46}
47
50 switch (ContentType) {
51 case dwarf::DW_LNCT_timestamp:
53 break;
54 case dwarf::DW_LNCT_size:
56 break;
57 case dwarf::DW_LNCT_MD5:
59 break;
60 case dwarf::DW_LNCT_LLVM_source:
62 break;
63 default:
64
65
66 break;
67 }
68}
69
71
74 assert(DwarfVersion != 0 &&
75 "line table prologue has no dwarf version information");
76 if (DwarfVersion >= 5)
77 return FileIndex < FileNames.size();
78 return FileIndex != 0 && FileIndex <= FileNames.size();
79}
80
81std::optional<uint64_t>
84 return std::nullopt;
86 assert(DwarfVersion != 0 &&
87 "line table prologue has no dwarf version information");
88
89 if (DwarfVersion >= 5)
92}
93
97 assert(DwarfVersion != 0 &&
98 "line table prologue has no dwarf version information");
99
100 if (DwarfVersion >= 5)
103}
104
116
120 return;
122 OS << "Line table prologue:\n"
123 << format(" total_length: 0x%0*" PRIx64 "\n", OffsetDumpWidth,
128 return;
132 OS << format(" prologue_length: 0x%0*" PRIx64 "\n", OffsetDumpWidth,
140
142 OS << formatv("standard_opcode_lengths[{0}] = {1}\n",
145
147
150 OS << format("include_directories[%3u] = ", I + DirBase);
152 OS << '\n';
153 }
154 }
155
157
161 OS << format("file_names[%3u]:\n", I + FileBase);
162 OS << " name: ";
163 FileEntry.Name.dump(OS, DumpOptions);
164 OS << '\n' << format(" dir_index: %" PRIu64 "\n", FileEntry.DirIdx);
166 OS << " md5_checksum: " << FileEntry.Checksum.digest() << '\n';
168 OS << format(" mod_time: 0x%8.8" PRIx64 "\n", FileEntry.ModTime);
170 OS << format(" length: 0x%8.8" PRIx64 "\n", FileEntry.Length);
173 if (!Source)
175 else if ((*Source)[0]) {
176 OS << " source: ";
177 FileEntry.Source.dump(OS, DumpOptions);
178 OS << '\n';
179 }
180 }
181 }
182 }
183}
184
185
190 std::vector &IncludeDirectories,
191 std::vectorDWARFDebugLine::FileNameEntry &FileNames) {
192 while (true) {
195 if (Err) {
198 "include directories table was not null "
199 "terminated before the end of the prologue");
200 }
202 break;
205 IncludeDirectories.push_back(Dir);
206 }
207
210
211 while (true) {
214 if (!Err && Name.empty())
215 break;
216
218 FileEntry.Name =
220 FileEntry.DirIdx = DebugLineData.getULEB128(OffsetPtr, &Err);
222 FileEntry.Length = DebugLineData.getULEB128(OffsetPtr, &Err);
223
224 if (Err) {
228 "file names table was not null terminated before "
229 "the end of the prologue");
230 }
231 FileNames.push_back(FileEntry);
232 }
233
235}
236
237
238
239
240static llvm::Expected
244 ContentDescriptors Descriptors;
245 int FormatCount = DebugLineData.getU8(OffsetPtr, &Err);
246 bool HasPath = false;
247 for (int I = 0; I != FormatCount && !Err; ++I) {
248 ContentDescriptor Descriptor;
249 Descriptor.Type =
252 if (Descriptor.Type == dwarf::DW_LNCT_path)
253 HasPath = true;
254 if (ContentTypes)
256 Descriptors.push_back(Descriptor);
257 }
258
259 if (Err)
261 "failed to parse entry content descriptors: %s",
263
264 if (!HasPath)
266 "failed to parse entry content descriptions"
267 " because no path was found");
268 return Descriptors;
269}
270
276 std::vector &IncludeDirectories,
277 std::vectorDWARFDebugLine::FileNameEntry &FileNames) {
278
281 if (!DirDescriptors)
282 return DirDescriptors.takeError();
283
284
286 for (uint64_t I = 0; I != DirEntryCount; ++I) {
287 for (auto Descriptor : *DirDescriptors) {
289 switch (Descriptor.Type) {
290 case DW_LNCT_path:
291 if (.extractValue(DebugLineData, OffsetPtr, FormParams, &Ctx, U))
293 "failed to parse directory entry because "
294 "extracting the form value failed");
295 IncludeDirectories.push_back(Value);
296 break;
297 default:
298 if (.skipValue(DebugLineData, OffsetPtr, FormParams))
300 "failed to parse directory entry because "
301 "skipping the form value failed");
302 }
303 }
304 }
305
306
309 if (!FileDescriptors)
310 return FileDescriptors.takeError();
311
312
314 for (uint64_t I = 0; I != FileEntryCount; ++I) {
316 for (auto Descriptor : *FileDescriptors) {
318 if (.extractValue(DebugLineData, OffsetPtr, FormParams, &Ctx, U))
320 "failed to parse file entry because "
321 "extracting the form value failed");
322 switch (Descriptor.Type) {
323 case DW_LNCT_path:
325 break;
326 case DW_LNCT_LLVM_source:
328 break;
329 case DW_LNCT_directory_index:
330 FileEntry.DirIdx = *Value.getAsUnsignedConstant();
331 break;
332 case DW_LNCT_timestamp:
333 FileEntry.ModTime = *Value.getAsUnsignedConstant();
334 break;
335 case DW_LNCT_size:
336 FileEntry.Length = *Value.getAsUnsignedConstant();
337 break;
338 case DW_LNCT_MD5:
339 if (.getAsBlock() || Value.getAsBlock()->size() != 16)
342 "failed to parse file entry because the MD5 hash is invalid");
345 break;
346 default:
347 break;
348 }
349 }
350 FileNames.push_back(FileEntry);
351 }
353}
354
362
367 const uint64_t PrologueOffset = *OffsetPtr;
368
373
374 DebugLineData =
378
379
380
381 *OffsetPtr = Cursor.tell();
384 "parsing line table prologue at offset 0x%8.8" PRIx64
385 ": unsupported version %" PRIu16,
387 }
388
393 if (Cursor) {
394 if (DataAddrSize == 0) {
395 if (PrologueAddrSize != 4 && PrologueAddrSize != 8) {
398 "parsing line table prologue at offset 0x%8.8" PRIx64
399 ": invalid address size %" PRIu8,
400 PrologueOffset, PrologueAddrSize));
401 }
402 } else if (DataAddrSize != PrologueAddrSize) {
405 "parsing line table prologue at offset 0x%8.8" PRIx64 ": address "
406 "size %" PRIu8 " doesn't match architecture address size %" PRIu8,
407 PrologueOffset, PrologueAddrSize, DataAddrSize));
408 }
409 }
411 }
412
416 DebugLineData = DWARFDataExtractor(DebugLineData, EndPrologueOffset);
424
426
427
428
431 "parsing line table prologue at offset 0x%8.8" PRIx64
432 " found opcode base of 0. Assuming no standard opcodes",
433 PrologueOffset));
434 } else if (Cursor) {
439 }
440 }
441
442 *OffsetPtr = Cursor.tell();
443
444
445
446 if (!Cursor)
449 "parsing line table prologue at offset 0x%8.8" PRIx64 ": %s",
450 PrologueOffset, toString(Cursor.takeError()).c_str());
451
458 if (E) {
462 "parsing line table prologue at 0x%8.8" PRIx64
463 " found an invalid directory or file table description at"
464 " 0x%8.8" PRIx64,
465 PrologueOffset, *OffsetPtr),
466 std::move(E)));
468 }
469
470 assert(*OffsetPtr <= EndPrologueOffset);
471 if (*OffsetPtr != EndPrologueOffset) {
474 "unknown data in line table prologue at offset 0x%8.8" PRIx64
475 ": parsing ended (at offset 0x%8.8" PRIx64
476 ") before reaching the prologue end at offset 0x%8.8" PRIx64,
477 PrologueOffset, *OffsetPtr, EndPrologueOffset));
478 }
480}
481
483
490
499 IsStmt = DefaultIsStmt;
505}
506
509 << "Address Line Column File ISA Discriminator OpIndex "
510 "Flags\n";
512 << "------------------ ------ ------ ------ --- ------------- ------- "
513 "-------------\n";
514}
515
524
526
536
538
541 Prologue.dump(OS, DumpOptions);
542
543 if (.empty()) {
544 OS << '\n';
546 for (const Row &R : Rows) {
547 R.dump(OS);
548 }
549 }
550
551
552
553 OS << '\n';
554}
555
561
562DWARFDebugLine::ParsingState::ParsingState(
566
567void DWARFDebugLine::ParsingState::resetRowAndSequence(uint64_t Offset) {
568 Row.reset(LineTable->Prologue.DefaultIsStmt);
569 Sequence.reset();
570 Sequence.StmtSeqOffset = Offset;
571}
572
573void DWARFDebugLine::ParsingState::appendRowToMatrix() {
574 unsigned RowNumber = LineTable->Rows.size();
575 if (Sequence.Empty) {
576
577 Sequence.Empty = false;
578 Sequence.LowPC = Row.Address.Address;
579 Sequence.FirstRowIndex = RowNumber;
580 }
583
590 }
592}
593
594const DWARFDebugLine::LineTable *
596 LineTableConstIter Pos = LineTableMap.find(Offset);
597 if (Pos != LineTableMap.end())
598 return &Pos->second;
599 return nullptr;
600}
601
607 "offset 0x%8.8" PRIx64
608 " is not a valid debug line section offset",
610
611 std::pair<LineTableIter, bool> Pos =
612 LineTableMap.insert(LineTableMapTy::value_type(Offset, LineTable()));
613 LineTable *LT = &Pos.first->second;
614 if (Pos.second) {
616 LT->parse(DebugLineData, &Offset, Ctx, U, RecoverableErrorHandler))
617 return std::move(Err);
618 return LT;
619 }
620 return LT;
621}
622
624 LineTableMap.erase(Offset);
625}
626
629 if (Opcode < OpcodeBase)
631 return "special";
632}
633
634DWARFDebugLine::ParsingState::AddrOpIndexDelta
635DWARFDebugLine::ParsingState::advanceAddrOpIndex(uint64_t OperationAdvance,
636 uint8_t Opcode,
637 uint64_t OpcodeOffset) {
639
640
641
646 "line table program at offset 0x%8.8" PRIx64
647 " contains a %s opcode at offset 0x%8.8" PRIx64
648 ", but the prologue maximum_operations_per_instruction value is 0"
649 ", which is invalid. Assuming a value of 1 instead",
650 LineTableOffset, OpcodeName.data(), OpcodeOffset));
651
652
653
654
655
659 "line table program at offset 0x%8.8" PRIx64
660 " contains a %s opcode at offset 0x%8.8" PRIx64
661 ", but the prologue maximum_operations_per_instruction value is %" PRId8
662 ", which is experimentally supported, so line number information "
663 "may be incorrect",
664 LineTableOffset, OpcodeName.data(), OpcodeOffset,
669 "line table program at offset 0x%8.8" PRIx64
670 " contains a %s opcode at offset 0x%8.8" PRIx64
671 ", but the prologue minimum_instruction_length value "
672 "is 0, which prevents any address advancing",
673 LineTableOffset, OpcodeName.data(), OpcodeOffset));
674 ReportAdvanceAddrProblem = false;
675
676
677
678
679
680
681
682
683
684
685
686
687 uint8_t MaxOpsPerInst =
689
690 uint64_t AddrOffset = ((Row.OpIndex + OperationAdvance) / MaxOpsPerInst) *
693
696 int16_t OpIndexDelta = static_cast<int16_t>(Row.OpIndex) - PrevOpIndex;
697
698 return {AddrOffset, OpIndexDelta};
699}
700
701DWARFDebugLine::ParsingState::OpcodeAdvanceResults
702DWARFDebugLine::ParsingState::advanceForOpcode(uint8_t Opcode,
703 uint64_t OpcodeOffset) {
704 assert(Opcode == DW_LNS_const_add_pc ||
707 StringRef OpcodeName =
711 "line table program at offset 0x%8.8" PRIx64
712 " contains a %s opcode at offset 0x%8.8" PRIx64
713 ", but the prologue line_range value is 0. The "
714 "address and line will not be adjusted",
715 LineTableOffset, OpcodeName.data(), OpcodeOffset));
716 ReportBadLineRange = false;
717 }
718
719 uint8_t OpcodeValue = Opcode;
720 if (Opcode == DW_LNS_const_add_pc)
721 OpcodeValue = 255;
723 uint64_t OperationAdvance =
726 : 0;
727 AddrOpIndexDelta Advance =
728 advanceAddrOpIndex(OperationAdvance, Opcode, OpcodeOffset);
729 return {Advance.AddrOffset, Advance.OpIndexDelta, AdjustedOpcode};
730}
731
732DWARFDebugLine::ParsingState::SpecialOpcodeDelta
733DWARFDebugLine::ParsingState::handleSpecialOpcode(uint8_t Opcode,
734 uint64_t OpcodeOffset) {
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766 DWARFDebugLine::ParsingState::OpcodeAdvanceResults AddrAdvanceResult =
767 advanceForOpcode(Opcode, OpcodeOffset);
768 int32_t LineOffset = 0;
770 LineOffset =
774 return {AddrAdvanceResult.AddrDelta, LineOffset,
776}
777
778
779
780template
784 if (Cursor)
786 return std::nullopt;
787}
788
794 assert((OS || ) && "cannot have verbose output without stream");
795 const uint64_t DebugLineOffset = *OffsetPtr;
796
798
799 Error PrologueErr =
800 Prologue.parse(DebugLineData, OffsetPtr, RecoverableErrorHandler, Ctx, U);
801
802 if (OS) {
805 Prologue.dump(*OS, DumpOptions);
806 }
807
808 if (PrologueErr) {
809
810
811 if (OS)
812 *OS << "\n";
813 return PrologueErr;
814 }
815
818 ProgramLength)) {
819 assert(DebugLineData.size() > DebugLineOffset &&
820 "prologue parsing should handle invalid offset");
821 uint64_t BytesRemaining = DebugLineData.size() - DebugLineOffset;
822 RecoverableErrorHandler(
824 "line table program with offset 0x%8.8" PRIx64
825 " has length 0x%8.8" PRIx64 " but only 0x%8.8" PRIx64
826 " bytes are available",
827 DebugLineOffset, ProgramLength, BytesRemaining));
828
829 ProgramLength = BytesRemaining;
830 }
831
832
833
834 const uint64_t EndOffset = DebugLineOffset + ProgramLength;
836
837
840 else
843
844 ParsingState State(this, DebugLineOffset, RecoverableErrorHandler);
845
846 *OffsetPtr = DebugLineOffset + Prologue.getLength();
847 if (OS && *OffsetPtr < EndOffset) {
848 *OS << '\n';
850 }
851
852
853 State.resetRowAndSequence(*OffsetPtr);
854
855 bool TombstonedAddress = false;
856 auto EmitRow = [&] {
857 if (!TombstonedAddress) {
859 *OS << "\n";
861 }
862 if (OS)
863 State.Row.dump(*OS);
864 State.appendRowToMatrix();
865 }
866 };
867 while (*OffsetPtr < EndOffset) {
869
871 *OS << format("0x%08.08" PRIx64 ": ", *OffsetPtr);
872
873 uint64_t OpcodeOffset = *OffsetPtr;
875 size_t RowCount = Rows.size();
876
878 *OS << format("%02.02" PRIx8 " ", Opcode);
879
880 if (Opcode == 0) {
881
882
884 uint64_t ExtOffset = Cursor.tell();
885
886
887 if (Len == 0) {
889 *OS << "Badly formed extended line op (length 0)\n";
890 if (!Cursor) {
892 *OS << "\n";
893 RecoverableErrorHandler(Cursor.takeError());
894 }
895 *OffsetPtr = Cursor.tell();
896 continue;
897 }
898
900
901
902 uint64_t OperandOffset = Cursor.tell();
905 switch (SubOpcode) {
906 case DW_LNE_end_sequence:
907
908
909
910
911
912
913
914 State.Row.EndSequence = true;
915
916
917
918 EmitRow();
919
920
921 State.resetRowAndSequence(Cursor.tell());
922 break;
923
924 case DW_LNE_set_address:
925
926
927
928
929
930
931
932
933
934
935 {
937 uint64_t OpcodeAddressSize = Len - 1;
938 if (ExtractorAddressSize != OpcodeAddressSize &&
939 ExtractorAddressSize != 0)
942 "mismatching address size at offset 0x%8.8" PRIx64
943 " expected 0x%2.2" PRIx8 " found 0x%2.2" PRIx64,
944 ExtOffset, ExtractorAddressSize, Len - 1));
945
946
947
948
949 if (OpcodeAddressSize != 1 && OpcodeAddressSize != 2 &&
950 OpcodeAddressSize != 4 && OpcodeAddressSize != 8) {
953 "address size 0x%2.2" PRIx64
954 " of DW_LNE_set_address opcode at offset 0x%8.8" PRIx64
955 " is unsupported",
956 OpcodeAddressSize, ExtOffset));
957 TableData.skip(Cursor, OpcodeAddressSize);
958 } else {
961 Cursor, &State.Row.Address.SectionIndex);
962 State.Row.OpIndex = 0;
963
966 TombstonedAddress = State.Row.Address.Address == Tombstone;
967
968
969 if (ExtractorAddressSize != 0)
971 }
972
974 *OS << " (";
976 State.Row.Address.Address);
977 *OS << ')';
978 }
979 }
980 break;
981
982 case DW_LNE_define_file:
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003 {
1005 const char *Name = TableData.getCStr(Cursor);
1006 FileEntry.Name =
1011 Prologue.FileNames.push_back(FileEntry);
1013 *OS << " (" << Name << ", dir=" << FileEntry.DirIdx << ", mod_time="
1014 << format("(0x%16.16" PRIx64 ")", FileEntry.ModTime)
1015 << ", length=" << FileEntry.Length << ")";
1016 }
1017 break;
1018
1019 case DW_LNE_set_discriminator:
1020 State.Row.Discriminator = TableData.getULEB128(Cursor);
1022 *OS << " (" << State.Row.Discriminator << ")";
1023 break;
1024
1025 default:
1027 *OS << format("Unrecognized extended op 0x%02.02" PRIx8, SubOpcode)
1028 << format(" length %" PRIx64, Len);
1029
1030
1031 TableData.skip(Cursor, Len - 1);
1032 break;
1033 }
1034
1035
1036
1037
1038 uint64_t End = ExtOffset + Len;
1039 if (Cursor && Cursor.tell() != End)
1042 "unexpected line op length at offset 0x%8.8" PRIx64
1043 " expected 0x%2.2" PRIx64 " found 0x%2.2" PRIx64,
1044 ExtOffset, Len, Cursor.tell() - ExtOffset));
1045 if (!Cursor && Verbose) {
1048 if (ByteCursor) {
1049 *OS << " (";
1050 do {
1051 *OS << format(" %2.2" PRIx8, Byte);
1052 Byte = TableData.getU8(ByteCursor);
1053 } while (ByteCursor);
1054 *OS << ")";
1055 }
1056
1057
1058
1059
1061 }
1062 *OffsetPtr = End;
1063 } else if (Opcode < Prologue.OpcodeBase) {
1066 switch (Opcode) {
1067
1068 case DW_LNS_copy:
1069
1070
1071 EmitRow();
1072 break;
1073
1074 case DW_LNS_advance_pc:
1075
1076
1077
1078 if (std::optional<uint64_t> Operand =
1081 State.advanceAddrOpIndex(*Operand, Opcode, OpcodeOffset);
1083 *OS << " (addr += " << Advance.AddrOffset
1084 << ", op-index += " << Advance.OpIndexDelta << ")";
1085 }
1086 break;
1087
1088 case DW_LNS_advance_line:
1089
1090
1091 {
1092 int64_t LineDelta = TableData.getSLEB128(Cursor);
1093 if (Cursor) {
1094 State.Row.Line += LineDelta;
1096 *OS << " (" << State.Row.Line << ")";
1097 }
1098 }
1099 break;
1100
1101 case DW_LNS_set_file:
1102
1103
1104 if (std::optional<uint16_t> File =
1106 State.Row.File = *File;
1108 *OS << " (" << State.Row.File << ")";
1109 }
1110 break;
1111
1112 case DW_LNS_set_column:
1113
1114
1115 if (std::optional<uint16_t> Column =
1117 State.Row.Column = *Column;
1119 *OS << " (" << State.Row.Column << ")";
1120 }
1121 break;
1122
1123 case DW_LNS_negate_stmt:
1124
1125
1126 State.Row.IsStmt = !State.Row.IsStmt;
1127 break;
1128
1129 case DW_LNS_set_basic_block:
1130
1131
1132 State.Row.BasicBlock = true;
1133 break;
1134
1135 case DW_LNS_const_add_pc:
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147 {
1149 State.advanceForOpcode(Opcode, OpcodeOffset);
1151 *OS << format(" (addr += 0x%16.16" PRIx64 ", op-index += %" PRIu8
1152 ")",
1154 }
1155 break;
1156
1157 case DW_LNS_fixed_advance_pc:
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168 {
1170 if (Cursor) {
1171 State.Row.Address.Address += PCOffset;
1172 State.Row.OpIndex = 0;
1174 *OS << format(" (addr += 0x%4.4" PRIx16 ", op-index = 0)",
1175 PCOffset);
1176 }
1177 }
1178 break;
1179
1180 case DW_LNS_set_prologue_end:
1181
1182
1183 State.Row.PrologueEnd = true;
1184 break;
1185
1186 case DW_LNS_set_epilogue_begin:
1187
1188
1189 State.Row.EpilogueBegin = true;
1190 break;
1191
1192 case DW_LNS_set_isa:
1193
1194
1195 if (std::optional<uint8_t> Isa =
1197 State.Row.Isa = *Isa;
1199 *OS << " (" << (uint64_t)State.Row.Isa << ")";
1200 }
1201 break;
1202
1203 default:
1204
1205
1206
1207 {
1208 assert(Opcode - 1U < Prologue.StandardOpcodeLengths.size());
1210 *OS << "Unrecognized standard opcode";
1211 uint8_t OpcodeLength = Prologue.StandardOpcodeLengths[Opcode - 1];
1212 std::vector<uint64_t> Operands;
1213 for (uint8_t I = 0; I < OpcodeLength; ++I) {
1214 if (std::optional<uint64_t> Value =
1216 Operands.push_back(*Value);
1217 else
1218 break;
1219 }
1220 if (Verbose && !Operands.empty()) {
1221 *OS << " (operands: ";
1222 bool First = true;
1225 *OS << ", ";
1227 *OS << format("0x%16.16" PRIx64, Value);
1228 }
1230 *OS << ')';
1231 }
1232 }
1233 break;
1234 }
1235
1236 *OffsetPtr = Cursor.tell();
1237 } else {
1238
1240 State.handleSpecialOpcode(Opcode, OpcodeOffset);
1241
1243 *OS << "address += " << Delta.Address << ", line += " << Delta.Line
1244 << ", op-index += " << Delta.OpIndex;
1245 EmitRow();
1246 *OffsetPtr = Cursor.tell();
1247 }
1248
1249
1250
1252 *OS << "\n";
1253
1254
1255
1256
1257
1258 if (!Cursor && Opcode != 0) {
1260 *OS << "\n";
1261 return Cursor.takeError();
1262 }
1263
1264 if (!Cursor)
1265 RecoverableErrorHandler(Cursor.takeError());
1266 }
1267
1268 if (!State.Sequence.Empty)
1271 "last sequence in debug line table at offset 0x%8.8" PRIx64
1272 " is not terminated",
1273 DebugLineOffset));
1274
1275
1278
1279
1280
1281
1282
1283
1284
1285 }
1286
1287
1288
1289 if (OS)
1290 *OS << "\n";
1291
1293}
1294
1295uint32_t DWARFDebugLine::LineTable::findRowInSeq(
1299 return UnknownRowIndex;
1301
1302
1303
1304
1305
1306
1307
1308
1311 RowIter FirstRow = Rows.begin() + Seq.FirstRowIndex;
1312 RowIter LastRow = Rows.begin() + Seq.LastRowIndex;
1315 RowIter RowPos = std::upper_bound(FirstRow + 1, LastRow - 1, Row,
1317 1;
1319 return RowPos - Rows.begin();
1320}
1321
1324 bool *IsApproximateLine) const {
1325
1326
1327 uint32_t Result = lookupAddressImpl(Address, IsApproximateLine);
1328
1331 return Result;
1332
1333
1335 return lookupAddressImpl(Address, IsApproximateLine);
1336}
1337
1340 bool *IsApproximateLine) const {
1341 assert((!IsApproximateLine || !*IsApproximateLine) &&
1342 "Make sure IsApproximateLine is appropriately "
1343 "initialized, if provided");
1344
1350 if (It == Sequences.end() || It->SectionIndex != Address.SectionIndex)
1351 return UnknownRowIndex;
1352
1354 if (RowIndex == UnknownRowIndex || !IsApproximateLine)
1355 return RowIndex;
1356
1357
1358 uint32_t ApproxRowIndex = RowIndex;
1359
1360 for (; ApproxRowIndex >= It->FirstRowIndex; --ApproxRowIndex) {
1361 if (Rows[ApproxRowIndex].Line)
1362 return ApproxRowIndex;
1363 *IsApproximateLine = true;
1364 }
1365
1366 if (ApproxRowIndex < It->FirstRowIndex)
1367 *IsApproximateLine = false;
1368
1369 return RowIndex;
1370}
1371
1374 std::vector<uint32_t> &Result,
1375 std::optional<uint64_t> StmtSequenceOffset) const {
1376
1377
1378 if (lookupAddressRangeImpl(Address, Size, Result, StmtSequenceOffset))
1379 return true;
1380
1382 return false;
1383
1384
1386 return lookupAddressRangeImpl(Address, Size, Result, StmtSequenceOffset);
1387}
1388
1389bool DWARFDebugLine::LineTable::lookupAddressRangeImpl(
1391 std::vector<uint32_t> &Result,
1392 std::optional<uint64_t> StmtSequenceOffset) const {
1393 if (Sequences.empty())
1394 return false;
1396
1400 SequenceIter LastSeq = Sequences.end();
1401 SequenceIter SeqPos;
1402
1403 if (StmtSequenceOffset) {
1404
1405
1406 SeqPos = std::find_if(Sequences.begin(), LastSeq,
1408 return S.StmtSeqOffset == *StmtSequenceOffset;
1409 });
1410
1411
1412 if (SeqPos == LastSeq)
1413 return false;
1414
1415
1416
1417 LastSeq = SeqPos + 1;
1418 } else {
1419
1420 SeqPos = std::upper_bound(Sequences.begin(), LastSeq, Sequence,
1422 if (SeqPos == LastSeq)
1423 return false;
1424 }
1425
1426
1427 if (!SeqPos->containsPC(Address))
1428 return false;
1429
1430 SequenceIter StartPos = SeqPos;
1431
1432
1433 while (SeqPos != LastSeq && SeqPos->LowPC < EndAddr) {
1435
1436
1438 if (SeqPos == StartPos)
1439 FirstRowIndex = findRowInSeq(CurSeq, Address);
1440
1441
1443 findRowInSeq(CurSeq, {EndAddr - 1, Address.SectionIndex});
1444 if (LastRowIndex == UnknownRowIndex)
1446
1447 assert(FirstRowIndex != UnknownRowIndex);
1448 assert(LastRowIndex != UnknownRowIndex);
1449
1450 for (uint32_t I = FirstRowIndex; I <= LastRowIndex; ++I) {
1452 }
1453
1454 ++SeqPos;
1455 }
1456
1457 return true;
1458}
1459
1460std::optional
1461DWARFDebugLine::LineTable::getSourceByIndex(uint64_t FileIndex,
1462 FileLineInfoKind Kind) const {
1464 return std::nullopt;
1467 return StringRef(*E);
1468 return std::nullopt;
1469}
1470
1478
1482 if (Kind == FileLineInfoKind::None || (FileIndex))
1483 return false;
1486 if (!E)
1487 return false;
1489 if (Kind == FileLineInfoKind::RawValue ||
1491 Result = std::string(FileName);
1492 return true;
1493 }
1494 if (Kind == FileLineInfoKind::BaseNameOnly) {
1496 return true;
1497 }
1498
1501
1503
1504
1505 if ((Entry.DirIdx != 0 || Kind != FileLineInfoKind::RelativeFilePath) &&
1508 } else {
1511 }
1512
1513
1514
1515
1516
1517 if (Kind == FileLineInfoKind::AbsoluteFilePath &&
1518 (getVersion() < 5 || Entry.DirIdx != 0) && !CompDir.empty() &&
1521
1522 assert((Kind == FileLineInfoKind::AbsoluteFilePath ||
1523 Kind == FileLineInfoKind::RelativeFilePath) &&
1524 "invalid FileLineInfo Kind");
1525
1526
1528 Result = std::string(FilePath);
1529 return true;
1530}
1531
1534 FileLineInfoKind Kind, DILineInfo &Result) const {
1535
1538 if (RowIndex == -1U)
1539 return false;
1540
1541 const auto &Row = Rows[RowIndex];
1543 return false;
1547 Result.Source = getSourceByIndex(Row.File, Kind);
1548 return true;
1549}
1550
1552 const FileNameEntry &Entry, std::string &Directory) const {
1553 if (Prologue.getVersion() >= 5) {
1554 if (Entry.DirIdx < Prologue.IncludeDirectories.size()) {
1555 Directory =
1557 return true;
1558 }
1559 return false;
1560 }
1561 if (0 < Entry.DirIdx && Entry.DirIdx <= Prologue.IncludeDirectories.size()) {
1562 Directory =
1564 return true;
1565 }
1566 return false;
1567}
1568
1569
1570
1571
1572
1576 for (const auto &U : Units)
1577 if (auto CUDIE = U->getUnitDIE())
1578 if (auto StmtOffset = toSectionOffset(CUDIE.find(DW_AT_stmt_list)))
1579 LineToUnit.insert(std::make_pair(*StmtOffset, &*U));
1580 return LineToUnit;
1581}
1582
1586 : DebugLineData(Data), Context(C) {
1588 if (!DebugLineData.isValidOffset(Offset))
1589 Done = true;
1590}
1591
1595
1600 assert(DebugLineData.isValidOffset(Offset) &&
1601 "parsing should have terminated");
1602 DWARFUnit *U = prepareToParse(Offset);
1603 uint64_t OldOffset = Offset;
1605 if (Error Err = LT.parse(DebugLineData, &Offset, Context, U,
1606 RecoverableErrorHandler, OS, Verbose))
1607 UnrecoverableErrorHandler(std::move(Err));
1608 moveToNextTable(OldOffset, LT.Prologue);
1609 return LT;
1610}
1611
1615 assert(DebugLineData.isValidOffset(Offset) &&
1616 "parsing should have terminated");
1617 DWARFUnit *U = prepareToParse(Offset);
1618 uint64_t OldOffset = Offset;
1620 if (Error Err = LT.Prologue.parse(DebugLineData, &Offset,
1621 RecoverableErrorHandler, Context, U))
1622 UnrecoverableErrorHandler(std::move(Err));
1623 moveToNextTable(OldOffset, LT.Prologue);
1624}
1625
1628 auto It = LineToUnit.find(Offset);
1629 if (It != LineToUnit.end())
1630 U = It->second;
1631 DebugLineData.setAddressSize(U ? U->getAddressByteSize() : 0);
1632 return U;
1633}
1634
1635bool DWARFDebugLine::SectionParser::hasValidVersion(uint64_t Offset) {
1638 DWARFDataExtractor HeaderData(DebugLineData, Cursor.tell() + TotalLength);
1640 if (!Cursor) {
1641
1642
1643
1645 return false;
1646 }
1648}
1649
1650void DWARFDebugLine::SectionParser::moveToNextTable(uint64_t OldOffset,
1652
1653
1654
1655 if (.totalLengthIsValid()) {
1656 Done = true;
1657 return;
1658 }
1659
1660 Offset = OldOffset + P.TotalLength + P.sizeofTotalLength();
1662 Done = true;
1663 return;
1664 }
1665
1666
1667
1668 if (hasValidVersion(Offset))
1669 return;
1670
1671
1672
1673
1674 for (unsigned Align : {4, 8}) {
1675 uint64_t AlignedOffset = alignTo(Offset, Align);
1676 if (!DebugLineData.isValidOffset(AlignedOffset)) {
1677
1678
1679
1680 Done = true;
1681 return;
1682 }
1683 if (hasValidVersion(AlignedOffset)) {
1684 Offset = AlignedOffset;
1685 break;
1686 }
1687 }
1688}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static Error parseV5DirFileTables(const DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr, const dwarf::FormParams &FormParams, const DWARFContext &Ctx, const DWARFUnit *U, DWARFDebugLine::ContentTypeTracker &ContentTypes, std::vector< DWARFFormValue > &IncludeDirectories, std::vector< DWARFDebugLine::FileNameEntry > &FileNames)
Definition DWARFDebugLine.cpp:272
static Error parseV2DirFileTables(const DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr, DWARFDebugLine::ContentTypeTracker &ContentTypes, std::vector< DWARFFormValue > &IncludeDirectories, std::vector< DWARFDebugLine::FileNameEntry > &FileNames)
Definition DWARFDebugLine.cpp:187
static llvm::Expected< ContentDescriptors > parseV5EntryFormat(const DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr, DWARFDebugLine::ContentTypeTracker *ContentTypes)
Definition DWARFDebugLine.cpp:241
static DWARFDebugLine::SectionParser::LineToUnitMap buildLineToUnitMap(DWARFUnitVector::iterator_range Units)
Definition DWARFDebugLine.cpp:1574
static bool versionIsSupported(uint16_t Version)
Definition DWARFDebugLine.cpp:44
static StringRef getOpcodeName(uint8_t Opcode, uint8_t OpcodeBase)
Definition DWARFDebugLine.cpp:627
static std::optional< T > parseULEB128(DWARFDataExtractor &Data, DataExtractor::Cursor &Cursor)
Parse a ULEB128 using the specified Cursor.
Definition DWARFDebugLine.cpp:781
This file contains constants used for implementing Dwarf debug support.
static fatal_error_handler_t ErrorHandler
This file defines the SmallString class.
This file defines the SmallVector class.
LocallyHashedType DenseMapInfo< LocallyHashedType >::Tombstone
DWARFContext This data structure is the top level entity that deals with dwarf debug information pars...
LLVM_ABI void skip(function_ref< void(Error)> RecoverableErrorHandler, function_ref< void(Error)> UnrecoverableErrorHandler)
Skip the current line table and go to the following line table (if present) immediately.
Definition DWARFDebugLine.cpp:1612
std::map< uint64_t, DWARFUnit * > LineToUnitMap
LLVM_ABI LineTable parseNext(function_ref< void(Error)> RecoverableErrorHandler, function_ref< void(Error)> UnrecoverableErrorHandler, raw_ostream *OS=nullptr, bool Verbose=false)
Get the next line table from the section.
Definition DWARFDebugLine.cpp:1596
LLVM_ABI SectionParser(DWARFDataExtractor &Data, const DWARFContext &C, DWARFUnitVector::iterator_range Units)
Definition DWARFDebugLine.cpp:1583
LLVM_ABI void clearLineTable(uint64_t Offset)
Definition DWARFDebugLine.cpp:623
LLVM_ABI Expected< const LineTable * > getOrParseLineTable(DWARFDataExtractor &DebugLineData, uint64_t Offset, const DWARFContext &Ctx, const DWARFUnit *U, function_ref< void(Error)> RecoverableErrorHandler)
Definition DWARFDebugLine.cpp:602
LLVM_ABI const LineTable * getLineTable(uint64_t Offset) const
Definition DWARFDebugLine.cpp:595
static LLVM_ABI DWARFFormValue createFromPValue(dwarf::Form F, const char *V)
LLVM_ABI void dumpAddress(raw_ostream &OS, uint64_t Address) const
LLVM_ABI void dump(raw_ostream &OS, DIDumpOptions DumpOpts=DIDumpOptions()) const
LLVM_ABI Expected< const char * > getAsCString() const
llvm::iterator_range< UnitVector::iterator > iterator_range
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
Error takeError()
Take ownership of the stored error.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
constexpr bool empty() const
empty - Check if the string is empty.
constexpr const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
LLVM Value Representation.
An efficient, type-erasing, non-owning reference to a callable.
This class implements an extremely fast bulk output stream that can only output to a stream.
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
LLVM_ABI StringRef LNExtendedString(unsigned Encoding)
LLVM_ABI StringRef FormatString(DwarfFormat Format)
LLVM_ABI StringRef LNStandardString(unsigned Standard)
@ C
The default llvm calling convention, compatible with C.
bool isPathAbsoluteOnWindowsOrPosix(const Twine &Path)
Calculates the starting offsets for various sections within the .debug_names section.
std::optional< const char * > toString(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract a string value from it.
LineNumberOps
Line Number Standard Opcode Encodings.
std::optional< uint64_t > toSectionOffset(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract an section offset.
StringRef toStringRef(const std::optional< DWARFFormValue > &V, StringRef Default={})
Take an optional DWARFFormValue and try to extract a string value from it.
uint8_t getDwarfOffsetByteSize(DwarfFormat Format)
The size of a reference determined by the DWARF 32/64-bit format.
uint64_t computeTombstoneAddress(uint8_t AddressByteSize)
LLVM_ABI StringRef filename(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get filename.
LLVM_ABI bool is_absolute(const Twine &path, Style style=Style::native)
Is path absolute?
LLVM_ABI void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
void stable_sort(R &&Range)
SmallVectorImpl< T >::const_pointer c_str(SmallVectorImpl< T > &str)
auto uninitialized_copy(R &&Src, IterTy Dst)
auto upper_bound(R &&Range, T &&Value)
Provide wrappers to std::upper_bound which take ranges instead of having to pass begin/end explicitly...
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
FunctionAddr VTableAddr uintptr_t uintptr_t Version
Error joinErrors(Error E1, Error E2)
Concatenate errors.
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
FunctionAddr VTableAddr uintptr_t uintptr_t Data
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
std::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)
void consumeError(Error Err)
Consume a Error without doing anything.
Container for dump options that control which debug information will be dumped.
A format-neutral container for source line information.
Tracks which optional content types are present in a DWARF file name entry format.
bool HasLength
Whether filename entries provide a file size.
bool HasSource
For v5, whether filename entries provide source text.
bool HasModTime
Whether filename entries provide a modification timestamp.
bool HasMD5
For v5, whether filename entries provide an MD5 checksum.
LLVM_ABI void trackContentType(dwarf::LineNumberEntryFormat ContentType)
Update tracked content types with ContentType.
Definition DWARFDebugLine.cpp:48
LLVM_ABI uint32_t lookupAddress(object::SectionedAddress Address, bool *IsApproximateLine=nullptr) const
Returns the index of the row with file/line info for a given address, or UnknownRowIndex if there is ...
Definition DWARFDebugLine.cpp:1323
LLVM_ABI bool getDirectoryForEntry(const FileNameEntry &Entry, std::string &Directory) const
Extracts directory name by its Entry in include directories table in prologue.
Definition DWARFDebugLine.cpp:1551
const uint32_t UnknownRowIndex
Represents an invalid row.
LLVM_ABI bool getFileLineInfoForAddress(object::SectionedAddress Address, bool Approximate, const char *CompDir, DILineInfoSpecifier::FileLineInfoKind Kind, DILineInfo &Result) const
Fills the Result argument with the file and line information corresponding to Address.
Definition DWARFDebugLine.cpp:1532
LLVM_ABI Error parse(DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr, const DWARFContext &Ctx, const DWARFUnit *U, function_ref< void(Error)> RecoverableErrorHandler, raw_ostream *OS=nullptr, bool Verbose=false)
Parse prologue and all rows.
Definition DWARFDebugLine.cpp:789
LLVM_ABI void clear()
Definition DWARFDebugLine.cpp:556
bool getFileNameByIndex(uint64_t FileIndex, StringRef CompDir, DILineInfoSpecifier::FileLineInfoKind Kind, std::string &Result) const
Extracts filename by its index in filename table in prologue.
LLVM_ABI LineTable()
Definition DWARFDebugLine.cpp:537
void appendSequence(const DWARFDebugLine::Sequence &S)
LLVM_ABI bool lookupAddressRange(object::SectionedAddress Address, uint64_t Size, std::vector< uint32_t > &Result, std::optional< uint64_t > StmtSequenceOffset=std::nullopt) const
Fills the Result argument with the indices of the rows that correspond to the address range specified...
Definition DWARFDebugLine.cpp:1372
void appendRow(const DWARFDebugLine::Row &R)
LLVM_ABI void dump(raw_ostream &OS, DIDumpOptions DumpOptions) const
Definition DWARFDebugLine.cpp:539
uint8_t MaxOpsPerInst
The maximum number of individual operations that may be encoded in an instruction.
uint8_t MinInstLength
The size in bytes of the smallest target machine instruction.
LLVM_ABI bool hasFileAtIndex(uint64_t FileIndex) const
Definition DWARFDebugLine.cpp:72
uint64_t PrologueLength
The number of bytes following the prologue_length field to the beginning of the first byte of the sta...
LLVM_ABI void clear()
Definition DWARFDebugLine.cpp:105
LLVM_ABI void dump(raw_ostream &OS, DIDumpOptions DumpOptions) const
Definition DWARFDebugLine.cpp:117
uint32_t sizeofTotalLength() const
uint8_t SegSelectorSize
In v5, size in bytes of a segment selector.
uint16_t getVersion() const
int8_t LineBase
This parameter affects the meaning of the special opcodes. See below.
LLVM_ABI std::optional< uint64_t > getLastValidFileIndex() const
Definition DWARFDebugLine.cpp:82
uint32_t sizeofPrologueLength() const
LLVM_ABI Error parse(DWARFDataExtractor Data, uint64_t *OffsetPtr, function_ref< void(Error)> RecoverableErrorHandler, const DWARFContext &Ctx, const DWARFUnit *U=nullptr)
Definition DWARFDebugLine.cpp:363
uint8_t LineRange
This parameter affects the meaning of the special opcodes. See below.
LLVM_ABI Prologue()
Definition DWARFDebugLine.cpp:70
std::vector< DWARFFormValue > IncludeDirectories
uint8_t OpcodeBase
The number assigned to the first special opcode.
std::vector< uint8_t > StandardOpcodeLengths
LLVM_ABI bool totalLengthIsValid() const
Definition DWARFDebugLine.cpp:1592
uint8_t getAddressSize() const
LLVM_ABI const llvm::DWARFDebugLine::FileNameEntry & getFileNameEntry(uint64_t Index) const
Get DWARF-version aware access to the file name entry at the provided index.
Definition DWARFDebugLine.cpp:95
LLVM_ABI bool getFileNameByIndex(uint64_t FileIndex, StringRef CompDir, DILineInfoSpecifier::FileLineInfoKind Kind, std::string &Result, sys::path::Style Style=sys::path::Style::native) const
Definition DWARFDebugLine.cpp:1479
uint8_t DefaultIsStmt
The initial value of theis_stmtregister.
uint64_t TotalLength
The size in bytes of the statement information for this compilation unit (not including the total_len...
dwarf::FormParams FormParams
Version, address size (starting in v5), and DWARF32/64 format; these parameters affect interpretation...
LLVM_ABI uint64_t getLength() const
Length of the prologue in bytes.
Definition DWARFDebugLine.cpp:355
ContentTypeTracker ContentTypes
This tracks which optional file format content types are present.
std::vector< FileNameEntry > FileNames
Standard .debug_line state machine structure.
uint8_t BasicBlock
A boolean indicating that the current instruction is the beginning of a basic block.
static bool orderByAddress(const Row &LHS, const Row &RHS)
uint32_t Line
An unsigned integer indicating a source line number.
uint16_t File
An unsigned integer indicating the identity of the source file corresponding to a machine instruction...
uint32_t Discriminator
An unsigned integer representing the DWARF path discriminator value for this location.
uint8_t EpilogueBegin
A boolean indicating that the current address is one (of possibly many) where execution should be sus...
object::SectionedAddress Address
The program-counter value corresponding to a machine instruction generated by the compiler and sectio...
LLVM_ABI void postAppend()
Called after a row is appended to the matrix.
Definition DWARFDebugLine.cpp:484
uint8_t PrologueEnd
A boolean indicating that the current address is one (of possibly many) where execution should be sus...
uint16_t Column
An unsigned integer indicating a column number within a source line.
uint8_t EndSequence
A boolean indicating that the current address is that of the first byte after the end of a sequence o...
static LLVM_ABI void dumpTableHeader(raw_ostream &OS, unsigned Indent)
Definition DWARFDebugLine.cpp:507
uint8_t IsStmt
A boolean indicating that the current instruction is the beginning of a statement.
LLVM_ABI void reset(bool DefaultIsStmt)
Definition DWARFDebugLine.cpp:491
LLVM_ABI Row(bool DefaultIsStmt=false)
Definition DWARFDebugLine.cpp:482
uint8_t Isa
An unsigned integer whose value encodes the applicable instruction set architecture for the current i...
LLVM_ABI void dump(raw_ostream &OS) const
Definition DWARFDebugLine.cpp:516
uint8_t OpIndex
An unsigned integer representing the index of an operation within a VLIW instruction.
Represents a series of contiguous machine instructions.
uint64_t LowPC
Sequence describes instructions at address range [LowPC, HighPC) and is described by line table rows ...
static bool orderByHighPC(const Sequence &LHS, const Sequence &RHS)
LLVM_ABI void reset()
Definition DWARFDebugLine.cpp:527
LLVM_ABI Sequence()
Definition DWARFDebugLine.cpp:525
bool containsPC(object::SectionedAddress PC) const
uint64_t StmtSeqOffset
The offset into the line table where this sequence begins.
uint64_t SectionIndex
If relocation information is present then this is the index of the section which contains above addre...
LLVM_ABI SmallString< 32 > digest() const
A helper struct providing information about the byte size of DW_FORM values that vary in size dependi...
static const uint64_t UndefSection