summaryrefslogtreecommitdiff
path: root/kernel/mboot/elf.c
blob: 88b61a71d94328c51cf75601971a45f9c929b0ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include "lib/kio.h"
#include <lib.h>
#include <elf.h>
#include <comus/mboot.h>

#include "mboot.h"

#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9

struct multiboot_tag_elf_sections {
	uint32_t type;
	uint32_t size;
	uint32_t num;
	uint32_t entsize;
	uint32_t shndx;
	Elf64_Shdr sections[];
};

static struct multiboot_tag_elf_sections *elf = NULL;
static Elf64_Shdr *symtab = NULL;
static Elf64_Shdr *symstrtab = NULL;

static Elf64_Shdr *mboot_get_elf_sec(uint32_t sh_type)
{
	for (uint32_t i = 0; i < elf->num; i++) {
		Elf64_Shdr *ent = &elf->sections[i];
		if (ent->sh_type == sh_type)
			return ent;
	}

	return NULL;
}

static int mboot_load_elf(void)
{
	void *tag = locate_mboot_table(MULTIBOOT_TAG_TYPE_ELF_SECTIONS);
	if (tag == NULL)
		return 1;

	// found elf sections
	elf = (struct multiboot_tag_elf_sections *)tag;

	// load symtab
	if ((symtab = mboot_get_elf_sec(SHT_SYMTAB)) == NULL)
		return 1;

	// load strsymtab
	if ((symstrtab = mboot_get_elf_sec(symtab->sh_link)) == NULL)
		return 1;

	return 0;
}

const char *mboot_get_elf_sym(uint64_t addr)
{
	if (symstrtab == NULL)
		if (mboot_load_elf())
			return NULL;

	// walk symbol table
	Elf64_Sym *syms = (Elf64_Sym *)symtab->sh_addr;
	Elf64_Sym *best = NULL;
	for (uint32_t i = 0; i < symtab->sh_size / symtab->sh_entsize; i++) {
		Elf64_Sym *sym = &syms[i];
		if (sym->st_value < addr)
			continue;
		if (best == NULL || (best->st_value < sym->st_value))
			best = sym;
	}

	if (best != NULL) {
		char *buf = (char *)symstrtab->sh_addr;
		return &buf[best->st_name];
	}

	return "???";
}