PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
symbol.c
Go to the documentation of this file.
2
3#include <kernel/log/log.h>
4#include <kernel/log/panic.h>
6
7#include <errno.h>
8#include <stdint.h>
9#include <stdlib.h>
10#include <string.h>
11#include <sys/list.h>
12#include <sys/proc.h>
13
15static size_t addrAmount = 0;
16static size_t addrCapacity = 0;
17
19
21
23
29
30// Needed since there could be multiple symbols with the same address, each of these symbols are stored contiguously.
32{
33 if (addrArray == NULL || addrAmount == 0)
34 {
35 return addrAmount;
36 }
37
38 uint64_t left = 0;
39 uint64_t right = addrAmount - 1;
40 uint64_t result = addrAmount;
41
42 while (left <= right)
43 {
44 uint64_t mid = left + ((right - left) / 2);
45 if (addrArray[mid]->addr <= addr)
46 {
47 result = mid;
48 left = mid + 1;
49 }
50 else
51 {
52 right = mid - 1;
53 }
54 }
55
56 return result;
57}
58
60 Elf64_Symbol_Type type, symbol_name_t* symbolName)
61{
62 uint64_t left = 0;
63 uint64_t right = addrAmount;
64
65 while (left < right)
66 {
67 uint64_t mid = left + ((right - left) / 2);
68 if (addrArray[mid]->addr >= addr)
69 {
70 right = mid;
71 }
72 else
73 {
74 left = mid + 1;
75 }
76 }
77
78 if (addrAmount + 1 > addrCapacity)
79 {
80 uint64_t newCapacity = addrCapacity == 0 ? 16 : addrCapacity * 2;
81 symbol_addr_t** newArray = (symbol_addr_t**)realloc((void*)addrArray, sizeof(symbol_addr_t*) * newCapacity);
82 if (newArray == NULL)
83 {
84 return NULL;
85 }
86 addrArray = newArray;
87 addrCapacity = newCapacity;
88 }
89
90 symbol_addr_t* addrEntry = malloc(sizeof(symbol_addr_t));
91 if (addrEntry == NULL)
92 {
93 return NULL;
94 }
95 list_entry_init(&addrEntry->nameEntry);
96 addrEntry->name = symbolName;
97 addrEntry->addr = addr;
98 addrEntry->groupId = groupId;
99 addrEntry->binding = binding;
100 addrEntry->type = type;
101
102 uint64_t moveSize = sizeof(symbol_addr_t*) * (addrAmount - left);
103 memmove_s((void*)&addrArray[left + 1], moveSize, (void*)&addrArray[left], moveSize);
104 addrArray[left] = addrEntry;
105 addrAmount++;
106
107 list_push_back(&symbolName->addrs, &addrEntry->nameEntry);
108 return addrEntry;
109}
110
112{
113 if (outSymbol == NULL || addr == NULL)
114 {
115 errno = EINVAL;
116 return ERR;
117 }
118
119 size_t index = symbol_get_floor_index_for_addr(addr);
120 if (index == addrAmount)
121 {
122 errno = ENOENT;
123 return ERR;
124 }
125
126 symbol_addr_t* addrEntry = addrArray[index];
127 symbol_name_t* nameEntry = addrEntry->name;
128
129 strncpy_s(outSymbol->name, SYMBOL_MAX_NAME, nameEntry->name, SYMBOL_MAX_NAME - 1);
130 outSymbol->name[SYMBOL_MAX_NAME - 1] = '\0';
131 outSymbol->addr = addrEntry->addr;
132 outSymbol->groupId = addrEntry->groupId;
133 outSymbol->binding = addrEntry->binding;
134 outSymbol->type = addrEntry->type;
135
136 return 0;
137}
138
139static uint64_t symbol_resolve_name_unlocked(symbol_info_t* outSymbol, const char* name)
140{
141 if (outSymbol == NULL || name == NULL)
142 {
143 errno = EINVAL;
144 return ERR;
145 }
146
147 map_key_t key = map_key_string(name);
148 symbol_name_t* nameEntry = CONTAINER_OF_SAFE(map_get(&nameMap, &key), symbol_name_t, mapEntry);
149 if (nameEntry == NULL || list_is_empty(&nameEntry->addrs))
150 {
151 errno = ENOENT;
152 return ERR;
153 }
154 symbol_addr_t* addrEntry = CONTAINER_OF(list_first(&nameEntry->addrs), symbol_addr_t, nameEntry);
155
156 strncpy_s(outSymbol->name, SYMBOL_MAX_NAME, nameEntry->name, SYMBOL_MAX_NAME - 1);
157 outSymbol->name[SYMBOL_MAX_NAME - 1] = '\0';
158 outSymbol->addr = addrEntry->addr;
159 outSymbol->groupId = addrEntry->groupId;
160 outSymbol->binding = addrEntry->binding;
161 outSymbol->type = addrEntry->type;
162
163 return 0;
164}
165
166uint64_t symbol_add(const char* name, void* addr, symbol_group_id_t groupId, Elf64_Symbol_Binding binding,
168{
169 if (type != STT_OBJECT && type != STT_FUNC)
170 {
171 return 0;
172 }
173
174 if (name == NULL || addr == NULL)
175 {
176 errno = EINVAL;
177 return ERR;
178 }
179
181
182 if (binding == STB_GLOBAL)
183 {
184 symbol_info_t existingSymbol;
185 if (symbol_resolve_name_unlocked(&existingSymbol, name) != ERR)
186 {
187 LOG_DEBUG("global symbol name conflict for '%s'\n", name);
188 errno = EEXIST;
189 return ERR;
190 }
191 }
192
193 symbol_group_t* symbolGroup = NULL;
194 symbol_name_t* symbolName = NULL;
195 symbol_addr_t* symbolAddr = NULL;
196 bool groupWasCreated = false;
197 bool nameWasCreated = false;
198
199 map_key_t groupKey = map_key_uint64(groupId);
200 symbolGroup = CONTAINER_OF_SAFE(map_get(&groupMap, &groupKey), symbol_group_t, mapEntry);
201 if (symbolGroup == NULL)
202 {
203 symbolGroup = malloc(sizeof(symbol_group_t));
204 if (symbolGroup == NULL)
205 {
206 goto error;
207 }
208 map_entry_init(&symbolGroup->mapEntry);
209 list_init(&symbolGroup->names);
210 symbolGroup->id = groupId;
211
212 if (map_insert(&groupMap, &groupKey, &symbolGroup->mapEntry) == ERR)
213 {
214 free(symbolGroup);
215 symbolGroup = NULL;
216 goto error;
217 }
218 groupWasCreated = true;
219 }
220
221 map_key_t nameKey = map_key_string(name);
222 symbolName = CONTAINER_OF_SAFE(map_get(&nameMap, &nameKey), symbol_name_t, mapEntry);
223 if (symbolName == NULL)
224 {
225 symbolName = malloc(sizeof(symbol_name_t));
226 if (symbolName == NULL)
227 {
228 goto error;
229 }
230 list_entry_init(&symbolName->groupEntry);
231 map_entry_init(&symbolName->mapEntry);
232 list_init(&symbolName->addrs);
233 strncpy_s(symbolName->name, SYMBOL_MAX_NAME, name, SYMBOL_MAX_NAME - 1);
234 symbolName->name[SYMBOL_MAX_NAME - 1] = '\0';
235
236 if (map_insert(&nameMap, &nameKey, &symbolName->mapEntry) == ERR)
237 {
238 free(symbolName);
239 symbolName = NULL;
240 goto error;
241 }
242 list_push_back(&symbolGroup->names, &symbolName->groupEntry);
243 nameWasCreated = true;
244 }
245
246 symbolAddr = symbol_insert_address(addr, groupId, binding, type, symbolName);
247 if (symbolAddr == NULL)
248 {
249 goto error;
250 }
251
252 return 0;
253
254error:
255 if (symbolAddr == NULL)
256 {
257 if (symbolName != NULL && nameWasCreated)
258 {
259 map_key_t key = map_key_string(symbolName->name);
260 map_remove(&nameMap, &symbolName->mapEntry);
261 list_remove(&symbolName->groupEntry);
262 free(symbolName);
263 }
264 }
265
266 if (symbolName == NULL)
267 {
268 if (symbolGroup != NULL && groupWasCreated)
269 {
270 map_remove(&groupMap, &symbolGroup->mapEntry);
271 free(symbolGroup);
272 }
273 }
274
275 LOG_DEBUG("failed to add symbol '%s' at address %p (%s)\n", name, addr, strerror(errno));
276 return ERR;
277}
278
280{
282
283 map_key_t groupKey = map_key_uint64(groupId);
284 symbol_group_t* groupEntry = CONTAINER_OF_SAFE(map_get(&groupMap, &groupKey), symbol_group_t, mapEntry);
285 if (groupEntry == NULL)
286 {
287 return;
288 }
289
290 while (!list_is_empty(&groupEntry->names))
291 {
292 symbol_name_t* nameEntry = CONTAINER_OF(list_pop_front(&groupEntry->names), symbol_name_t, groupEntry);
293 list_entry_init(&nameEntry->groupEntry);
294 }
295
296 size_t writeIdx = 0;
297 for (size_t readIdx = 0; readIdx < addrAmount; readIdx++)
298 {
299 symbol_addr_t* addrEntry = addrArray[readIdx];
300 if (addrEntry->groupId == groupId)
301 {
302 symbol_name_t* nameEntry = addrEntry->name;
303
304 list_remove(&addrEntry->nameEntry);
305 free(addrEntry);
306
307 if (list_is_empty(&nameEntry->addrs))
308 {
309 map_remove(&nameMap, &nameEntry->mapEntry);
310 list_remove(&nameEntry->groupEntry);
311 free(nameEntry);
312 }
313 }
314 else
315 {
316 if (writeIdx != readIdx)
317 {
318 addrArray[writeIdx] = addrArray[readIdx];
319 }
320 writeIdx++;
321 }
322 }
323 addrAmount = writeIdx;
324
325 map_remove(&groupMap, &groupEntry->mapEntry);
326 free(groupEntry);
327
328 if (addrAmount == 0)
329 {
330 free((void*)addrArray);
331 addrArray = NULL;
332 addrCapacity = 0;
333 }
334 else if (addrArray != NULL && addrAmount < addrCapacity / 4)
335 {
336 uint64_t newCapacity = addrCapacity / 2;
337 symbol_addr_t** newArray = (symbol_addr_t**)realloc((void*)addrArray, sizeof(symbol_addr_t*) * newCapacity);
338 if (newArray != NULL)
339 {
340 addrArray = newArray;
341 addrCapacity = newCapacity;
342 }
343 }
344}
345
347{
349 return symbol_resolve_addr_unlocked(outSymbol, addr);
350}
351
352uint64_t symbol_resolve_name(symbol_info_t* outSymbol, const char* name)
353{
355 return symbol_resolve_name_unlocked(outSymbol, name);
356}
#define LOG_DEBUG(format,...)
Definition log.h:85
uint64_t symbol_resolve_name(symbol_info_t *outSymbol, const char *name)
Resolve a symbol by name.
Definition symbol.c:352
uint64_t symbol_group_id_t
Symbol group identifier type.
Definition symbol.h:67
uint64_t symbol_resolve_addr(symbol_info_t *outSymbol, void *addr)
Resolve a symbol by address.
Definition symbol.c:346
uint64_t symbol_add(const char *name, void *addr, symbol_group_id_t groupId, Elf64_Symbol_Binding binding, Elf64_Symbol_Type type)
Add a symbol to the kernel symbol table.
Definition symbol.c:166
#define SYMBOL_MAX_NAME
Maximum length of a symbol name.
Definition symbol.h:57
void symbol_remove_group(symbol_group_id_t groupId)
Remove all symbols from the kernel symbol table in the given group.
Definition symbol.c:279
symbol_group_id_t symbol_generate_group_id(void)
Generate a unique symbol group identifier.
Definition symbol.c:24
#define RWLOCK_READ_SCOPE(lock)
Acquires a rwlock for reading for the reminder of the current scope.
Definition rwlock.h:34
#define RWLOCK_CREATE()
Create a rwlock initializer.
Definition rwlock.h:52
#define RWLOCK_WRITE_SCOPE(lock)
Acquires a rwlock for writing for the reminder of the current scope.
Definition rwlock.h:43
void map_entry_init(map_entry_t *entry)
Initialize a map entry.
Definition map.c:37
static map_key_t map_key_uint64(uint64_t uint64)
Create a map key from a uint64_t.
Definition map.h:129
uint64_t map_insert(map_t *map, const map_key_t *key, map_entry_t *value)
Insert a key-value pair into the map.
Definition map.c:170
void map_remove(map_t *map, map_entry_t *entry)
Remove a entry from the map.
Definition map.c:319
map_entry_t * map_get(map_t *map, const map_key_t *key)
Get a value from the map by key.
Definition map.c:253
static map_key_t map_key_string(const char *str)
Create a map key from a string.
Definition map.h:144
#define MAP_CREATE()
Create a map initializer.
Definition map.h:161
#define ENOENT
No such file or directory.
Definition errno.h:42
#define EEXIST
File exists.
Definition errno.h:117
#define EINVAL
Invalid argument.
Definition errno.h:142
#define errno
Error number variable.
Definition errno.h:27
Elf64_Symbol_Binding
Symbol binding values stored in st_info.
Definition elf.h:565
Elf64_Symbol_Type
Symbol type values stored in st_info.
Definition elf.h:588
@ STB_GLOBAL
Global symbol, visible to all object files being combined.
Definition elf.h:567
@ STT_FUNC
Symbol is a code object.
Definition elf.h:591
@ STT_OBJECT
Symbol is a data object.
Definition elf.h:590
static void list_remove(list_entry_t *entry)
Removes a list entry from its current list.
Definition list.h:290
static list_entry_t * list_first(list_t *list)
Gets the first entry in the list without removing it.
Definition list.h:406
static void list_push_back(list_t *list, list_entry_t *entry)
Pushes an entry to the end of the list.
Definition list.h:322
static bool list_is_empty(list_t *list)
Checks if a list is empty.
Definition list.h:210
static void list_entry_init(list_entry_t *entry)
Initializes a list entry.
Definition list.h:173
static list_entry_t * list_pop_front(list_t *list)
Pops the first entry from the list.
Definition list.h:366
static void list_init(list_t *list)
Initializes a list.
Definition list.h:185
#define NULL
Pointer error value.
Definition NULL.h:25
#define ERR
Integer error value.
Definition ERR.h:17
#define CONTAINER_OF(ptr, type, member)
Container of macro.
#define CONTAINER_OF_SAFE(ptr, type, member)
Safe container of macro.
errno_t memmove_s(void *s1, rsize_t s1max, const void *s2, rsize_t n)
Definition memmove_s.c:9
@ memory_order_relaxed
Definition stdatomic.h:116
#define atomic_fetch_add_explicit(object, operand, order)
Definition stdatomic.h:259
#define _Atomic(T)
Definition stdatomic.h:59
#define ATOMIC_VAR_INIT(value)
Definition stdatomic.h:74
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
_PUBLIC void * realloc(void *ptr, size_t size)
Definition realloc.c:13
_PUBLIC void * malloc(size_t size)
Definition malloc.c:5
_PUBLIC void free(void *ptr)
Definition free.c:11
_PUBLIC char * strerror(int errnum)
Definition strerror.c:6
errno_t strncpy_s(char *_RESTRICT s1, rsize_t s1max, const char *_RESTRICT s2, rsize_t n)
Definition strncpy_s.c:9
Map key stucture.
Definition map.h:57
Hash map structure.
Definition map.h:90
Read-Write Ticket Lock structure.
Definition rwlock.h:66
Symbol address mapping structure.
Definition symbol.h:104
symbol_name_t * name
Definition symbol.h:106
symbol_group_id_t groupId
Definition symbol.h:108
Elf64_Symbol_Binding binding
Definition symbol.h:109
void * addr
Definition symbol.h:107
Elf64_Symbol_Type type
Definition symbol.h:110
list_entry_t nameEntry
Definition symbol.h:105
list_t names
Definition symbol.h:79
map_entry_t mapEntry
Definition symbol.h:77
symbol_group_id_t id
Definition symbol.h:78
Symbol information structure.
Definition symbol.h:120
void * addr
Definition symbol.h:122
symbol_group_id_t groupId
Definition symbol.h:123
Elf64_Symbol_Binding binding
Definition symbol.h:124
char name[SYMBOL_MAX_NAME]
Definition symbol.h:121
Elf64_Symbol_Type type
Definition symbol.h:125
Symbol name mapping structure.
Definition symbol.h:89
list_entry_t groupEntry
Definition symbol.h:90
list_t addrs
Definition symbol.h:92
map_entry_t mapEntry
Definition symbol.h:91
char name[SYMBOL_MAX_NAME]
Definition symbol.h:93
static symbol_addr_t * symbol_insert_address(void *addr, symbol_group_id_t groupId, Elf64_Symbol_Binding binding, Elf64_Symbol_Type type, symbol_name_t *symbolName)
Definition symbol.c:59
static rwlock_t lock
Definition symbol.c:22
static symbol_addr_t ** addrArray
Definition symbol.c:14
static map_t groupMap
Definition symbol.c:20
static uint64_t symbol_get_floor_index_for_addr(void *addr)
Definition symbol.c:31
static size_t addrCapacity
Definition symbol.c:16
static map_t nameMap
Definition symbol.c:18
static size_t addrAmount
Definition symbol.c:15
static uint64_t symbol_resolve_addr_unlocked(symbol_info_t *outSymbol, void *addr)
Definition symbol.c:111
static uint64_t symbol_resolve_name_unlocked(symbol_info_t *outSymbol, const char *name)
Definition symbol.c:139