llvm.org GIT mirror llvm / 35abb61
[llvm-pdbutil] Add a function for formatting MSF data. The goal here is to make it possible to display absolute file offsets when dumping byets from an MSF. The problem is that when dumping bytes from an MSF, often the bytes will cross a block boundary and encounter a discontinuity. We can't use the normal formatBinary() function for this because this would just treat the sequence as entirely ascending, and not account out-of-order blocks. This patch adds a formatMsfData() function to our printer, and then uses this function to improve the output of the -stream-data command line option for dumping bytes from a particular stream. Test coverage is also expanded to make sure to include all possible scenarios of offsets, sizes, and crossing block boundaries. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@306141 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 2 years ago
6 changed file(s) with 211 addition(s) and 37 deletion(s). Raw diff Collapse all Expand all
1212 #include "llvm/ADT/DenseMap.h"
1313 #include "llvm/DebugInfo/MSF/IMSFFile.h"
1414 #include "llvm/DebugInfo/MSF/MSFCommon.h"
15 #include "llvm/DebugInfo/MSF/MSFStreamLayout.h"
1516 #include "llvm/Support/Allocator.h"
1617 #include "llvm/Support/BinaryStreamRef.h"
1718 #include "llvm/Support/Endian.h"
8485
8586 ArrayRef getDirectoryBlockArray() const;
8687
88 msf::MSFStreamLayout getStreamLayout(uint32_t StreamIdx) const;
89
8790 Error parseFileHeaders();
8891 Error parseStreamData();
8992
229229 return ContainerLayout.DirectoryBlocks;
230230 }
231231
232 MSFStreamLayout PDBFile::getStreamLayout(uint32_t StreamIdx) const {
233 MSFStreamLayout Result;
234 auto Blocks = getStreamBlockList(StreamIdx);
235 Result.Blocks.assign(Blocks.begin(), Blocks.end());
236 Result.Length = getStreamByteSize(StreamIdx);
237 return Result;
238 }
239
232240 Expected PDBFile::getPDBGlobalsStream() {
233241 if (!Globals) {
234242 auto DbiS = getPDBDbiStream();
11 ; RUN: llvm-pdbutil bytes -stream-data=100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=INVALIDSTREAM %s
22 ; RUN: llvm-pdbutil bytes -stream-data=1,100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BOTH %s
33
4 ; RUN: llvm-pdbutil bytes -stream-data=1:10 %p/Inputs/empty.pdb | FileCheck --check-prefix=OFFSET %s
5 ; RUN: llvm-pdbutil bytes -stream-data=1@20 %p/Inputs/empty.pdb | FileCheck --check-prefix=SIZED %s
6 ; RUN: llvm-pdbutil bytes -stream-data=1:8@20 %p/Inputs/empty.pdb | FileCheck --check-prefix=SLICE %s
7 ; RUN: llvm-pdbutil bytes -stream-data=1:0x8@0x14 %p/Inputs/empty.pdb | FileCheck --check-prefix=SLICE %s
8 ; RUN: llvm-pdbutil bytes -stream-data=2:4050@100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=DISCONTINUITY %s
9
410 STREAM: Stream Data
511 STREAM-NEXT: ============================================================
6 STREAM-NEXT: Stream 1 (118 bytes): PDB Stream
12 STREAM-NEXT: Stream 1: PDB Stream (dumping 118 / 118 bytes)
713 STREAM-NEXT: Data (
8 STREAM-NEXT: 0000: 942E3101 E207E554 01000000 0B355641 86A0A249 896F9988 FAE52FF0 22000000 |..1....T.....5VA...I.o..../."...|
9 STREAM-NEXT: 0020: 2F4C696E 6B496E66 6F002F6E 616D6573 002F7372 632F6865 61646572 626C6F63 |/LinkInfo./names./src/headerbloc|
10 STREAM-NEXT: 0040: 6B000300 00000600 00000100 00001A00 00000000 00001100 00000900 00000A00 |k...............................|
11 STREAM-NEXT: 0060: 00000D00 00000000 00000500 00000000 00004191 3201 |..................A.2.|
14 STREAM-NEXT: 13000: 942E3101 E207E554 01000000 0B355641 86A0A249 896F9988 FAE52FF0 22000000 |..1....T.....5VA...I.o..../."...|
15 STREAM-NEXT: 13020: 2F4C696E 6B496E66 6F002F6E 616D6573 002F7372 632F6865 61646572 626C6F63 |/LinkInfo./names./src/headerbloc|
16 STREAM-NEXT: 13040: 6B000300 00000600 00000100 00001A00 00000000 00001100 00000900 00000A00 |k...............................|
17 STREAM-NEXT: 13060: 00000D00 00000000 00000500 00000000 00004191 3201 |..................A.2.|
1218 STREAM-NEXT: )
1319
1420 INVALIDSTREAM: Stream Data
1723
1824 BOTH: Stream Data
1925 BOTH-NEXT: ============================================================
20 BOTH-NEXT: Stream 1 (118 bytes): PDB Stream
26 BOTH-NEXT: Stream 1: PDB Stream (dumping 118 / 118 bytes)
2127 BOTH-NEXT: Data (
22 BOTH-NEXT: 0000: 942E3101 E207E554 01000000 0B355641 86A0A249 896F9988 FAE52FF0 22000000 |..1....T.....5VA...I.o..../."...|
23 BOTH-NEXT: 0020: 2F4C696E 6B496E66 6F002F6E 616D6573 002F7372 632F6865 61646572 626C6F63 |/LinkInfo./names./src/headerbloc|
24 BOTH-NEXT: 0040: 6B000300 00000600 00000100 00001A00 00000000 00001100 00000900 00000A00 |k...............................|
25 BOTH-NEXT: 0060: 00000D00 00000000 00000500 00000000 00004191 3201 |..................A.2.|
28 BOTH-NEXT: 13000: 942E3101 E207E554 01000000 0B355641 86A0A249 896F9988 FAE52FF0 22000000 |..1....T.....5VA...I.o..../."...|
29 BOTH-NEXT: 13020: 2F4C696E 6B496E66 6F002F6E 616D6573 002F7372 632F6865 61646572 626C6F63 |/LinkInfo./names./src/headerbloc|
30 BOTH-NEXT: 13040: 6B000300 00000600 00000100 00001A00 00000000 00001100 00000900 00000A00 |k...............................|
31 BOTH-NEXT: 13060: 00000D00 00000000 00000500 00000000 00004191 3201 |..................A.2.|
2632 BOTH-NEXT: )
2733 BOTH-NEXT: Stream 100: Not present
34
35 OFFSET: Stream Data
36 OFFSET-NEXT: ============================================================
37 OFFSET-NEXT: Stream 1: PDB Stream (dumping 108 / 118 bytes)
38 OFFSET-NEXT: Data (
39 OFFSET-NEXT: 1300A: 00000B35 564186A0 A249896F 9988FAE5 2FF02200 00002F4C 696E6B49 6E666F00 |...5VA...I.o..../.".../LinkInfo.|
40 OFFSET-NEXT: 1302A: 2F6E616D 6573002F 7372632F 68656164 6572626C 6F636B00 03000000 06000000 |/names./src/headerblock.........|
41 OFFSET-NEXT: 1304A: 01000000 1A000000 00000000 11000000 09000000 0A000000 0D000000 00000000 |................................|
42 OFFSET-NEXT: 1306A: 05000000 00000000 41913201 |........A.2.|
43 OFFSET-NEXT: )
44
45 SIZED: Stream Data
46 SIZED-NEXT: ============================================================
47 SIZED-NEXT: Stream 1: PDB Stream (dumping 20 / 118 bytes)
48 SIZED-NEXT: Data (
49 SIZED-NEXT: 13000: 942E3101 E207E554 01000000 0B355641 86A0A249 |..1....T.....5VA...I|
50 SIZED-NEXT: )
51
52 SLICE: Stream Data
53 SLICE-NEXT: ============================================================
54 SLICE-NEXT: Stream 1: PDB Stream (dumping 20 / 118 bytes)
55 SLICE-NEXT: Data (
56 SLICE-NEXT: 13008: 01000000 0B355641 86A0A249 896F9988 FAE52FF0 |.....5VA...I.o..../.|
57 SLICE-NEXT: )
58
59 DISCONTINUITY: Stream Data
60 DISCONTINUITY-NEXT: ============================================================
61 DISCONTINUITY-NEXT: Stream 2: TPI Stream (dumping 100 / 5,392 bytes)
62 DISCONTINUITY-NEXT: Data (
63 DISCONTINUITY-NEXT: 12FD2: 65537472 75637455 73616765 00F10215 03000480 00002000 654C6F63 616C5573 |eStructUsage.......... .eLocalUs|
64 DISCONTINUITY-NEXT: 12FF2: 61676500 F2F10215 03000480 0000 |age...........|
65 DISCONTINUITY-NEXT: ---------------------------------------------------------------------------------------------------
66 DISCONTINUITY-NEXT: 11000: 40006550 726F7065 72747955 73616765 00F3F2F1 02150300 04800000 80006545 |@.ePropertyUsage..............eE|
67 DISCONTINUITY-NEXT: 11020: 76656E74 55736167 6500F2F1 02150300 04800000 0001 |ventUsage.............|
68 DISCONTINUITY-NEXT: )
131131 auto Specs = parseStreamSpecs(P);
132132
133133 for (const auto &Spec : Specs) {
134 uint32_t End = 0;
135
136134 AutoIndent Indent(P);
137 if (Spec.SI >= File.getNumStreams()) {
135 if (Spec.SI >= StreamPurposes.size()) {
138136 P.formatLine("Stream {0}: Not present", Spec.SI);
139137 continue;
140138 }
141
142 auto S = MappedBlockStream::createIndexedStream(
143 File.getMsfLayout(), File.getMsfBuffer(), Spec.SI, File.getAllocator());
144 if (!S) {
145 P.NewLine();
146 P.formatLine("Stream {0}: Not present", Spec.SI);
147 continue;
148 }
149
150 if (Spec.Size == 0)
151 End = S->getLength();
152 else
153 End = std::min(Spec.Begin + Spec.Size, S->getLength());
154 uint32_t Size = End - Spec.Begin;
155
156 P.formatLine("Stream {0} ({1:N} bytes): {2}", Spec.SI, S->getLength(),
157 StreamPurposes[Spec.SI]);
158 AutoIndent Indent2(P);
159
160 BinaryStreamReader R(*S);
161 ArrayRef StreamData;
162 Err(R.readBytes(StreamData, S->getLength()));
163 StreamData = StreamData.slice(Spec.Begin, Size);
164 P.formatBinary("Data", StreamData, Spec.Begin);
139 P.formatMsfStreamData("Data", File, Spec.SI, StreamPurposes[Spec.SI],
140 Spec.Begin, Spec.Size);
165141 }
166142 }
1111 #include "llvm-pdbutil.h"
1212
1313 #include "llvm/ADT/STLExtras.h"
14 #include "llvm/DebugInfo/MSF/MSFCommon.h"
15 #include "llvm/DebugInfo/MSF/MSFStreamLayout.h"
16 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
17 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
1418 #include "llvm/DebugInfo/PDB/UDTLayout.h"
19 #include "llvm/Support/BinaryStreamReader.h"
1520 #include "llvm/Support/Format.h"
21 #include "llvm/Support/FormatAdapters.h"
22 #include "llvm/Support/FormatVariadic.h"
1623 #include "llvm/Support/Regex.h"
1724
1825 #include
1926
2027 using namespace llvm;
28 using namespace llvm::msf;
2129 using namespace llvm::pdb;
2230
2331 namespace {
119127 OS << ")";
120128 }
121129
130 namespace {
131 struct Run {
132 Run() = default;
133 explicit Run(uint32_t Block) : Block(Block) {}
134 uint32_t Block = 0;
135 uint32_t ByteLen = 0;
136 };
137 } // namespace
138
139 static std::vector computeBlockRuns(uint32_t BlockSize,
140 const msf::MSFStreamLayout &Layout) {
141 std::vector Runs;
142 if (Layout.Length == 0)
143 return Runs;
144
145 ArrayRef Blocks = Layout.Blocks;
146 assert(!Blocks.empty());
147 uint32_t StreamBytesRemaining = Layout.Length;
148 Runs.emplace_back(Blocks[0]);
149 while (!Blocks.empty()) {
150 Run *CurrentRun = &Runs.back();
151 uint32_t NextBlock = Blocks.front();
152 if (NextBlock < CurrentRun->Block || (NextBlock - CurrentRun->Block > 1)) {
153 Runs.emplace_back(NextBlock);
154 CurrentRun = &Runs.back();
155 }
156
157 uint32_t Used = std::min(BlockSize, StreamBytesRemaining);
158 CurrentRun->ByteLen += Used;
159 StreamBytesRemaining -= Used;
160 Blocks = Blocks.drop_front();
161 }
162 return Runs;
163 }
164
165 static std::pair findRun(uint32_t Offset, ArrayRef Runs) {
166 for (const auto &R : Runs) {
167 if (Offset < R.ByteLen)
168 return std::make_pair(R, Offset);
169 Offset -= R.ByteLen;
170 }
171 llvm_unreachable("Invalid offset!");
172 }
173
174 void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,
175 uint32_t StreamIdx,
176 StringRef StreamPurpose, uint32_t Offset,
177 uint32_t Size) {
178 if (StreamIdx >= File.getNumStreams()) {
179 formatLine("Stream {0}: Not present", StreamIdx);
180 return;
181 }
182 if (Size + Offset > File.getStreamByteSize(StreamIdx)) {
183 formatLine(
184 "Stream {0}: Invalid offset and size, range out of stream bounds",
185 StreamIdx);
186 return;
187 }
188
189 auto S = MappedBlockStream::createIndexedStream(
190 File.getMsfLayout(), File.getMsfBuffer(), StreamIdx, File.getAllocator());
191 if (!S) {
192 NewLine();
193 formatLine("Stream {0}: Not present", StreamIdx);
194 return;
195 }
196
197 uint32_t End =
198 (Size == 0) ? S->getLength() : std::min(Offset + Size, S->getLength());
199 Size = End - Offset;
200
201 formatLine("Stream {0}: {1} (dumping {2:N} / {3:N} bytes)", StreamIdx,
202 StreamPurpose, Size, S->getLength());
203 AutoIndent Indent(*this);
204 BinaryStreamRef Slice(*S);
205 Slice = Slice.keep_front(Offset + Size);
206 BinaryStreamReader Reader(Slice);
207 consumeError(Reader.skip(Offset));
208 auto Layout = File.getStreamLayout(StreamIdx);
209 formatMsfStreamData(Label, File, Layout, Reader);
210 }
211
212 void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,
213 const msf::MSFStreamLayout &Stream,
214 BinarySubstreamRef Substream) {
215 BinaryStreamReader Reader(Substream.StreamData);
216
217 consumeError(Reader.skip(Substream.Offset));
218 formatMsfStreamData(Label, File, Stream, Reader);
219 }
220
221 void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,
222 const msf::MSFStreamLayout &Stream,
223 BinaryStreamReader &Reader) {
224 auto Runs = computeBlockRuns(File.getBlockSize(), Stream);
225
226 NewLine();
227 OS << Label << " (";
228 while (Reader.bytesRemaining() > 0) {
229 OS << "\n";
230
231 Run FoundRun;
232 uint32_t RunOffset;
233 std::tie(FoundRun, RunOffset) = findRun(Reader.getOffset(), Runs);
234 assert(FoundRun.ByteLen >= RunOffset);
235 uint32_t Len = FoundRun.ByteLen - RunOffset;
236 Len = std::min(Len, Reader.bytesRemaining());
237 uint64_t Base = FoundRun.Block * File.getBlockSize() + RunOffset;
238 ArrayRef Data;
239 consumeError(Reader.readBytes(Data, Len));
240 OS << format_bytes_with_ascii(Data, Base, 32, 4,
241 CurrentIndent + IndentSpaces, true);
242 if (Reader.bytesRemaining() > 0) {
243 NewLine();
244 OS << formatv(" {0}",
245 fmt_align("", AlignStyle::Center, 114, '-'));
246 }
247 }
248 NewLine();
249 OS << ")";
250 }
251
122252 bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size) {
123253 if (IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters))
124254 return true;
1212 #include "llvm/ADT/ArrayRef.h"
1313 #include "llvm/ADT/StringRef.h"
1414 #include "llvm/ADT/Twine.h"
15 #include "llvm/Support/BinaryStreamRef.h"
1516 #include "llvm/Support/FormatVariadic.h"
1617 #include "llvm/Support/Regex.h"
1718 #include "llvm/Support/raw_ostream.h"
1920 #include
2021
2122 namespace llvm {
23 class BinaryStreamReader;
24 namespace msf {
25 class MSFStreamLayout;
26 } // namespace msf
2227 namespace pdb {
2328
2429 class ClassLayout;
30 class PDBFile;
2531
2632 class LinePrinter {
2733 friend class WithColor;
4652 uint32_t StartOffset);
4753 void formatBinary(StringRef Label, ArrayRef Data, uint64_t BaseAddr,
4854 uint32_t StartOffset);
55
56 void formatMsfStreamData(StringRef Label, PDBFile &File, uint32_t StreamIdx,
57 StringRef StreamPurpose, uint32_t Offset,
58 uint32_t Size);
59 void formatMsfStreamData(StringRef Label, PDBFile &File,
60 const msf::MSFStreamLayout &Stream,
61 BinarySubstreamRef Substream);
62 void formatMsfStreamData(StringRef Label, PDBFile &File,
63 const msf::MSFStreamLayout &Stream,
64 BinaryStreamReader &Reader);
4965
5066 bool hasColor() const { return UseColor; }
5167 raw_ostream &getStream() { return OS; }