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 {...@@ -76,7 +76,7 @@ pub const Pdb = struct {
76 msf: Msf,76 msf: Msf,
7777
78 pub fn openFile(self: *Pdb, allocator: *mem.Allocator, file_name: []u8) !void {78 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);
80 self.allocator = allocator;80 self.allocator = allocator;
8181
82 try self.msf.openFile(allocator, self.in_file);82 try self.msf.openFile(allocator, self.in_file);
...@@ -85,7 +85,7 @@ pub const Pdb = struct {...@@ -85,7 +85,7 @@ pub const Pdb = struct {
85 pub fn getStream(self: *Pdb, stream: StreamType) ?*MsfStream {85 pub fn getStream(self: *Pdb, stream: StreamType) ?*MsfStream {
86 const id = @enumToInt(stream);86 const id = @enumToInt(stream);
87 if (id < self.msf.streams.len)87 if (id < self.msf.streams.len)
88 return &self.msf.streams.items[id];88 return &self.msf.streams[id];
89 return null;89 return null;
90 }90 }
9191
...@@ -101,17 +101,31 @@ pub const Pdb = struct {...@@ -101,17 +101,31 @@ pub const Pdb = struct {
101 // Module Info Substream101 // Module Info Substream
102 var mod_info_offset: usize = 0;102 var mod_info_offset: usize = 0;
103 while (mod_info_offset < header.ModInfoSize) {103 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 }
104 var mod_info: ModInfo = undefined;109 var mod_info: ModInfo = undefined;
105 try dbi.stream.readStruct(ModInfo, &mod_info);110 try dbi.stream.readStruct(ModInfo, &mod_info);
106 std.debug.warn("{}\n", mod_info);111 std.debug.warn("{}\n", mod_info);
107 mod_info_offset += @sizeOf(ModInfo);112 mod_info_offset += @sizeOf(ModInfo);
108113
109 const module_name = try dbi.readNullTermString(self.allocator);114 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);
111 mod_info_offset += module_name.len + 1;116 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
113 const obj_file_name = try dbi.readNullTermString(self.allocator);127 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);
115 mod_info_offset += obj_file_name.len + 1;129 mod_info_offset += obj_file_name.len + 1;
116 }130 }
117 std.debug.warn("end modules\n");131 std.debug.warn("end modules\n");
...@@ -123,66 +137,55 @@ pub const Pdb = struct {...@@ -123,66 +137,55 @@ pub const Pdb = struct {
123137
124// see https://llvm.org/docs/PDB/MsfFile.html138// see https://llvm.org/docs/PDB/MsfFile.html
125const Msf = struct {139const Msf = struct {
126 superblock: SuperBlock,
127 directory: MsfStream,140 directory: MsfStream,
128 streams: ArrayList(MsfStream),141 streams: []MsfStream,
129142
130 fn openFile(self: *Msf, allocator: *mem.Allocator, file: os.File) !void {143 fn openFile(self: *Msf, allocator: *mem.Allocator, file: os.File) !void {
131 var file_stream = io.FileInStream.init(file);144 var file_stream = io.FileInStream.init(file);
132 const in = &file_stream.stream;145 const in = &file_stream.stream;
133146
134 var magic: SuperBlock.FileMagicBuffer = undefined;147 var superblock: SuperBlock = undefined;
135 try in.readNoEof(magic[0..]);148 try in.readStruct(SuperBlock, &superblock);
136 warn("magic: '{}'\n", magic);
137
138 if (!mem.eql(u8, magic, SuperBlock.FileMagic))
139 return error.InvalidDebugInfo;
140149
141 self.superblock = SuperBlock {150 if (!mem.eql(u8, superblock.FileMagic, SuperBlock.file_magic))
142 .block_size = try in.readIntLe(u32),151 return error.InvalidDebugInfo;
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 };
149152
150 switch (self.superblock.block_size) {153 switch (superblock.BlockSize) {
151 512, 1024, 2048, 4096 => {}, // llvm only uses 4096154 // llvm only supports 4096 but we can handle any of these values
155 512, 1024, 2048, 4096 => {},
152 else => return error.InvalidDebugInfo156 else => return error.InvalidDebugInfo
153 }157 }
154158
155 if (self.superblock.fileSize() != try file.getEndPos())159 if (superblock.NumBlocks * superblock.BlockSize != try file.getEndPos())
156 return error.InvalidDebugInfo; // Should always stand.160 return error.InvalidDebugInfo;
157161
158 self.directory = try MsfStream.init(162 self.directory = try MsfStream.init(
159 self.superblock.block_size,163 superblock.BlockSize,
160 self.superblock.blocksOccupiedByDirectoryStream(),164 blockCountFromSize(superblock.NumDirectoryBytes, superblock.BlockSize),
161 self.superblock.blockMapAddr(),165 superblock.BlockSize * superblock.BlockMapAddr,
162 file,166 file,
163 allocator167 allocator,
164 );168 );
165169
166 const stream_count = try self.directory.stream.readIntLe(u32);170 const stream_count = try self.directory.stream.readIntLe(u32);
167 warn("stream count {}\n", stream_count);171 warn("stream count {}\n", stream_count);
168172
169 var stream_sizes = ArrayList(u32).init(allocator);173 const stream_sizes = try allocator.alloc(u32, stream_count);
170 try stream_sizes.resize(stream_count);174 for (stream_sizes) |*s| {
171 for (stream_sizes.toSlice()) |*s| {
172 const size = try self.directory.stream.readIntLe(u32);175 const size = try self.directory.stream.readIntLe(u32);
173 s.* = blockCountFromSize(size, self.superblock.block_size);176 s.* = blockCountFromSize(size, superblock.BlockSize);
174 warn("stream {}B {} blocks\n", size, s.*);177 warn("stream {}B {} blocks\n", size, s.*);
175 }178 }
176179
177 self.streams = ArrayList(MsfStream).init(allocator);180 self.streams = try allocator.alloc(MsfStream, stream_count);
178 try self.streams.resize(stream_count);181 for (self.streams) |*stream, i| {
179 for (self.streams.toSlice()) |*ss, i| {182 stream.* = try MsfStream.init(
180 ss.* = try MsfStream.init(183 superblock.BlockSize,
181 self.superblock.block_size,184 stream_sizes[i],
182 stream_sizes.items[i],185 // MsfStream.init expects the file to be at the part where it reads [N]u32
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.186 try file.getPos(),
184 file,187 file,
185 allocator188 allocator,
186 );189 );
187 }190 }
188 }191 }
...@@ -192,34 +195,53 @@ fn blockCountFromSize(size: u32, block_size: u32) u32 {...@@ -192,34 +195,53 @@ fn blockCountFromSize(size: u32, block_size: u32) u32 {
192 return (size + block_size - 1) / block_size;195 return (size + block_size - 1) / block_size;
193}196}
194197
195const SuperBlock = struct {198// https://llvm.org/docs/PDB/MsfFile.html#the-superblock
196 const FileMagic = "Microsoft C/C++ MSF 7.00\r\n" ++ []u8 { 0x1A, 'D', 'S', 0, 0, 0};199const SuperBlock = packed struct {
197 const FileMagicBuffer = @typeOf(FileMagic);200 /// The LLVM docs list a space between C / C++ but empirically this is not the case.
198201 const file_magic = "Microsoft C/C++ MSF 7.00\r\n\x1a\x44\x53\x00\x00\x00";
199 block_size: u32,202
200 free_block_map_block: u32,203 FileMagic: [file_magic.len]u8,
201 num_blocks: u32,204
202 num_directory_bytes: u32,205 /// The block size of the internal file system. Valid values are 512, 1024,
203 unknown: u32,206 /// 2048, and 4096 bytes. Certain aspects of the MSF file layout vary depending
204 block_map_addr: u32,207 /// on the block sizes. For the purposes of LLVM, we handle only block sizes of
205208 /// 4KiB, and all further discussion assumes a block size of 4KiB.
206 fn fileSize(self: *const SuperBlock) usize {209 BlockSize: u32,
207 return self.num_blocks * self.block_size;210
208 }211 /// The index of a block within the file, at which begins a bitfield representing
209212 /// the set of all blocks within the file which are “free” (i.e. the data within
210 fn blockMapAddr(self: *const SuperBlock) usize {213 /// that block is not used). See The Free Block Map for more information. Important:
211 return self.block_size * self.block_map_addr;214 /// FreeBlockMapBlock can only be 1 or 2!
212 }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 }
217};239};
218240
219const MsfStream = struct {241const MsfStream = struct {
220 in_file: os.File,242 in_file: os.File,
221 pos: usize,243 pos: usize,
222 blocks: ArrayList(u32),244 blocks: []u32,
223 block_size: u32,245 block_size: u32,
224246
225 /// Implementation of InStream trait for Pdb.MsfStream247 /// Implementation of InStream trait for Pdb.MsfStream
...@@ -232,15 +254,13 @@ const MsfStream = struct {...@@ -232,15 +254,13 @@ const MsfStream = struct {
232 var stream = MsfStream {254 var stream = MsfStream {
233 .in_file = file,255 .in_file = file,
234 .pos = 0,256 .pos = 0,
235 .blocks = ArrayList(u32).init(allocator),257 .blocks = try allocator.alloc(u32, block_count),
236 .block_size = block_size,258 .block_size = block_size,
237 .stream = Stream {259 .stream = Stream {
238 .readFn = readFn,260 .readFn = readFn,
239 },261 },
240 };262 };
241263
242 try stream.blocks.resize(block_count);
243
244 var file_stream = io.FileInStream.init(file);264 var file_stream = io.FileInStream.init(file);
245 const in = &file_stream.stream;265 const in = &file_stream.stream;
246 try file.seekTo(pos);266 try file.seekTo(pos);
...@@ -248,8 +268,8 @@ const MsfStream = struct {...@@ -248,8 +268,8 @@ const MsfStream = struct {
248 warn("stream with blocks");268 warn("stream with blocks");
249 var i: u32 = 0;269 var i: u32 = 0;
250 while (i < block_count) : (i += 1) {270 while (i < block_count) : (i += 1) {
251 stream.blocks.items[i] = try in.readIntLe(u32);271 stream.blocks[i] = try in.readIntLe(u32);
252 warn(" {}", stream.blocks.items[i]);272 warn(" {}", stream.blocks[i]);
253 }273 }
254 warn("\n");274 warn("\n");
255275
...@@ -270,9 +290,13 @@ const MsfStream = struct {...@@ -270,9 +290,13 @@ const MsfStream = struct {
270290
271 fn read(self: *MsfStream, buffer: []u8) !usize {291 fn read(self: *MsfStream, buffer: []u8) !usize {
272 var block_id = self.pos / self.block_size;292 var block_id = self.pos / self.block_size;
273 var block = self.blocks.items[block_id];293 var block = self.blocks[block_id];
274 var offset = self.pos % self.block_size;294 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
276 try self.in_file.seekTo(block * self.block_size + offset);300 try self.in_file.seekTo(block * self.block_size + offset);
277 var file_stream = io.FileInStream.init(self.in_file);301 var file_stream = io.FileInStream.init(self.in_file);
278 const in = &file_stream.stream;302 const in = &file_stream.stream;
...@@ -285,11 +309,10 @@ const MsfStream = struct {...@@ -285,11 +309,10 @@ const MsfStream = struct {
285 size += 1;309 size += 1;
286310
287 // If we're at the end of a block, go to the next one.311 // If we're at the end of a block, go to the next one.
288 if (offset == self.block_size)312 if (offset == self.block_size) {
289 {
290 offset = 0;313 offset = 0;
291 block_id += 1;314 block_id += 1;
292 block = self.blocks.items[block_id];315 block = self.blocks[block_id];
293 try self.in_file.seekTo(block * self.block_size);316 try self.in_file.seekTo(block * self.block_size);
294 }317 }
295 }318 }
...@@ -314,9 +337,9 @@ const MsfStream = struct {...@@ -314,9 +337,9 @@ const MsfStream = struct {
314 return self.blocks.len * self.block_size;337 return self.blocks.len * self.block_size;
315 }338 }
316339
317 fn getFilePos(self: *const MsfStream) usize {340 fn getFilePos(self: MsfStream) usize {
318 const block_id = self.pos / self.block_size;341 const block_id = self.pos / self.block_size;
319 const block = self.blocks.items[block_id];342 const block = self.blocks[block_id];
320 const offset = self.pos % self.block_size;343 const offset = self.pos % self.block_size;
321344
322 return block * self.block_size + offset;345 return block * self.block_size + offset;