Skip to content

Commit

Permalink
Merge pull request #90 from kubkon/better-error-handling
Browse files Browse the repository at this point in the history
Better error handling
  • Loading branch information
kubkon authored Dec 16, 2023
2 parents 5c2c367 + 5a4b21f commit 658e836
Show file tree
Hide file tree
Showing 16 changed files with 278 additions and 147 deletions.
68 changes: 43 additions & 25 deletions src/Elf.zig
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,6 @@ has_text_reloc: bool = false,
num_ifunc_dynrelocs: usize = 0,
default_sym_version: elf.Elf64_Versym,

file_resolution_error: bool = false,

pub fn openPath(allocator: Allocator, options: Options, thread_pool: *ThreadPool) !*Elf {
const file = try options.emit.directory.createFile(options.emit.sub_path, .{
.truncate = true,
Expand Down Expand Up @@ -223,7 +221,7 @@ fn resolveFile(
if (try getFullPath(arena, search_dir, path, .ar)) |full_path| break :full_path full_path;
}
self.base.fatal("library not found '{s}'", .{path});
return error.ResolveFail;
return error.FileNotFound;
}

const path = path: {
Expand All @@ -234,7 +232,7 @@ fn resolveFile(
if (try getFullPath(arena, search_dir, obj.path, .none)) |path| break :path path;
}
self.base.fatal("file not found '{s}'", .{obj.path});
return error.ResolveFail;
return error.FileNotFound;
},
else => |e| return e,
};
Expand Down Expand Up @@ -288,18 +286,30 @@ pub fn flush(self: *Elf) !void {
log.debug(" -L{s}", .{dir});
}

var has_parse_error = false;
for (self.options.positionals) |obj| {
try self.parsePositional(arena, obj, search_dirs.items);
self.parsePositional(arena, obj, search_dirs.items) catch |err| {
has_parse_error = true;
switch (err) {
error.FileNotFound, error.ParseFailed => {}, // already reported
else => |e| {
self.base.fatal("{s}: unexpected error occurred while parsing input file: {s}", .{
obj.path, @errorName(e),
});
return e;
},
}
};
}

if (self.file_resolution_error) {
if (has_parse_error) {
const err = try self.base.addErrorWithNotes(search_dirs.items.len);
try err.addMsg("library search paths", .{});
for (search_dirs.items) |dir| {
try err.addNote(" {s}", .{dir});
}
return error.ParseFailed;
}
self.base.reportWarningsAndErrorsAndExit();

// Dedup DSOs
{
Expand Down Expand Up @@ -352,8 +362,7 @@ pub fn flush(self: *Elf) !void {
}

if (!self.options.allow_multiple_definition) {
self.checkDuplicates();
self.base.reportWarningsAndErrorsAndExit();
try self.checkDuplicates();
}

try self.initOutputSections();
Expand Down Expand Up @@ -400,8 +409,6 @@ pub fn flush(self: *Elf) !void {
try self.writePhdrs();
try self.writeShdrs();
try self.writeHeader();

self.base.reportWarningsAndErrorsAndExit();
}

/// We need to sort constructors/destuctors in the following sections:
Expand Down Expand Up @@ -1615,13 +1622,7 @@ fn allocateSyntheticSymbols(self: *Elf) void {
}

fn parsePositional(self: *Elf, arena: Allocator, obj: LinkObject, search_dirs: []const []const u8) anyerror!void {
const resolved_obj = self.resolveFile(arena, obj, search_dirs) catch |err| switch (err) {
error.ResolveFail => {
self.file_resolution_error = true;
return;
},
else => |e| return e,
};
const resolved_obj = try self.resolveFile(arena, obj, search_dirs);

log.debug("parsing positional argument '{s}'", .{resolved_obj.path});

Expand Down Expand Up @@ -1674,14 +1675,22 @@ fn parseArchive(self: *Elf, arena: Allocator, obj: LinkObject) !bool {
defer archive.deinit(gpa);
try archive.parse(arena, self);

var has_parse_error = false;
for (archive.objects.items) |extracted| {
const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
self.files.set(index, .{ .object = extracted });
const object = &self.files.items(.data)[index].object;
object.index = index;
try object.parse(self);
object.parse(self) catch |err| switch (err) {
error.ParseFailed => {
has_parse_error = true;
continue;
},
else => |e| return e,
};
try self.objects.append(gpa, index);
}
if (has_parse_error) return error.ParseFailed;

return true;
}
Expand Down Expand Up @@ -1956,8 +1965,14 @@ fn resolveSyntheticSymbols(self: *Elf) !void {
internal.resolveSymbols(self);
}

fn checkDuplicates(self: *Elf) void {
for (self.objects.items) |index| self.getFile(index).?.object.checkDuplicates(self);
fn checkDuplicates(self: *Elf) !void {
var has_dupes = false;
for (self.objects.items) |index| {
if (self.getFile(index).?.object.checkDuplicates(self)) {
has_dupes = true;
}
}
if (has_dupes) return error.MultipleSymbolDefinition;
}

fn claimUnresolved(self: *Elf) void {
Expand Down Expand Up @@ -2017,15 +2032,19 @@ fn reportUndefs(self: *Elf) !void {
try err.addNote("referenced {d} more times", .{remaining});
}
}
return error.UndefinedSymbols;
}

fn scanRelocs(self: *Elf) !void {
var has_reloc_error = false;
for (self.objects.items) |index| {
try self.getFile(index).?.object.scanRelocs(self);
self.getFile(index).?.object.scanRelocs(self) catch |err| switch (err) {
error.RelocError => has_reloc_error = true,
else => |e| return e,
};
}

try self.reportUndefs();
self.base.reportWarningsAndErrorsAndExit();
if (has_reloc_error) return error.RelocError;

for (self.symbols.items, 0..) |*symbol, i| {
const index = @as(u32, @intCast(i));
Expand Down Expand Up @@ -2161,7 +2180,6 @@ fn writeAtoms(self: *Elf) !void {
}

try self.reportUndefs();
self.base.reportWarningsAndErrorsAndExit();
}

fn writeSyntheticSections(self: *Elf) !void {
Expand Down
10 changes: 6 additions & 4 deletions src/Elf/Archive.zig
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@ pub fn parse(self: *Archive, arena: Allocator, elf_file: *Elf) !void {
const hdr = reader.readStruct(elf.ar_hdr) catch break;

if (!mem.eql(u8, &hdr.ar_fmag, elf.ARFMAG)) {
return elf_file.base.fatal(
"{s}: invalid header delimiter: expected '{s}', found '{s}'",
.{ self.path, std.fmt.fmtSliceEscapeLower(elf.ARFMAG), std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag) },
);
elf_file.base.fatal("{s}: invalid header delimiter: expected '{s}', found '{s}'", .{
self.path,
std.fmt.fmtSliceEscapeLower(elf.ARFMAG),
std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag),
});
return error.ParseFailed;
}

const size = try hdr.size();
Expand Down
55 changes: 37 additions & 18 deletions src/Elf/Atom.zig
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf) !void {
const relocs = self.getRelocs(elf_file);
const code = try self.getCodeUncompressAlloc(elf_file);
defer elf_file.base.allocator.free(code);

var has_errors = false;
var i: usize = 0;
while (i < relocs.len) : (i += 1) {
const rel = relocs[i];
Expand All @@ -159,13 +161,17 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf) !void {
// pointer indirection via GOT, or a stub trampoline via PLT.
switch (rel.r_type()) {
elf.R_X86_64_64 => {
self.scanReloc(symbol, rel, getDynAbsRelocAction(symbol, elf_file), elf_file);
self.scanReloc(symbol, rel, getDynAbsRelocAction(symbol, elf_file), elf_file) catch {
has_errors = true;
};
},

elf.R_X86_64_32,
elf.R_X86_64_32S,
=> {
self.scanReloc(symbol, rel, getAbsRelocAction(symbol, elf_file), elf_file);
self.scanReloc(symbol, rel, getAbsRelocAction(symbol, elf_file), elf_file) catch {
has_errors = true;
};
},

elf.R_X86_64_GOT32,
Expand All @@ -189,7 +195,9 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf) !void {
},

elf.R_X86_64_PC32 => {
self.scanReloc(symbol, rel, getPcRelocAction(symbol, elf_file), elf_file);
self.scanReloc(symbol, rel, getPcRelocAction(symbol, elf_file), elf_file) catch {
has_errors = true;
};
},

elf.R_X86_64_TLSGD => {
Expand Down Expand Up @@ -245,7 +253,9 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf) !void {
elf.R_X86_64_TPOFF32,
elf.R_X86_64_TPOFF64,
=> {
if (is_shared) self.picError(symbol, rel, elf_file);
if (is_shared) self.picError(symbol, rel, elf_file) catch {
has_errors = true;
};
},

elf.R_X86_64_GOTOFF64,
Expand All @@ -256,39 +266,44 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf) !void {
elf.R_X86_64_TLSDESC_CALL,
=> {},

else => elf_file.base.fatal("{s}: unknown relocation type: {}", .{
self.getName(elf_file),
fmtRelocType(rel.r_type()),
}),
else => {
elf_file.base.fatal("{s}: unknown relocation type: {}", .{
self.getName(elf_file),
fmtRelocType(rel.r_type()),
});
has_errors = true;
},
}
}

if (has_errors) return error.RelocError;
}

fn scanReloc(self: Atom, symbol: *Symbol, rel: elf.Elf64_Rela, action: RelocAction, elf_file: *Elf) void {
fn scanReloc(self: Atom, symbol: *Symbol, rel: elf.Elf64_Rela, action: RelocAction, elf_file: *Elf) !void {
const is_writeable = self.getInputShdr(elf_file).sh_flags & elf.SHF_WRITE != 0;
const object = self.getObject(elf_file);

switch (action) {
.none => {},

.@"error" => if (symbol.isAbs(elf_file))
self.noPicError(symbol, rel, elf_file)
try self.noPicError(symbol, rel, elf_file)
else
self.picError(symbol, rel, elf_file),
try self.picError(symbol, rel, elf_file),

.copyrel => {
if (elf_file.options.z_nocopyreloc) {
if (symbol.isAbs(elf_file))
self.noPicError(symbol, rel, elf_file)
try self.noPicError(symbol, rel, elf_file)
else
self.picError(symbol, rel, elf_file);
try self.picError(symbol, rel, elf_file);
}
symbol.flags.copy_rel = true;
},

.dyn_copyrel => {
if (is_writeable or elf_file.options.z_nocopyreloc) {
self.textReloc(symbol, elf_file);
try self.textReloc(symbol, elf_file);
object.num_dynrelocs += 1;
} else {
symbol.flags.copy_rel = true;
Expand All @@ -314,15 +329,15 @@ fn scanReloc(self: Atom, symbol: *Symbol, rel: elf.Elf64_Rela, action: RelocActi
},

.dynrel, .baserel, .ifunc => {
self.textReloc(symbol, elf_file);
try self.textReloc(symbol, elf_file);
object.num_dynrelocs += 1;

if (action == .ifunc) elf_file.num_ifunc_dynrelocs += 1;
},
}
}

inline fn textReloc(self: Atom, symbol: *const Symbol, elf_file: *Elf) void {
inline fn textReloc(self: Atom, symbol: *const Symbol, elf_file: *Elf) !void {
const is_writeable = self.getInputShdr(elf_file).sh_flags & elf.SHF_WRITE != 0;
if (!is_writeable) {
if (elf_file.options.z_text) {
Expand All @@ -331,13 +346,14 @@ inline fn textReloc(self: Atom, symbol: *const Symbol, elf_file: *Elf) void {
self.getName(elf_file),
symbol.getName(elf_file),
});
return error.RelocError;
} else {
elf_file.has_text_reloc = true;
}
}
}

inline fn noPicError(self: Atom, symbol: *const Symbol, rel: elf.Elf64_Rela, elf_file: *Elf) void {
inline fn noPicError(self: Atom, symbol: *const Symbol, rel: elf.Elf64_Rela, elf_file: *Elf) !void {
elf_file.base.fatal(
"{s}: {s}: {} relocation at offset 0x{x} against symbol '{s}' cannot be used; recompile with -fno-PIC",
.{
Expand All @@ -348,9 +364,10 @@ inline fn noPicError(self: Atom, symbol: *const Symbol, rel: elf.Elf64_Rela, elf
symbol.getName(elf_file),
},
);
return error.RelocError;
}

inline fn picError(self: Atom, symbol: *const Symbol, rel: elf.Elf64_Rela, elf_file: *Elf) void {
inline fn picError(self: Atom, symbol: *const Symbol, rel: elf.Elf64_Rela, elf_file: *Elf) !void {
elf_file.base.fatal(
"{s}: {s}: {} relocation at offset 0x{x} against symbol '{s}' cannot be used; recompile with -fPIC",
.{
Expand All @@ -361,6 +378,7 @@ inline fn picError(self: Atom, symbol: *const Symbol, rel: elf.Elf64_Rela, elf_f
symbol.getName(elf_file),
},
);
return error.RelocError;
}

const RelocAction = enum {
Expand Down Expand Up @@ -460,6 +478,7 @@ fn reportUndefSymbol(self: Atom, rel: elf.Elf64_Rela, elf_file: *Elf) !bool {
gop.value_ptr.* = .{};
}
try gop.value_ptr.append(gpa, self.atom_index);
return true;
}

return false;
Expand Down
Loading

0 comments on commit 658e836

Please sign in to comment.