printing info from the ModuleInfo substream of DebugInfo

This commit is contained in:
Andrew Kelley 2018-08-29 19:00:24 -04:00
parent f1b71053de
commit 686663239a
5 changed files with 120 additions and 57 deletions

View File

@ -41,7 +41,7 @@ pub const Coff = struct {
pub fn loadHeader(self: *Coff) !void {
const pe_pointer_offset = 0x3C;
var file_stream = io.FileInStream.init(&self.in_file);
var file_stream = io.FileInStream.init(self.in_file);
const in = &file_stream.stream;
var magic: [2]u8 = undefined;
@ -126,7 +126,7 @@ pub const Coff = struct {
std.debug.warn("file offset {x}\n", file_offset);
try self.in_file.seekTo(file_offset + debug_dir.size);
var file_stream = io.FileInStream.init(&self.in_file);
var file_stream = io.FileInStream.init(self.in_file);
const in = &file_stream.stream;
var cv_signature: [4]u8 = undefined; // CodeView signature
@ -158,7 +158,7 @@ pub const Coff = struct {
self.sections = ArrayList(Section).init(self.allocator);
var file_stream = io.FileInStream.init(&self.in_file);
var file_stream = io.FileInStream.init(self.in_file);
const in = &file_stream.stream;
var name: [8]u8 = undefined;
@ -235,4 +235,4 @@ const SectionHeader = struct {
number_of_relocations: u16,
number_of_line_numbers: u16,
characteristics: u32,
};
};

View File

@ -40,7 +40,7 @@ pub fn getStderrStream() !*io.OutStream(io.FileOutStream.Error) {
return st;
} else {
stderr_file = try io.getStdErr();
stderr_file_out_stream = io.FileOutStream.init(&stderr_file);
stderr_file_out_stream = io.FileOutStream.init(stderr_file);
const st = &stderr_file_out_stream.stream;
stderr_stream = st;
return st;
@ -73,7 +73,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
return;
};
writeCurrentStackTrace(stderr, getDebugInfoAllocator(), debug_info, wantTtyColor(), start_addr) catch |err| {
writeCurrentStackTrace(stderr, debug_info, wantTtyColor(), start_addr) catch |err| {
stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
return;
};
@ -194,9 +194,9 @@ pub inline fn getReturnAddress(frame_count: usize) usize {
return @intToPtr(*const usize, fp + @sizeOf(usize)).*;
}
pub fn writeCurrentStackTrace(out_stream: var, allocator: *mem.Allocator, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void {
pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void {
switch (builtin.os) {
builtin.Os.windows => return writeCurrentStackTraceWindows(out_stream, allocator, debug_info, tty_color, start_addr),
builtin.Os.windows => return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr),
else => {},
}
const AddressState = union(enum) {
@ -231,7 +231,7 @@ pub fn writeCurrentStackTrace(out_stream: var, allocator: *mem.Allocator, debug_
}
}
pub fn writeCurrentStackTraceWindows(out_stream: var, allocator: *mem.Allocator, debug_info: *DebugInfo,
pub fn writeCurrentStackTraceWindows(out_stream: var, debug_info: *DebugInfo,
tty_color: bool, start_addr: ?usize) !void
{
var addr_buf: [1024]usize = undefined;

View File

@ -34,13 +34,13 @@ pub fn getStdIn() GetStdIoErrs!File {
/// Implementation of InStream trait for File
pub const FileInStream = struct {
file: *File,
file: File,
stream: Stream,
pub const Error = @typeOf(File.read).ReturnType.ErrorSet;
pub const Stream = InStream(Error);
pub fn init(file: *File) FileInStream {
pub fn init(file: File) FileInStream {
return FileInStream{
.file = file,
.stream = Stream{ .readFn = readFn },
@ -55,13 +55,13 @@ pub const FileInStream = struct {
/// Implementation of OutStream trait for File
pub const FileOutStream = struct {
file: *File,
file: File,
stream: Stream,
pub const Error = File.WriteError;
pub const Stream = OutStream(Error);
pub fn init(file: *File) FileOutStream {
pub fn init(file: File) FileOutStream {
return FileOutStream{
.file = file,
.stream = Stream{ .writeFn = writeFn },

View File

@ -205,17 +205,16 @@ pub const File = struct {
/// Upon success, the stream is in an uninitialized state. To continue using it,
/// you must use the open() function.
pub fn close(self: *File) void {
pub fn close(self: File) void {
os.close(self.handle);
self.handle = undefined;
}
/// Calls `os.isTty` on `self.handle`.
pub fn isTty(self: *File) bool {
pub fn isTty(self: File) bool {
return os.isTty(self.handle);
}
pub fn seekForward(self: *File, amount: isize) !void {
pub fn seekForward(self: File, amount: isize) !void {
switch (builtin.os) {
Os.linux, Os.macosx, Os.ios => {
const result = posix.lseek(self.handle, amount, posix.SEEK_CUR);
@ -246,7 +245,7 @@ pub const File = struct {
}
}
pub fn seekTo(self: *File, pos: usize) !void {
pub fn seekTo(self: File, pos: usize) !void {
switch (builtin.os) {
Os.linux, Os.macosx, Os.ios => {
const ipos = try math.cast(isize, pos);
@ -280,7 +279,7 @@ pub const File = struct {
}
}
pub fn getPos(self: *File) !usize {
pub fn getPos(self: File) !usize {
switch (builtin.os) {
Os.linux, Os.macosx, Os.ios => {
const result = posix.lseek(self.handle, 0, posix.SEEK_CUR);
@ -316,7 +315,7 @@ pub const File = struct {
}
}
pub fn getEndPos(self: *File) !usize {
pub fn getEndPos(self: File) !usize {
if (is_posix) {
const stat = try os.posixFStat(self.handle);
return @intCast(usize, stat.size);
@ -341,7 +340,7 @@ pub const File = struct {
Unexpected,
};
pub fn mode(self: *File) ModeError!Mode {
pub fn mode(self: File) ModeError!Mode {
if (is_posix) {
var stat: posix.Stat = undefined;
const err = posix.getErrno(posix.fstat(self.handle, &stat));
@ -375,7 +374,7 @@ pub const File = struct {
Unexpected,
};
pub fn read(self: *File, buffer: []u8) ReadError!usize {
pub fn read(self: File, buffer: []u8) ReadError!usize {
if (is_posix) {
var index: usize = 0;
while (index < buffer.len) {
@ -423,7 +422,7 @@ pub const File = struct {
pub const WriteError = os.WindowsWriteError || os.PosixWriteError;
pub fn write(self: *File, bytes: []const u8) WriteError!void {
pub fn write(self: File, bytes: []const u8) WriteError!void {
if (is_posix) {
try os.posixWrite(self.handle, bytes);
} else if (is_windows) {

View File

@ -8,9 +8,58 @@ const warn = std.debug.warn;
const ArrayList = std.ArrayList;
pub const PdbError = error {
InvalidPdbMagic,
CorruptedFile,
// https://llvm.org/docs/PDB/DbiStream.html#stream-header
const DbiStreamHeader = packed struct {
VersionSignature: i32,
VersionHeader: u32,
Age: u32,
GlobalStreamIndex: u16,
BuildNumber: u16,
PublicStreamIndex: u16,
PdbDllVersion: u16,
SymRecordStream: u16,
PdbDllRbld: u16,
ModInfoSize: u32,
SectionContributionSize: i32,
SectionMapSize: i32,
SourceInfoSize: i32,
TypeServerSize: i32,
MFCTypeServerIndex: u32,
OptionalDbgHeaderSize: i32,
ECSubstreamSize: i32,
Flags: u16,
Machine: u16,
Padding: u32,
};
const SectionContribEntry = packed struct {
Section: u16,
Padding1: [2]u8,
Offset: i32,
Size: i32,
Characteristics: u32,
ModuleIndex: u16,
Padding2: [2]u8,
DataCrc: u32,
RelocCrc: u32,
};
const ModInfo = packed struct {
Unused1: u32,
SectionContr: SectionContribEntry,
Flags: u16,
ModuleSymStream: u16,
SymByteSize: u32,
C11ByteSize: u32,
C13ByteSize: u32,
SourceFileCount: u16,
Padding: [2]u8,
Unused2: u32,
SourceFileNameIndex: u32,
PdbFilePathNameIndex: u32,
// These fields are variable length
//ModuleName: char[],
//ObjFileName: char[],
};
pub const StreamType = enum(u16) {
@ -30,7 +79,7 @@ pub const Pdb = struct {
self.in_file = try os.File.openRead(file_name[0..]);
self.allocator = allocator;
try self.msf.openFile(allocator, &self.in_file);
try self.msf.openFile(allocator, self.in_file);
}
pub fn getStream(self: *Pdb, stream: StreamType) ?*MsfStream {
@ -41,29 +90,32 @@ pub const Pdb = struct {
}
pub fn getSourceLine(self: *Pdb, address: usize) !void {
const dbi = self.getStream(StreamType.Dbi) orelse return error.CorruptedFile;
const dbi = self.getStream(StreamType.Dbi) orelse return error.InvalidDebugInfo;
// Dbi Header
try dbi.seekForward(@sizeOf(u32) * 3 + @sizeOf(u16) * 6);
warn("dbi stream at {} (file offset)\n", dbi.getFilePos());
const module_info_size = try dbi.stream.readIntLe(u32);
const section_contribution_size = try dbi.stream.readIntLe(u32);
const section_map_size = try dbi.stream.readIntLe(u32);
const source_info_size = try dbi.stream.readIntLe(u32);
warn("module_info_size: {}\n", module_info_size);
warn("section_contribution_size: {}\n", section_contribution_size);
warn("section_map_size: {}\n", section_map_size);
warn("source_info_size: {}\n", source_info_size);
try dbi.seekForward(@sizeOf(u32) * 5 + @sizeOf(u16) * 2);
var header: DbiStreamHeader = undefined;
try dbi.stream.readStruct(DbiStreamHeader, &header);
std.debug.warn("{}\n", header);
warn("after header dbi stream at {} (file offset)\n", dbi.getFilePos());
// Module Info Substream
try dbi.seekForward(@sizeOf(u32) + @sizeOf(u16) + @sizeOf(u8) * 2);
const offset = try dbi.stream.readIntLe(u32);
const size = try dbi.stream.readIntLe(u32);
try dbi.seekForward(@sizeOf(u32));
const module_index = try dbi.stream.readIntLe(u16);
warn("module {} of size {} at {}\n", module_index, size, offset);
var mod_info_offset: usize = 0;
while (mod_info_offset < header.ModInfoSize) {
var mod_info: ModInfo = undefined;
try dbi.stream.readStruct(ModInfo, &mod_info);
std.debug.warn("{}\n", mod_info);
mod_info_offset += @sizeOf(ModInfo);
const module_name = try dbi.readNullTermString(self.allocator);
std.debug.warn("module_name {}\n", module_name);
mod_info_offset += module_name.len + 1;
const obj_file_name = try dbi.readNullTermString(self.allocator);
std.debug.warn("obj_file_name {}\n", obj_file_name);
mod_info_offset += obj_file_name.len + 1;
}
std.debug.warn("end modules\n");
// TODO: locate corresponding source line information
}
@ -75,7 +127,7 @@ const Msf = struct {
directory: MsfStream,
streams: ArrayList(MsfStream),
fn openFile(self: *Msf, allocator: *mem.Allocator, file: *os.File) !void {
fn openFile(self: *Msf, allocator: *mem.Allocator, file: os.File) !void {
var file_stream = io.FileInStream.init(file);
const in = &file_stream.stream;
@ -84,7 +136,7 @@ const Msf = struct {
warn("magic: '{}'\n", magic);
if (!mem.eql(u8, magic, SuperBlock.FileMagic))
return error.InvalidPdbMagic;
return error.InvalidDebugInfo;
self.superblock = SuperBlock {
.block_size = try in.readIntLe(u32),
@ -97,11 +149,11 @@ const Msf = struct {
switch (self.superblock.block_size) {
512, 1024, 2048, 4096 => {}, // llvm only uses 4096
else => return error.InvalidPdbMagic
else => return error.InvalidDebugInfo
}
if (self.superblock.fileSize() != try file.getEndPos())
return error.CorruptedFile; // Should always stand.
return error.InvalidDebugInfo; // Should always stand.
self.directory = try MsfStream.init(
self.superblock.block_size,
@ -165,12 +217,18 @@ const SuperBlock = struct {
};
const MsfStream = struct {
in_file: *os.File,
in_file: os.File,
pos: usize,
blocks: ArrayList(u32),
block_size: u32,
fn init(block_size: u32, block_count: u32, pos: usize, file: *os.File, allocator: *mem.Allocator) !MsfStream {
/// Implementation of InStream trait for Pdb.MsfStream
stream: Stream,
pub const Error = @typeOf(read).ReturnType.ErrorSet;
pub const Stream = io.InStream(Error);
fn init(block_size: u32, block_count: u32, pos: usize, file: os.File, allocator: *mem.Allocator) !MsfStream {
var stream = MsfStream {
.in_file = file,
.pos = 0,
@ -198,6 +256,18 @@ const MsfStream = struct {
return stream;
}
fn readNullTermString(self: *MsfStream, allocator: *mem.Allocator) ![]u8 {
var list = ArrayList(u8).init(allocator);
defer list.deinit();
while (true) {
const byte = try self.stream.readByte();
if (byte == 0) {
return list.toSlice();
}
try list.append(byte);
}
}
fn read(self: *MsfStream, buffer: []u8) !usize {
var block_id = self.pos / self.block_size;
var block = self.blocks.items[block_id];
@ -252,12 +322,6 @@ const MsfStream = struct {
return block * self.block_size + offset;
}
/// Implementation of InStream trait for Pdb.MsfStream
pub const Error = @typeOf(read).ReturnType.ErrorSet;
pub const Stream = io.InStream(Error);
stream: Stream,
fn readFn(in_stream: *Stream, buffer: []u8) Error!usize {
const self = @fieldParentPtr(MsfStream, "stream", in_stream);
return self.read(buffer);