Created
November 20, 2024 23:07
-
-
Save leroycep/cf4cd7625a9f929104ff3f9b73e58736 to your computer and use it in GitHub Desktop.
Finding symbol name from program address in EXEC type ELF files
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const std = @import("std"); | |
pub fn build(b: *std.Build) !void { | |
const exe = b.addExecutable(.{ | |
.name = "symbol_from_address", | |
.root_source_file = b.path("./main.zig"), | |
.target = b.standardTargetOptions(.{}), | |
.optimize = b.standardOptimizeOption(.{}), | |
}); | |
exe.root_module.omit_frame_pointer = false; | |
const stripped_exe = b.addObjCopy(exe.getEmittedBin(), .{ | |
.basename = exe.out_filename, // set the name for the debuglink | |
.strip = .debug, | |
}); | |
b.getInstallStep().dependOn(&b.addInstallBinFile( | |
stripped_exe.getOutput(), | |
exe.out_filename, | |
).step); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const std = @import("std"); | |
const posix = std.posix; | |
const elf = std.elf; | |
const builtin = @import("builtin"); | |
const native_endian = builtin.cpu.arch.endian(); | |
pub fn main() !void { | |
const elf_file = try std.fs.openSelfExe(.{}); | |
defer elf_file.close(); | |
const elf_contents = try mapWholeFile(elf_file); | |
defer std.posix.munmap(elf_contents); | |
const hdr: *const elf.Ehdr = @ptrCast(&elf_contents[0]); | |
if (!std.mem.eql(u8, hdr.e_ident[0..4], elf.MAGIC)) return error.InvalidElfMagic; | |
if (hdr.e_ident[elf.EI_VERSION] != 1) return error.InvalidElfVersion; | |
const endian: std.builtin.Endian = switch (hdr.e_ident[elf.EI_DATA]) { | |
elf.ELFDATA2LSB => .little, | |
elf.ELFDATA2MSB => .big, | |
else => return error.InvalidElfEndian, | |
}; | |
if (endian != native_endian) return error.UnimplementedDwarfForeignEndian; | |
const shoff = hdr.e_shoff; | |
const str_section_off = shoff + @as(u64, hdr.e_shentsize) * @as(u64, hdr.e_shstrndx); | |
const str_shdr: *const elf.Shdr = @ptrCast(@alignCast(&elf_contents[std.math.cast(usize, str_section_off) orelse return error.Overflow])); | |
const header_strings = elf_contents[str_shdr.sh_offset..][0..str_shdr.sh_size]; | |
const section_headers = @as( | |
[*]const elf.Shdr, | |
@ptrCast(@alignCast(&elf_contents[shoff])), | |
)[0..hdr.e_shnum]; | |
const address_looking_for = thisFnAddress(); | |
var symbol_string_table_opt: ?[]const u8 = null; | |
var address_section_index: ?usize = null; | |
for (section_headers, 0..) |section_header, i| { | |
const name_opt = getStringFromTable(header_strings, section_header.sh_name); | |
if (section_header.sh_type == elf.SHT_STRTAB and name_opt != null and std.mem.eql(u8, name_opt.?, ".strtab")) { | |
if (symbol_string_table_opt != null) { | |
@panic("TODO: handling multiple symbol string tables not implemented yet"); | |
} | |
symbol_string_table_opt = elf_contents[section_header.sh_offset..][0..section_header.sh_size]; | |
} | |
if (address_looking_for >= section_header.sh_addr and address_looking_for <= section_header.sh_addr + section_header.sh_size) { | |
// std.debug.print("Found address (0x{x}) in section \"{}\" (0x{x}, {:.0})\n", .{ address_looking_for, std.zig.fmtEscapes(name_opt orelse ""), section_header.sh_addr, std.fmt.fmtIntSizeBin(section_header.sh_size) }); | |
address_section_index = i; | |
} | |
} | |
const symbol_string_table = symbol_string_table_opt orelse { | |
std.debug.print("no string table found", .{}); | |
return; | |
}; | |
std.debug.print("symbol\tvalue\tsize\tbind\ttype\n", .{}); | |
for (section_headers) |section_header| { | |
if (section_header.sh_type != elf.SHT_SYMTAB) { | |
continue; | |
} | |
const symbols = @as([*]const elf.Sym, @ptrCast(@alignCast(&elf_contents[section_header.sh_offset])))[0 .. section_header.sh_size / section_header.sh_entsize]; | |
for (symbols) |symbol| { | |
if (symbol.st_name == 0) continue; | |
if (symbol.st_shndx == elf.SHN_UNDEF) continue; | |
if (address_section_index != null and symbol.st_shndx != address_section_index.?) { | |
continue; | |
} | |
const symbol_name = getStringFromTable(symbol_string_table, symbol.st_name) orelse continue; | |
if (symbol.st_shndx == elf.SHN_ABS) { | |
std.debug.print("\"{}\"\t0x{x}\t{}\n", .{ std.zig.fmtEscapes(symbol_name), symbol.st_value, std.fmt.fmtIntSizeBin(symbol.st_size) }); | |
continue; | |
} | |
const symbol_section_header = section_headers[symbol.st_shndx]; | |
const symbol_start_address = switch (hdr.e_type) { | |
.EXEC => symbol.st_value, | |
.DYN => symbol_section_header.sh_addr + symbol.st_value, | |
else => std.debug.panic("Unhandled ELF file type: {}", .{hdr.e_type}), | |
}; | |
const symbol_end_address = symbol_start_address + symbol.st_size; | |
// std.debug.print("\"{}\"\t0x{x}\t{}\t{}\t{s}\n", .{ | |
// std.zig.fmtEscapes(symbol_name), | |
// symbol_start_address, | |
// std.fmt.fmtIntSizeBin(symbol.st_size), | |
// symbol.st_info >> 4, | |
// switch (symbol.st_info & 0xf) { | |
// elf.STT_NOTYPE => "notype", | |
// elf.STT_OBJECT => "object", | |
// elf.STT_FUNC => "fn", | |
// elf.STT_SECTION => "section", | |
// elf.STT_FILE => "file", | |
// elf.STT_COMMON => "common", | |
// elf.STT_TLS => "thread_local_storage", | |
// else => "other", | |
// }, | |
// }); | |
if (address_looking_for >= symbol_start_address and address_looking_for <= symbol_end_address) { | |
std.debug.print("\n\nFound symbol containing address:\n looking for = 0x{x}\n symbol name = \"{}\"\n symbol start = 0x{x}\n symbol end = 0x{x}\n", .{ | |
address_looking_for, | |
std.zig.fmtEscapes(symbol_name), | |
symbol_start_address, | |
symbol_end_address, | |
}); | |
return; | |
} | |
} | |
} | |
std.debug.print("looking_for_this\t0x{x}\t\"\"\n", .{address_looking_for}); | |
} | |
fn getStringFromTable(string_table: []const u8, pos: usize) ?[]const u8 { | |
const section_name_end = std.mem.indexOfScalarPos(u8, string_table, pos, '\x00') orelse return null; | |
return string_table[pos..section_name_end]; | |
} | |
noinline fn thisFnAddress() usize { | |
return @returnAddress(); | |
} | |
fn mapWholeFile(file: std.fs.File) ![]align(std.mem.page_size) const u8 { | |
const file_len = std.math.cast(usize, try file.getEndPos()) orelse std.math.maxInt(usize); | |
const mapped_mem = try std.posix.mmap( | |
null, | |
file_len, | |
std.posix.PROT.READ, | |
.{ .TYPE = .SHARED }, | |
file.handle, | |
0, | |
); | |
errdefer std.posix.munmap(mapped_mem); | |
return mapped_mem; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
In ReleaseFast:
In Debug: