8
8
9
9
#include " llvm-dwarfdump.h"
10
10
#include " llvm/ADT/DenseMap.h"
11
+ #include " llvm/ADT/DenseSet.h"
11
12
#include " llvm/ADT/StringSet.h"
12
13
#include " llvm/DebugInfo/DWARF/DWARFContext.h"
13
14
#include " llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
@@ -188,6 +189,16 @@ struct LocationStats {
188
189
// / Total number of local variables processed.
189
190
SaturatingUINT64 NumVar = 0 ;
190
191
};
192
+
193
+ // / Holds accumulated debug line statistics across all CUs.
194
+ struct LineStats {
195
+ SaturatingUINT64 NumBytes = 0 ;
196
+ SaturatingUINT64 NumLineZeroBytes = 0 ;
197
+ SaturatingUINT64 NumEntries = 0 ;
198
+ SaturatingUINT64 NumIsStmtEntries = 0 ;
199
+ SaturatingUINT64 NumUniqueEntries = 0 ;
200
+ SaturatingUINT64 NumUniqueNonZeroEntries = 0 ;
201
+ };
191
202
} // namespace
192
203
193
204
// / Collect debug location statistics for one DIE.
@@ -848,6 +859,7 @@ bool dwarfdump::collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
848
859
StringRef FormatName = Obj.getFileFormatName ();
849
860
GlobalStats GlobalStats;
850
861
LocationStats LocStats;
862
+ LineStats LnStats;
851
863
StringMap<PerFunctionStats> Statistics;
852
864
// This variable holds variable information for functions with
853
865
// abstract_origin globally, across all CUs.
@@ -856,6 +868,14 @@ bool dwarfdump::collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
856
868
// abstract_origin.
857
869
FunctionDIECUTyMap AbstractOriginFnCUs;
858
870
CrossCUReferencingDIELocationTy CrossCUReferencesToBeResolved;
871
+ // Tuple representing a single source code position in the line table. Fields
872
+ // are respectively: Line, Col, File, where 'File' is an index into the Files
873
+ // vector below.
874
+ using LineTuple = std::tuple<uint32_t , uint16_t , uint16_t >;
875
+ SmallVector<std::string> Files;
876
+ DenseSet<LineTuple> UniqueLines;
877
+ DenseSet<LineTuple> UniqueNonZeroLines;
878
+
859
879
for (const auto &CU : static_cast <DWARFContext *>(&DICtx)->compile_units ()) {
860
880
if (DWARFDie CUDie = CU->getNonSkeletonUnitDIE (false )) {
861
881
// This variable holds variable information for functions with
@@ -882,8 +902,58 @@ bool dwarfdump::collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
882
902
CrossCUReferencesToBeResolved.push_back (
883
903
DIELocation (CUDie.getDwarfUnit (), CrossCUReferencingDIEOffset));
884
904
}
905
+ const auto *LineTable = DICtx.getLineTableForUnit (CU.get ());
906
+ std::optional<uint64_t > LastFileIdxOpt;
907
+ if (LineTable)
908
+ LastFileIdxOpt = LineTable->getLastValidFileIndex ();
909
+ if (LastFileIdxOpt) {
910
+ // Each CU has its own file index; in order to track unique line entries
911
+ // across CUs, we therefore need to map each CU file index to a global
912
+ // file index, which we store here.
913
+ DenseMap<uint64_t , uint16_t > CUFileMapping;
914
+ for (uint64_t FileIdx = 0 ; FileIdx <= *LastFileIdxOpt; ++FileIdx) {
915
+ std::string File;
916
+ if (LineTable->getFileNameByIndex (
917
+ FileIdx, CU->getCompilationDir (),
918
+ DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath,
919
+ File)) {
920
+ auto ExistingFile = llvm::find (Files, File);
921
+ if (ExistingFile != Files.end ()) {
922
+ CUFileMapping[FileIdx] = std::distance (Files.begin (), ExistingFile);
923
+ } else {
924
+ CUFileMapping[FileIdx] = Files.size ();
925
+ Files.push_back (File);
926
+ }
927
+ }
928
+ }
929
+ for (const auto &Seq : LineTable->Sequences ) {
930
+ LnStats.NumBytes += Seq.HighPC - Seq.LowPC ;
931
+ // Ignore the `end_sequence` entry, since it's not interesting for us.
932
+ LnStats.NumEntries += Seq.LastRowIndex - Seq.FirstRowIndex - 1 ;
933
+ for (size_t RowIdx = Seq.FirstRowIndex ; RowIdx < Seq.LastRowIndex - 1 ;
934
+ ++RowIdx) {
935
+ auto Entry = LineTable->Rows [RowIdx];
936
+ if (Entry.IsStmt )
937
+ LnStats.NumIsStmtEntries += 1 ;
938
+ assert (CUFileMapping.contains (Entry.File ) &&
939
+ " Should have been collected earlier!" );
940
+ uint16_t MappedFile = CUFileMapping[Entry.File ];
941
+ UniqueLines.insert ({Entry.Line , Entry.Column , MappedFile});
942
+ if (Entry.Line != 0 ) {
943
+ UniqueNonZeroLines.insert ({Entry.Line , Entry.Column , MappedFile});
944
+ } else {
945
+ auto EntryStartAddress = Entry.Address .Address ;
946
+ auto EntryEndAddress = LineTable->Rows [RowIdx + 1 ].Address .Address ;
947
+ LnStats.NumLineZeroBytes += EntryEndAddress - EntryStartAddress;
948
+ }
949
+ }
950
+ }
951
+ }
885
952
}
886
953
954
+ LnStats.NumUniqueEntries = UniqueLines.size ();
955
+ LnStats.NumUniqueNonZeroEntries = UniqueNonZeroLines.size ();
956
+
887
957
// / Resolve CrossCU references.
888
958
collectZeroLocCovForVarsWithCrossCUReferencingAbstractOrigin (
889
959
LocStats, AbstractOriginFnCUs, GlobalAbstractOriginFnInfo,
@@ -1043,6 +1113,16 @@ bool dwarfdump::collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
1043
1113
printLocationStats (J, " #local vars" , LocStats.LocalVarLocStats );
1044
1114
printLocationStats (J, " #local vars - entry values" ,
1045
1115
LocStats.LocalVarNonEntryValLocStats );
1116
+
1117
+ // Print line statistics for the object file.
1118
+ printDatum (J, " #bytes with line information" , LnStats.NumBytes .Value );
1119
+ printDatum (J, " #bytes with line-0 locations" , LnStats.NumLineZeroBytes .Value );
1120
+ printDatum (J, " #line entries" , LnStats.NumEntries .Value );
1121
+ printDatum (J, " #line entries (is_stmt)" , LnStats.NumIsStmtEntries .Value );
1122
+ printDatum (J, " #line entries (unique)" , LnStats.NumUniqueEntries .Value );
1123
+ printDatum (J, " #line entries (unique non-0)" ,
1124
+ LnStats.NumUniqueNonZeroEntries .Value );
1125
+
1046
1126
J.objectEnd ();
1047
1127
OS << ' \n ' ;
1048
1128
LLVM_DEBUG (
0 commit comments