PatchworkOS  28a9544
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
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->addr = addr;
97 addrEntry->groupId = groupId;
98 addrEntry->binding = binding;
99 addrEntry->type = type;
100
101 uint64_t moveSize = sizeof(symbol_addr_t*) * (addrAmount - left);
102 memmove_s((void*)&addrArray[left + 1], moveSize, (void*)&addrArray[left], moveSize);
103 addrArray[left] = addrEntry;
104 addrAmount++;
105
106 list_push_back(&symbolName->addrs, &addrEntry->nameEntry);
107 return addrEntry;
108}
109
111{
112 if (outSymbol == NULL || addr == NULL)
113 {
114 errno = EINVAL;
115 return ERR;
116 }
117
119 if (index == addrAmount)
120 {
121 errno = ENOENT;
122 return ERR;
123 }
124
125 symbol_addr_t* addrEntry = addrArray[index];
126 symbol_name_t* nameEntry = CONTAINER_OF(addrEntry->nameEntry.list, symbol_name_t, addrs);
127
128 strncpy_s(outSymbol->name, SYMBOL_MAX_NAME, nameEntry->name, SYMBOL_MAX_NAME - 1);
129 outSymbol->name[SYMBOL_MAX_NAME - 1] = '\0';
130 outSymbol->addr = addrEntry->addr;
131 outSymbol->groupId = addrEntry->groupId;
132 outSymbol->binding = addrEntry->binding;
133 outSymbol->type = addrEntry->type;
134
135 return 0;
136}
137
138static uint64_t symbol_resolve_name_unlocked(symbol_info_t* outSymbol, const char* name)
139{
140 if (outSymbol == NULL || name == NULL)
141 {
142 errno = EINVAL;
143 return ERR;
144 }
145
146 map_key_t key = map_key_string(name);
147 symbol_name_t* nameEntry = CONTAINER_OF_SAFE(map_get(&nameMap, &key), symbol_name_t, mapEntry);
148 if (nameEntry == NULL || list_is_empty(&nameEntry->addrs))
149 {
150 errno = ENOENT;
151 return ERR;
152 }
153 symbol_addr_t* addrEntry = CONTAINER_OF(list_first(&nameEntry->addrs), symbol_addr_t, nameEntry);
154
155 strncpy_s(outSymbol->name, SYMBOL_MAX_NAME, nameEntry->name, SYMBOL_MAX_NAME - 1);
156 outSymbol->name[SYMBOL_MAX_NAME - 1] = '\0';
157 outSymbol->addr = addrEntry->addr;
158 outSymbol->groupId = addrEntry->groupId;
159 outSymbol->binding = addrEntry->binding;
160 outSymbol->type = addrEntry->type;
161
162 return 0;
163}
164
165uint64_t symbol_add(const char* name, void* addr, symbol_group_id_t groupId, Elf64_Symbol_Binding binding,
167{
168 if (type != STT_OBJECT && type != STT_FUNC)
169 {
170 return 0;
171 }
172
173 if (name == NULL || addr == NULL)
174 {
175 errno = EINVAL;
176 return ERR;
177 }
178
180
181 if (binding == STB_GLOBAL)
182 {
183 symbol_info_t existingSymbol;
184 if (symbol_resolve_name_unlocked(&existingSymbol, name) != ERR)
185 {
186 LOG_DEBUG("global symbol name conflict for '%s'\n", name);
187 errno = EEXIST;
188 return ERR;
189 }
190 }
191
192 symbol_group_t* symbolGroup = NULL;
193 symbol_name_t* symbolName = NULL;
194 symbol_addr_t* symbolAddr = NULL;
195 bool groupWasCreated = false;
196 bool nameWasCreated = false;
197
198 map_key_t groupKey = map_key_uint64(groupId);
199 symbolGroup = CONTAINER_OF_SAFE(map_get(&groupMap, &groupKey), symbol_group_t, mapEntry);
200 if (symbolGroup == NULL)
201 {
202 symbolGroup = malloc(sizeof(symbol_group_t));
203 if (symbolGroup == NULL)
204 {
205 goto error;
206 }
207 map_entry_init(&symbolGroup->mapEntry);
208 list_init(&symbolGroup->names);
209 symbolGroup->id = groupId;
210
211 if (map_insert(&groupMap, &groupKey, &symbolGroup->mapEntry) == ERR)
212 {
213 free(symbolGroup);
214 symbolGroup = NULL;
215 goto error;
216 }
217 groupWasCreated = true;
218 }
219
220 map_key_t nameKey = map_key_string(name);
221 symbolName = CONTAINER_OF_SAFE(map_get(&nameMap, &nameKey), symbol_name_t, mapEntry);
222 if (symbolName == NULL)
223 {
224 symbolName = malloc(sizeof(symbol_name_t));
225 if (symbolName == NULL)
226 {
227 goto error;
228 }
229 list_entry_init(&symbolName->groupEntry);
230 map_entry_init(&symbolName->mapEntry);
231 list_init(&symbolName->addrs);
232 strncpy_s(symbolName->name, SYMBOL_MAX_NAME, name, SYMBOL_MAX_NAME - 1);
233 symbolName->name[SYMBOL_MAX_NAME - 1] = '\0';
234
235 if (map_insert(&nameMap, &nameKey, &symbolName->mapEntry) == ERR)
236 {
237 free(symbolName);
238 symbolName = NULL;
239 goto error;
240 }
241 list_push_back(&symbolGroup->names, &symbolName->groupEntry);
242 nameWasCreated = true;
243 }
244
245 symbolAddr = symbol_insert_address(addr, groupId, binding, type, symbolName);
246 if (symbolAddr == NULL)
247 {
248 goto error;
249 }
250
251 return 0;
252
253error:
254 if (symbolAddr == NULL)
255 {
256 if (symbolName != NULL && nameWasCreated)
257 {
258 map_key_t key = map_key_string(symbolName->name);
259 map_remove(&nameMap, &symbolName->mapEntry);
260 list_remove(&symbolGroup->names, &symbolName->groupEntry);
261 free(symbolName);
262 }
263 }
264
265 if (symbolName == NULL)
266 {
267 if (symbolGroup != NULL && groupWasCreated)
268 {
269 map_remove(&groupMap, &symbolGroup->mapEntry);
270 free(symbolGroup);
271 }
272 }
273
274 LOG_DEBUG("failed to add symbol '%s' at address %p (%s)\n", name, addr, strerror(errno));
275 return ERR;
276}
277
279{
281
282 map_key_t groupKey = map_key_uint64(groupId);
283 symbol_group_t* groupEntry = CONTAINER_OF_SAFE(map_get(&groupMap, &groupKey), symbol_group_t, mapEntry);
284 if (groupEntry == NULL)
285 {
286 return;
287 }
288
289 uint64_t writeIdx = 0;
290 for (uint64_t readIdx = 0; readIdx < addrAmount; readIdx++)
291 {
292 if (addrArray[readIdx]->groupId != groupId)
293 {
294 if (writeIdx != readIdx)
295 {
296 addrArray[writeIdx] = addrArray[readIdx];
297 }
298 writeIdx++;
299 }
300 }
301 addrAmount = writeIdx;
302
303 while (!list_is_empty(&groupEntry->names))
304 {
305 symbol_name_t* nameEntry = CONTAINER_OF(list_pop_first(&groupEntry->names), symbol_name_t, groupEntry);
306
307 while (!list_is_empty(&nameEntry->addrs))
308 {
309 symbol_addr_t* addrEntry = CONTAINER_OF(list_pop_first(&nameEntry->addrs), symbol_addr_t, nameEntry);
310 free(addrEntry);
311 }
312
313 map_remove(&nameMap, &nameEntry->mapEntry);
314 free(nameEntry);
315 }
316
317 map_remove(&groupMap, &groupEntry->mapEntry);
318 free(groupEntry);
319
320 if (addrAmount == 0)
321 {
322 free((void*)addrArray);
323 addrArray = NULL;
324 addrCapacity = 0;
325 }
326 else if (addrArray != NULL && addrAmount < addrCapacity / 4)
327 {
328 uint64_t newCapacity = addrCapacity / 2;
329 symbol_addr_t** newArray = (symbol_addr_t**)realloc((void*)addrArray, sizeof(symbol_addr_t*) * newCapacity);
330 if (newArray != NULL)
331 {
332 addrArray = newArray;
333 addrCapacity = newCapacity;
334 }
335 }
336}
337
339{
341 return symbol_resolve_addr_unlocked(outSymbol, addr);
342}
343
344uint64_t symbol_resolve_name(symbol_info_t* outSymbol, const char* name)
345{
347 return symbol_resolve_name_unlocked(outSymbol, name);
348}
#define LOG_DEBUG(format,...)
Definition log.h:83
uint64_t symbol_resolve_name(symbol_info_t *outSymbol, const char *name)
Resolve a symbol by name.
Definition symbol.c:344
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:338
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:165
#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:278
symbol_group_id_t symbol_generate_group_id(void)
Generate a unique symbol group identifier.
Definition symbol.c:24
#define RWLOCK_CREATE
Create a rwlock initializer.
Definition rwlock.h:47
#define RWLOCK_READ_SCOPE(lock)
Acquires a rwlock for reading for the reminder of the current scope.
Definition rwlock.h:29
#define RWLOCK_WRITE_SCOPE(lock)
Acquires a rwlock for writing for the reminder of the current scope.
Definition rwlock.h:38
void map_entry_init(map_entry_t *entry)
Initialize a map entry.
Definition map.c:71
static map_key_t map_key_uint64(uint64_t uint64)
Create a map key from a uint64_t.
Definition map.h:128
#define MAP_CREATE
Create a map initializer.
Definition map.h:160
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:193
void map_remove(map_t *map, map_entry_t *entry)
Remove a entry from the map.
Definition map.c:307
map_entry_t * map_get(map_t *map, const map_key_t *key)
Get a value from the map by key.
Definition map.c:241
static map_key_t map_key_string(const char *str)
Create a map key from a string.
Definition map.h:143
#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 list_entry_t * list_first(list_t *list)
Gets the first entry in the list without removing it.
Definition list.h:419
static list_entry_t * list_pop_first(list_t *list)
Pops the first entry from the list.
Definition list.h:377
static void list_push_back(list_t *list, list_entry_t *entry)
Pushes an entry to the end of the list.
Definition list.h:345
static void list_remove(list_t *list, list_entry_t *entry)
Removes a list entry from its current list.
Definition list.h:317
static bool list_is_empty(list_t *list)
Checks if a list is empty.
Definition list.h:229
static void list_entry_init(list_entry_t *entry)
Initializes a list entry.
Definition list.h:184
static void list_init(list_t *list)
Initializes a list.
Definition list.h:198
#define NULL
Pointer error value.
Definition NULL.h:23
#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
list_t * list
The list this entry belongs to.
Definition list.h:41
Map key stucture.
Definition map.h:56
Hash map structure.
Definition map.h:89
Read-Write Ticket Lock structure.
Definition rwlock.h:61
Symbol address mapping structure.
Definition symbol.h:104
symbol_group_id_t groupId
Definition symbol.h:107
Elf64_Symbol_Binding binding
Definition symbol.h:108
void * addr
Definition symbol.h:106
Elf64_Symbol_Type type
Definition symbol.h:109
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:119
void * addr
Definition symbol.h:121
symbol_group_id_t groupId
Definition symbol.h:122
Elf64_Symbol_Binding binding
Definition symbol.h:123
char name[SYMBOL_MAX_NAME]
Definition symbol.h:120
Elf64_Symbol_Type type
Definition symbol.h:124
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 map_t nameMap
Definition symbol.c:18
static uint64_t addrCapacity
Definition symbol.c:16
static uint64_t addrAmount
Definition symbol.c:15
static uint64_t symbol_resolve_addr_unlocked(symbol_info_t *outSymbol, void *addr)
Definition symbol.c:110
static uint64_t symbol_resolve_name_unlocked(symbol_info_t *outSymbol, const char *name)
Definition symbol.c:138