PatchworkOS  28a9544
A non-POSIX operating system.
Loading...
Searching...
No Matches
Kernel Symbols

Kernel Symbol Resolution and Management. More...

Data Structures

struct  symbol_group_t
 
struct  symbol_name_t
 Symbol name mapping structure. More...
 
struct  symbol_addr_t
 Symbol address mapping structure. More...
 
struct  symbol_info_t
 Symbol information structure. More...
 

Macros

#define SYMBOL_MAX_NAME   MAP_KEY_MAX_LENGTH
 Maximum length of a symbol name.
 

Typedefs

typedef uint64_t symbol_group_id_t
 Symbol group identifier type.
 

Functions

symbol_group_id_t symbol_generate_group_id (void)
 Generate a unique symbol group identifier.
 
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.
 
void symbol_remove_group (symbol_group_id_t groupId)
 Remove all symbols from the kernel symbol table in the given group.
 
uint64_t symbol_resolve_addr (symbol_info_t *outSymbol, void *addr)
 Resolve a symbol by address.
 
uint64_t symbol_resolve_name (symbol_info_t *outSymbol, const char *name)
 Resolve a symbol by name.
 

Detailed Description

Kernel Symbol Resolution and Management.

What are Symbols?

All binary files are made up of "symbols", a name associated with an address in the binary, which includes the kernel. These symbols are usually stored in the binary file of whatever binary we are dealing with, usually the only purpose of these symbols is linking and debugging.

Runtime Symbol Resolution

We can take advantage of these symbols to resolve symbol names to addresses ("kmain" -> 0xXXXXXXXX) and addresses to symbol names (0xXXXXXXXX -> "kmain") at runtime. This is not only massively useful for debugging and logging, but vital for implementing kernel modules, as the kernel effectively acts as a "runtime linker" for the kernel module binaries, resolving any kernel symbols (which are stored in the module binary by its name since it cant know the address beforehand) to their actual addresses in the kernel so that the module can call into the kernel and of course vice versa. We can also use this to resolve symbols between modules.

In the end we have a large structure of all currently loaded symbols in the kernel or modules, and we can search this structure by name or by address.

The Structure

The kernel stores symbols using three main structures, which when combined form a slightly over optimized way to retrieve symbols by name or address and to easily remove symbols when a module is unloaded.

The structures are:

These structures form a kind of circular graph, where from a group we can retrieve the names, from the names we can retrieve the addresses and from the addresses we can retrieve the group again. Its also possible to go from a address to its name using the CONTAINER_OF macro.

Note that we cant use a map for the addresses as we need to be able to find non-exact matches when resolving an address. If a address inside a function is provided we still want to be able to resolve it to the function name, this is done by finding the closest symbol with an address less than or equal to the provided address.

Macro Definition Documentation

◆ SYMBOL_MAX_NAME

#define SYMBOL_MAX_NAME   MAP_KEY_MAX_LENGTH

Maximum length of a symbol name.

Definition at line 57 of file symbol.h.

Typedef Documentation

◆ symbol_group_id_t

Symbol group identifier type.

Used to easily group symbols for removal later, mostly used by modules to remove all their symbols when unloaded.

A value of 0 indicates that its part of the kernel and not a module.

Definition at line 67 of file symbol.h.

Function Documentation

◆ symbol_add()

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.

Symbols of binding STB_GLOBAL must have unique names but can have duplicated addresses, symbols of other bindings can be duplicated in name, address or both.

If the symbol is not of type STT_OBJECT or STT_FUNC the function is a no-op and returns success.

Parameters
nameThe name of the symbol.
addrThe address of the symbol.
groupIdThe group identifier of the symbol.
bindingThe binding of the symbol, specifies visibility and linkage.
typeThe type of the symbol, specifies what the symbol represents.
Returns
On success, 0. On failure, ERR and errno is set.

Definition at line 165 of file symbol.c.

References symbol_name_t::addrs, CONTAINER_OF_SAFE, EEXIST, EINVAL, ERR, errno, free(), symbol_name_t::groupEntry, groupMap, symbol_group_t::id, list_entry_init(), list_init(), list_push_back(), list_remove(), lock, LOG_DEBUG, malloc(), map_entry_init(), map_get(), map_insert(), map_key_string(), map_key_uint64(), map_remove(), symbol_group_t::mapEntry, symbol_name_t::mapEntry, symbol_name_t::name, nameMap, symbol_group_t::names, NULL, RWLOCK_WRITE_SCOPE, STB_GLOBAL, strerror(), strncpy_s(), STT_FUNC, STT_OBJECT, symbol_insert_address(), SYMBOL_MAX_NAME, and symbol_resolve_name_unlocked().

Referenced by module_init_fake_kernel_module(), and module_load_and_relocate_elf().

◆ symbol_generate_group_id()

symbol_group_id_t symbol_generate_group_id ( void  )

Generate a unique symbol group identifier.

All identifiers are generated sequentially.

Returns
The symbol group identifier.

Definition at line 24 of file symbol.c.

References _Atomic, atomic_fetch_add_explicit, ATOMIC_VAR_INIT, and memory_order_relaxed.

◆ symbol_remove_group()

void symbol_remove_group ( symbol_group_id_t  groupId)

Remove all symbols from the kernel symbol table in the given group.

Parameters
groupIdThe group identifier of the symbols to remove.

Definition at line 278 of file symbol.c.

References addrAmount, addrArray, addrCapacity, symbol_name_t::addrs, CONTAINER_OF, CONTAINER_OF_SAFE, free(), groupMap, list_is_empty(), list_pop_first(), lock, map_get(), map_key_uint64(), map_remove(), symbol_group_t::mapEntry, symbol_name_t::mapEntry, nameMap, symbol_group_t::names, NULL, realloc(), and RWLOCK_WRITE_SCOPE.

Referenced by module_free().

◆ symbol_resolve_addr()

uint64_t symbol_resolve_addr ( symbol_info_t outSymbol,
void *  addr 
)

Resolve a symbol by address.

The resolved symbol is the closest symbol with an address less than or equal to the given address. The outSymbol->addr will be the address of the symbol, not the given address.

If multiple symbols exist at the same address, one of them will be returned, but which one is undefined. Dont rely on this behaviour being predictable.

Parameters
outSymbolOutput pointer to store the resolved symbol information.
addrThe address of the symbol to resolve.
Returns
On success, 0. On failure, ERR and errno is set.

Definition at line 338 of file symbol.c.

References lock, RWLOCK_READ_SCOPE, and symbol_resolve_addr_unlocked().

Referenced by panic_print_trace_address(), and panic_registers().

◆ symbol_resolve_name()

uint64_t symbol_resolve_name ( symbol_info_t outSymbol,
const char *  name 
)

Resolve a symbol by name.

Parameters
outSymbolOutput pointer to store the resolved symbol information.
nameThe name of the symbol to resolve.
Returns
On success, 0. On failure, ERR and errno is set.

Definition at line 344 of file symbol.c.

References lock, RWLOCK_READ_SCOPE, and symbol_resolve_name_unlocked().

Referenced by module_resolve_callback().