authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-08-30 03:44:34-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-08-30 03:44:34-04:00
log96117e20cc7c076cbf9d8243602c6e4205fdd0d4
tree489c244d0b5128e67b8d678a4e5864e401e38b59
parent686663239af6afd8dea814a9fe6a8885f06d6cb3

reading the module information substream


1 files changed, 96 insertions(+), 73 deletions(-)

std/pdb.zig+96-73
......@@ -76,7 +76,7 @@ pub const Pdb = struct {
7676 msf: Msf,
7777
7878 pub fn openFile(self: *Pdb, allocator: *mem.Allocator, file_name: []u8) !void {
79 self.in_file = try os.File.openRead(file_name[0..]);
79 self.in_file = try os.File.openRead(file_name);
8080 self.allocator = allocator;
8181
8282 try self.msf.openFile(allocator, self.in_file);
......@@ -85,7 +85,7 @@ pub const Pdb = struct {
8585 pub fn getStream(self: *Pdb, stream: StreamType) ?*MsfStream {
8686 const id = @enumToInt(stream);
8787 if (id < self.msf.streams.len)
88 return &self.msf.streams.items[id];
88 return &self.msf.streams[id];
8989 return null;
9090 }
9191
......@@ -101,17 +101,31 @@ pub const Pdb = struct {
101101 // Module Info Substream
102102 var mod_info_offset: usize = 0;
103103 while (mod_info_offset < header.ModInfoSize) {
104 const march_forward_bytes = dbi.getFilePos() % 4;
105 if (march_forward_bytes != 0) {
106 try dbi.seekForward(march_forward_bytes);
107 mod_info_offset += march_forward_bytes;
108 }
104109 var mod_info: ModInfo = undefined;
105110 try dbi.stream.readStruct(ModInfo, &mod_info);
106111 std.debug.warn("{}\n", mod_info);
107112 mod_info_offset += @sizeOf(ModInfo);
108113
109114 const module_name = try dbi.readNullTermString(self.allocator);
110 std.debug.warn("module_name {}\n", module_name);
115 std.debug.warn("module_name '{}'\n", module_name);
111116 mod_info_offset += module_name.len + 1;
112117
118 //if (mem.eql(u8, module_name, "piler_rt.obj")) {
119 // std.debug.warn("detected bad thing\n");
120 // try dbi.seekTo(dbi.pos -
121 // "c:\\msys64\\home\\andy\\zig\\build-llvm6-msvc-release\\.\\zig-cache\\compiler_rt.obj\x00".len -
122 // @sizeOf(ModInfo));
123 // mod_info_offset -= module_name.len + 1;
124 // continue;
125 //}
126
113127 const obj_file_name = try dbi.readNullTermString(self.allocator);
114 std.debug.warn("obj_file_name {}\n", obj_file_name);
128 std.debug.warn("obj_file_name '{}'\n", obj_file_name);
115129 mod_info_offset += obj_file_name.len + 1;
116130 }
117131 std.debug.warn("end modules\n");
......@@ -123,66 +137,55 @@ pub const Pdb = struct {
123137
124138// see https://llvm.org/docs/PDB/MsfFile.html
125139const Msf = struct {
126 superblock: SuperBlock,
127140 directory: MsfStream,
128 streams: ArrayList(MsfStream),
141 streams: []MsfStream,
129142
130143 fn openFile(self: *Msf, allocator: *mem.Allocator, file: os.File) !void {
131144 var file_stream = io.FileInStream.init(file);
132145 const in = &file_stream.stream;
133146
134 var magic: SuperBlock.FileMagicBuffer = undefined;
135 try in.readNoEof(magic[0..]);
136 warn("magic: '{}'\n", magic);
137
138 if (!mem.eql(u8, magic, SuperBlock.FileMagic))
139 return error.InvalidDebugInfo;
147 var superblock: SuperBlock = undefined;
148 try in.readStruct(SuperBlock, &superblock);
140149
141 self.superblock = SuperBlock {
142 .block_size = try in.readIntLe(u32),
143 .free_block_map_block = try in.readIntLe(u32),
144 .num_blocks = try in.readIntLe(u32),
145 .num_directory_bytes = try in.readIntLe(u32),
146 .unknown = try in.readIntLe(u32),
147 .block_map_addr = try in.readIntLe(u32),
148 };
150 if (!mem.eql(u8, superblock.FileMagic, SuperBlock.file_magic))
151 return error.InvalidDebugInfo;
149152
150 switch (self.superblock.block_size) {
151 512, 1024, 2048, 4096 => {}, // llvm only uses 4096
153 switch (superblock.BlockSize) {
154 // llvm only supports 4096 but we can handle any of these values
155 512, 1024, 2048, 4096 => {},
152156 else => return error.InvalidDebugInfo
153157 }
154158
155 if (self.superblock.fileSize() != try file.getEndPos())
156 return error.InvalidDebugInfo; // Should always stand.
159 if (superblock.NumBlocks * superblock.BlockSize != try file.getEndPos())
160 return error.InvalidDebugInfo;
157161
158162 self.directory = try MsfStream.init(
159 self.superblock.block_size,
160 self.superblock.blocksOccupiedByDirectoryStream(),
161 self.superblock.blockMapAddr(),
163 superblock.BlockSize,
164 blockCountFromSize(superblock.NumDirectoryBytes, superblock.BlockSize),
165 superblock.BlockSize * superblock.BlockMapAddr,
162166 file,
163 allocator
167 allocator,
164168 );
165169
166170 const stream_count = try self.directory.stream.readIntLe(u32);
167171 warn("stream count {}\n", stream_count);
168172
169 var stream_sizes = ArrayList(u32).init(allocator);
170 try stream_sizes.resize(stream_count);
171 for (stream_sizes.toSlice()) |*s| {
173 const stream_sizes = try allocator.alloc(u32, stream_count);
174 for (stream_sizes) |*s| {
172175 const size = try self.directory.stream.readIntLe(u32);
173 s.* = blockCountFromSize(size, self.superblock.block_size);
176 s.* = blockCountFromSize(size, superblock.BlockSize);
174177 warn("stream {}B {} blocks\n", size, s.*);
175178 }
176179
177 self.streams = ArrayList(MsfStream).init(allocator);
178 try self.streams.resize(stream_count);
179 for (self.streams.toSlice()) |*ss, i| {
180 ss.* = try MsfStream.init(
181 self.superblock.block_size,
182 stream_sizes.items[i],
183 try file.getPos(), // We're reading the jagged array of block indices when creating streams so the file is always at the right position.
180 self.streams = try allocator.alloc(MsfStream, stream_count);
181 for (self.streams) |*stream, i| {
182 stream.* = try MsfStream.init(
183 superblock.BlockSize,
184 stream_sizes[i],
185 // MsfStream.init expects the file to be at the part where it reads [N]u32
186 try file.getPos(),
184187 file,
185 allocator
188 allocator,
186189 );
187190 }
188191 }
......@@ -192,34 +195,53 @@ fn blockCountFromSize(size: u32, block_size: u32) u32 {
192195 return (size + block_size - 1) / block_size;
193196}
194197
195const SuperBlock = struct {
196 const FileMagic = "Microsoft C/C++ MSF 7.00\r\n" ++ []u8 { 0x1A, 'D', 'S', 0, 0, 0};
197 const FileMagicBuffer = @typeOf(FileMagic);
198
199 block_size: u32,
200 free_block_map_block: u32,
201 num_blocks: u32,
202 num_directory_bytes: u32,
203 unknown: u32,
204 block_map_addr: u32,
205
206 fn fileSize(self: *const SuperBlock) usize {
207 return self.num_blocks * self.block_size;
208 }
209
210 fn blockMapAddr(self: *const SuperBlock) usize {
211 return self.block_size * self.block_map_addr;
212 }
198// https://llvm.org/docs/PDB/MsfFile.html#the-superblock
199const SuperBlock = packed struct {
200 /// The LLVM docs list a space between C / C++ but empirically this is not the case.
201 const file_magic = "Microsoft C/C++ MSF 7.00\r\n\x1a\x44\x53\x00\x00\x00";
202
203 FileMagic: [file_magic.len]u8,
204
205 /// The block size of the internal file system. Valid values are 512, 1024,
206 /// 2048, and 4096 bytes. Certain aspects of the MSF file layout vary depending
207 /// on the block sizes. For the purposes of LLVM, we handle only block sizes of
208 /// 4KiB, and all further discussion assumes a block size of 4KiB.
209 BlockSize: u32,
210
211 /// The index of a block within the file, at which begins a bitfield representing
212 /// the set of all blocks within the file which are “free” (i.e. the data within
213 /// that block is not used). See The Free Block Map for more information. Important:
214 /// FreeBlockMapBlock can only be 1 or 2!
215 FreeBlockMapBlock: u32,
216
217 /// The total number of blocks in the file. NumBlocks * BlockSize should equal the
218 /// size of the file on disk.
219 NumBlocks: u32,
220
221 /// The size of the stream directory, in bytes. The stream directory contains
222 /// information about each stream’s size and the set of blocks that it occupies.
223 /// It will be described in more detail later.
224 NumDirectoryBytes: u32,
225
226 Unknown: u32,
227
228 /// The index of a block within the MSF file. At this block is an array of
229 /// ulittle32_t’s listing the blocks that the stream directory resides on.
230 /// For large MSF files, the stream directory (which describes the block
231 /// layout of each stream) may not fit entirely on a single block. As a
232 /// result, this extra layer of indirection is introduced, whereby this
233 /// block contains the list of blocks that the stream directory occupies,
234 /// and the stream directory itself can be stitched together accordingly.
235 /// The number of ulittle32_t’s in this array is given by
236 /// ceil(NumDirectoryBytes / BlockSize).
237 BlockMapAddr: u32,
213238
214 fn blocksOccupiedByDirectoryStream(self: *const SuperBlock) u32 {
215 return blockCountFromSize(self.num_directory_bytes, self.block_size);
216 }
217239};
218240
219241const MsfStream = struct {
220242 in_file: os.File,
221243 pos: usize,
222 blocks: ArrayList(u32),
244 blocks: []u32,
223245 block_size: u32,
224246
225247 /// Implementation of InStream trait for Pdb.MsfStream
......@@ -232,15 +254,13 @@ const MsfStream = struct {
232254 var stream = MsfStream {
233255 .in_file = file,
234256 .pos = 0,
235 .blocks = ArrayList(u32).init(allocator),
257 .blocks = try allocator.alloc(u32, block_count),
236258 .block_size = block_size,
237259 .stream = Stream {
238260 .readFn = readFn,
239261 },
240262 };
241263
242 try stream.blocks.resize(block_count);
243
244264 var file_stream = io.FileInStream.init(file);
245265 const in = &file_stream.stream;
246266 try file.seekTo(pos);
......@@ -248,8 +268,8 @@ const MsfStream = struct {
248268 warn("stream with blocks");
249269 var i: u32 = 0;
250270 while (i < block_count) : (i += 1) {
251 stream.blocks.items[i] = try in.readIntLe(u32);
252 warn(" {}", stream.blocks.items[i]);
271 stream.blocks[i] = try in.readIntLe(u32);
272 warn(" {}", stream.blocks[i]);
253273 }
254274 warn("\n");
255275
......@@ -270,9 +290,13 @@ const MsfStream = struct {
270290
271291 fn read(self: *MsfStream, buffer: []u8) !usize {
272292 var block_id = self.pos / self.block_size;
273 var block = self.blocks.items[block_id];
293 var block = self.blocks[block_id];
274294 var offset = self.pos % self.block_size;
275295
296 //std.debug.warn("seek {} read {}B: block_id={} block={} offset={}\n",
297 // block * self.block_size + offset,
298 // buffer.len, block_id, block, offset);
299
276300 try self.in_file.seekTo(block * self.block_size + offset);
277301 var file_stream = io.FileInStream.init(self.in_file);
278302 const in = &file_stream.stream;
......@@ -285,11 +309,10 @@ const MsfStream = struct {
285309 size += 1;
286310
287311 // If we're at the end of a block, go to the next one.
288 if (offset == self.block_size)
289 {
312 if (offset == self.block_size) {
290313 offset = 0;
291314 block_id += 1;
292 block = self.blocks.items[block_id];
315 block = self.blocks[block_id];
293316 try self.in_file.seekTo(block * self.block_size);
294317 }
295318 }
......@@ -314,9 +337,9 @@ const MsfStream = struct {
314337 return self.blocks.len * self.block_size;
315338 }
316339
317 fn getFilePos(self: *const MsfStream) usize {
340 fn getFilePos(self: MsfStream) usize {
318341 const block_id = self.pos / self.block_size;
319 const block = self.blocks.items[block_id];
342 const block = self.blocks[block_id];
320343 const offset = self.pos % self.block_size;
321344
322345 return block * self.block_size + offset;