#ifdef _STANDALONE
#include "stand.h"
#define perror(msg) printf("ERROR %d: %s\n", errno, msg)
#define fprintf(x, ...) printf( __VA_ARGS__ )
#include <machine/elf.h>
#include <sys/param.h>
#include "util.h"
#else
#include <elf.h>
#include <errno.h>
#include <fcntl.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <asm/bootparam.h>
#define PAGE_SIZE 4096
#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
(ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
(ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
(ehdr).e_ident[EI_MAG3] == ELFMAG3)
#define ELF_TARG_CLASS ELFCLASS64
#define ELF_TARG_MACH EM_X86_64
#define ELF_TARG_DATA ELFDATA2LSB
#endif
#define KCORE_PATH "/proc/kcore"
#define KALLSYMS_PATH "/proc/kallsyms"
struct elf_file
{
uint8_t buf[PAGE_SIZE];
int fd;
};
struct line_buffer
{
int fd;
char buf[PAGE_SIZE];
char *pos;
char *eos;
};
static bool
lb_fill(struct line_buffer *lb)
{
ssize_t rv;
lb->pos = lb->eos = lb->buf;
rv = read(lb->fd, lb->buf, sizeof(lb->buf));
if (rv <= 0)
return (false);
lb->pos = lb->buf;
lb->eos = lb->buf + rv;
return (true);
}
static bool
lb_fini(struct line_buffer *lb)
{
close(lb->fd);
return (true);
}
static bool
lb_init(struct line_buffer *lb, const char *fn)
{
lb->fd = open(fn, O_RDONLY);
if (lb->fd == -1)
return (false);
lb->pos = lb->eos = lb->buf;
if (!lb_fill(lb)) {
lb_fini(lb);
return (false);
}
return (true);
}
static bool
lb_1line(struct line_buffer *lb, char *buffer, size_t buflen)
{
char *bufeos = buffer + buflen - 1;
char *walker = buffer;
while (walker < bufeos) {
if (lb->pos >= lb->eos) {
if (!lb_fill(lb)) {
if (walker > buffer)
break;
return (false);
}
}
*walker = *lb->pos++;
if (*walker == '\n')
break;
walker++;
}
*++walker = '\0';
return (true);
}
unsigned long
symbol_addr(const char *symbol)
{
struct line_buffer lb;
unsigned long addr;
char line[256];
if (!lb_init(&lb, KALLSYMS_PATH))
return (0);
while (lb_1line(&lb, line, sizeof(line))) {
char *val, *name, *x, t;
val = line;
x = strchr(val, ' ');
if (x == NULL)
continue;
*x++ = '\0';
t = *x++;
if (strchr("dDbB", t) == NULL)
continue;
if (*x++ != ' ')
continue;
name = x;
x = strchr(x, '\n');
if (x == NULL)
continue;
*x++ = '\0';
if (strcmp(name, symbol) == 0) {
unsigned long v;
char *eop = NULL;
lb_fini(&lb);
v = strtoul(val, &eop, 16);
if (*eop == '\0')
return (v);
return (0);
}
}
lb_fini(&lb);
return (0);
}
bool
read_at_address(unsigned long addr, void *buf, size_t len)
{
struct elf_file ef;
Elf64_Ehdr *hdr;
Elf64_Phdr *phdr;
ssize_t rv;
bzero(&ef, sizeof(ef));
ef.fd = open(KCORE_PATH, O_RDONLY);
if (ef.fd == -1) {
perror("open " KCORE_PATH "\n");
return (false);
}
rv = read(ef.fd, ef.buf, sizeof(ef.buf));
if (rv != sizeof(ef.buf)) {
perror("short hdr read\n");
close(ef.fd);
return (false);
}
hdr = (Elf64_Ehdr *)&ef.buf;
if (!IS_ELF(*hdr)) {
fprintf(stderr, "Not Elf\n");
close(ef.fd);
return (false);
}
if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||
hdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
hdr->e_ident[EI_VERSION] != EV_CURRENT ||
hdr->e_version != EV_CURRENT ||
hdr->e_machine != ELF_TARG_MACH ||
hdr->e_type != ET_CORE) {
fprintf(stderr, "Not what I expect\n");
close(ef.fd);
return (false);
}
phdr = (Elf64_Phdr *)(ef.buf + hdr->e_phoff);
for (int i = 0; i < hdr->e_phnum; i++) {
if (phdr[i].p_type != PT_LOAD)
continue;
if (addr < phdr[i].p_vaddr ||
addr >= phdr[i].p_vaddr + phdr[i].p_filesz)
continue;
lseek(ef.fd, (off_t)phdr[i].p_offset + addr - phdr[i].p_vaddr,
SEEK_SET);
rv = read(ef.fd, buf, len);
if (rv != len)
perror("Can't read buffer\n");
close(ef.fd);
return (rv == len);
}
close(ef.fd);
return (false);
}
bool
data_from_kernel(const char *sym, void *buf, size_t len)
{
unsigned long addr;
addr = symbol_addr(sym);
if (addr == 0) {
fprintf(stderr, "Can't find symbol %s", sym);
return (false);
}
if (!read_at_address(addr, buf, len)) {
fprintf(stderr, "Can't read from kernel");
return (false);
}
return (true);
}
#ifndef _STANDALONE
int
main(int argc, char **argv)
{
struct boot_params bp;
if (data_from_kernel("boot_params", &bp, sizeof(bp))) {
fprintf(stderr, "Something went wrong\n");
} else {
printf("sig %#x systab %#lx memmap %#lx mmapsize %d md_size %d md_vers %d\n",
bp.efi_info.efi_loader_signature,
(long)(bp.efi_info.efi_systab | ((long)bp.efi_info.efi_systab_hi << 32)),
(long)(bp.efi_info.efi_memmap | ((long)bp.efi_info.efi_memmap_hi << 32)),
bp.efi_info.efi_memmap_size, bp.efi_info.efi_memdesc_size,
bp.efi_info.efi_memdesc_version);
}
}
#endif