Commit 46cbed621b

LemonBoy <thatlemon@gmail.com>
2019-05-29 10:30:30
Move dl_iterate_phdr to os.zig
1 parent 4b30e40
Changed files (5)
std/os/bits/freebsd.zig
@@ -20,6 +20,13 @@ pub const pthread_attr_t = extern struct {
     __align: c_long,
 };
 
+pub const dl_phdr_info = extern struct {
+    dlpi_addr: usize,
+    dlpi_name: ?[*]const u8,
+    dlpi_phdr: [*]std.elf.Phdr,
+    dlpi_phnum: u16,
+};
+
 pub const msghdr = extern struct {
     /// optional address
     msg_name: ?*sockaddr,
std/os/bits/netbsd.zig
@@ -20,6 +20,13 @@ pub const pthread_attr_t = extern struct {
     pta_private: *c_void,
 };
 
+pub const dl_phdr_info = extern struct {
+    dlpi_addr: usize,
+    dlpi_name: ?[*]const u8,
+    dlpi_phdr: [*]std.elf.Phdr,
+    dlpi_phnum: u16,
+};
+
 pub const msghdr = extern struct {
     /// optional address
     msg_name: ?*sockaddr,
std/os/linux/test.zig
@@ -44,42 +44,3 @@ test "timer" {
     // TODO implicit cast from *[N]T to [*]T
     err = linux.epoll_wait(@intCast(i32, epoll_fd), @ptrCast([*]linux.epoll_event, &events), 8, -1);
 }
-
-export fn iter_fn(info: *linux.dl_phdr_info, size: usize, data: ?*usize) i32 {
-    var counter = data.?;
-    // Count how many libraries are loaded
-    counter.* += usize(1);
-
-    // The image should contain at least a PT_LOAD segment
-    if (info.dlpi_phnum < 1) return -1;
-
-    // Quick & dirty validation of the phdr pointers, make sure we're not
-    // pointing to some random gibberish
-    var i: usize = 0;
-    var found_load = false;
-    while (i < info.dlpi_phnum) : (i += 1) {
-        const phdr = info.dlpi_phdr[i];
-
-        if (phdr.p_type != elf.PT_LOAD) continue;
-
-        // Find the ELF header
-        const elf_header = @intToPtr(*elf.Ehdr, phdr.p_vaddr - phdr.p_offset);
-        // Validate the magic
-        if (!mem.eql(u8, elf_header.e_ident[0..], "\x7fELF")) return -1;
-        // Consistency check
-        if (elf_header.e_phnum != info.dlpi_phnum) return -1;
-
-        found_load = true;
-        break;
-    }
-
-    if (!found_load) return -1;
-
-    return 42;
-}
-
-test "dl_iterate_phdr" {
-    var counter: usize = 0;
-    expect(linux.dl_iterate_phdr(usize, iter_fn, &counter) != 0);
-    expect(counter != 0);
-}
std/os/test.zig
@@ -5,6 +5,7 @@ const expect = std.testing.expect;
 const io = std.io;
 const fs = std.fs;
 const mem = std.mem;
+const elf = std.elf;
 const File = std.fs.File;
 const Thread = std.Thread;
 
@@ -160,3 +161,52 @@ test "sigaltstack" {
     st.ss_size = 1;
     testing.expectError(error.SizeTooSmall, os.sigaltstack(&st, null));
 }
+
+// If the type is not available use void to avoid erroring out when `iter_fn` is
+// analyzed
+const dl_phdr_info = if (@hasDecl(os, "dl_phdr_info")) os.dl_phdr_info else c_void;
+
+export fn iter_fn(info: *dl_phdr_info, size: usize, data: ?*usize) i32 {
+    if (builtin.os == .windows or builtin.os == .wasi or builtin.os == .macosx)
+        return 0;
+
+    var counter = data.?;
+    // Count how many libraries are loaded
+    counter.* += usize(1);
+
+    // The image should contain at least a PT_LOAD segment
+    if (info.dlpi_phnum < 1) return -1;
+
+    // Quick & dirty validation of the phdr pointers, make sure we're not
+    // pointing to some random gibberish
+    var i: usize = 0;
+    var found_load = false;
+    while (i < info.dlpi_phnum) : (i += 1) {
+        const phdr = info.dlpi_phdr[i];
+
+        if (phdr.p_type != elf.PT_LOAD) continue;
+
+        // Find the ELF header
+        const elf_header = @intToPtr(*elf.Ehdr, phdr.p_vaddr - phdr.p_offset);
+        // Validate the magic
+        if (!mem.eql(u8, elf_header.e_ident[0..4], "\x7fELF")) return -1;
+        // Consistency check
+        if (elf_header.e_phnum != info.dlpi_phnum) return -1;
+
+        found_load = true;
+        break;
+    }
+
+    if (!found_load) return -1;
+
+    return 42;
+}
+
+test "dl_iterate_phdr" {
+    if (builtin.os == .windows or builtin.os == .wasi or builtin.os == .macosx)
+        return error.SkipZigTest;
+
+    var counter: usize = 0;
+    expect(os.dl_iterate_phdr(usize, iter_fn, &counter) != 0);
+    expect(counter != 0);
+}
std/os.zig
@@ -19,6 +19,8 @@ const builtin = @import("builtin");
 const assert = std.debug.assert;
 const math = std.math;
 const mem = std.mem;
+const elf = std.elf;
+const dl = @import("dynamic_library.zig");
 const MAX_PATH_BYTES = std.fs.MAX_PATH_BYTES;
 
 comptime {
@@ -2367,6 +2369,70 @@ pub fn nanosleep(seconds: u64, nanoseconds: u64) void {
     }
 }
 
+pub fn dl_iterate_phdr(comptime T: type, callback: extern fn (info: *dl_phdr_info, size: usize, data: ?*T) i32, data: ?*T) isize {
+    // This is implemented only for systems using ELF executables
+    if (windows.is_the_target or builtin.os == .uefi or wasi.is_the_target or darwin.is_the_target)
+        @compileError("dl_iterate_phdr is not available for this target");
+
+    if (builtin.link_libc) {
+        return system.dl_iterate_phdr(
+            @ptrCast(std.c.dl_iterate_phdr_callback, callback),
+            @ptrCast(?*c_void, data),
+        );
+    }
+
+    const elf_base = std.process.getBaseAddress();
+    const ehdr = @intToPtr(*elf.Ehdr, elf_base);
+    // Make sure the base address points to an ELF image
+    assert(mem.eql(u8, ehdr.e_ident[0..4], "\x7fELF"));
+    const n_phdr = ehdr.e_phnum;
+    const phdrs = (@intToPtr([*]elf.Phdr, elf_base + ehdr.e_phoff))[0..n_phdr];
+
+    var it = dl.linkmap_iterator(phdrs) catch unreachable;
+
+    // The executable has no dynamic link segment, create a single entry for
+    // the whole ELF image
+    if (it.end()) {
+        var info = dl_phdr_info{
+            .dlpi_addr = elf_base,
+            .dlpi_name = c"/proc/self/exe",
+            .dlpi_phdr = phdrs.ptr,
+            .dlpi_phnum = ehdr.e_phnum,
+        };
+
+        return callback(&info, @sizeOf(dl_phdr_info), data);
+    }
+
+    // Last return value from the callback function
+    var last_r: isize = 0;
+    while (it.next()) |entry| {
+        var dlpi_phdr: [*]elf.Phdr = undefined;
+        var dlpi_phnum: u16 = undefined;
+
+        if (entry.l_addr != 0) {
+            const elf_header = @intToPtr(*elf.Ehdr, entry.l_addr);
+            dlpi_phdr = @intToPtr([*]elf.Phdr, entry.l_addr + elf_header.e_phoff);
+            dlpi_phnum = elf_header.e_phnum;
+        } else {
+            // This is the running ELF image
+            dlpi_phdr = @intToPtr([*]elf.Phdr, elf_base + ehdr.e_phoff);
+            dlpi_phnum = ehdr.e_phnum;
+        }
+
+        var info = dl_phdr_info{
+            .dlpi_addr = entry.l_addr,
+            .dlpi_name = entry.l_name,
+            .dlpi_phdr = dlpi_phdr,
+            .dlpi_phnum = dlpi_phnum,
+        };
+
+        last_r = callback(&info, @sizeOf(dl_phdr_info), data);
+        if (last_r != 0) break;
+    }
+
+    return last_r;
+}
+
 pub const ClockGetTimeError = error{
     UnsupportedClock,
     Unexpected,