summaryrefslogtreecommitdiff
path: root/mld/symtab.c
blob: 314a1c3ee81b1cb38b06df9d94a4f2a597fa24b1 (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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include <elf.h>
#include <merror.h>
#include <stdio.h>
#include <stdlib.h>
#include <melf.h>

#include "link.h"

#define SYMTAB_INIT_LEN 8

int symtab_init(struct symbol_table *symtab)
{
	symtab->len = 1;
	symtab->size = SYMTAB_INIT_LEN;
	symtab->syms = malloc(sizeof(Elf32_Sym) * SYMTAB_INIT_LEN);

	if (symtab->syms == NULL) {
		PERROR("cannot alloc");
		return M_ERROR;
	}

	symtab->syms[0] = (Elf32_Sym){0};
	symtab->map = NULL;

	return M_SUCCESS;
}

void symtab_free(struct symbol_table *symtab)
{
	free(symtab->syms);
}

int symtab_push(struct symbol_table *symtab, const Elf32_Sym *sym)
{
	if (symtab->len >= symtab->size) {
		size_t size = symtab->size *= 2;
		void *new = realloc(symtab->syms, sizeof(Elf32_Sym) * size);
		if (new == NULL) {
			PERROR("cannot realloc");
			return M_ERROR;
		}
		symtab->size = size;
		symtab->syms = new;
	}

	symtab->syms[symtab->len++] = *sym;
	return M_SUCCESS;
}

int symtab_get(struct symbol_table *symtab, Elf32_Sym **res, const char *name,
	       int32_t obj_idx)
{
	for (size_t i = 1; i < symtab->len; i++) {
		Elf32_Sym *sym = &symtab->syms[i];
		const char *symname = symtab->strtab->data + B32(sym->st_name);
		if (strcmp(name, symname) != 0)
			continue;

		// ignore absolute symbols
		if (B16(sym->st_shndx) == SHN_ABS)
			continue;

		// only allow retrevial of local variables from the
		// same object
		if (sym->st_info >> 4 != STB_GLOBAL && symtab->map != NULL &&
			obj_idx >= 0) {
			// we need to change the index by one since
			// symbol tables always start will a NULl symbol
			struct object *obj = symtab->map->meta[i - 1];
			if (obj->index != (uint32_t)obj_idx)
				continue;
		} else if (obj_idx < 0 && sym->st_info >> 4 != STB_GLOBAL) {
			// when obj_idx is -1, we only want to reutrn
			// global symbols
			continue;
		}

		if (res != NULL)
			*res = sym;
		return M_SUCCESS;
	}
	return M_ERROR;
}

int symtab_map_push(struct symbol_table_mapping *symtabm, struct object *meta)
{
	if (symtabm->len >= symtabm->size) {
		uint32_t size = symtabm->size * 2;
		void *new = realloc(symtabm->meta,
		      sizeof(struct object *) * size);
		if (new == NULL) {
			PERROR("cannot realloc");
			return M_ERROR;
		}
		symtabm->size = size;
		symtabm->meta = new;
	}

	symtabm->meta[symtabm->len++] = meta;
	return M_SUCCESS;
}

int symtab_map_init(struct symbol_table_mapping *symtabm)
{
	symtabm->len = 0;
	symtabm->size = SYMTAB_INIT_LEN;
	symtabm->meta = malloc(sizeof(struct object *) * symtabm->size);

	if (symtabm->meta == NULL) {
		PERROR("cannot alloc");
		return M_ERROR;
	}

	return M_SUCCESS;
}


void symtab_map_free(struct symbol_table_mapping *symtabm)
{
	free(symtabm->meta);
}