* Copyright 2025, Trung Nguyen, trungnt282910@gmail.com.
* Distributed under the terms of the MIT License.
*/
#include "commpage.h"
#include <string.h>
#include <syscalls.h>
#include "runtime_loader_private.h"
static const char* const kCommpageName = "commpage";
static image_id sCommpageImageID = -1;
static int32 sCommpageSymbolCount = -1;
static void* sCommpageSymbolsBuffer = NULL;
static elf_sym* sCommpageSymbols = NULL;
static char* sCommpageStringTable = NULL;
status_t
commpage_reinit_after_fork()
{
sCommpageImageID = -1;
return B_OK;
}
static status_t
get_commpage_image_id(team_id team)
{
image_info info;
int32 cookie = 0;
while (_kern_get_next_image_info(team, &cookie, &info, sizeof(info)) == B_OK) {
if (strcmp(info.name, kCommpageName) == 0)
return info.id;
}
return B_ENTRY_NOT_FOUND;
}
status_t
get_nearest_commpage_symbol_at_address_locked(void* address, image_id* _imageID, char** _imagePath,
char** _imageName, char** _symbolName, int32* _type, void** _location, bool* _exactMatch)
{
status_t status;
bool wantsImage = _imageID != NULL;
bool wantsSymbol = _symbolName != NULL || _type != NULL || _location != NULL;
if (wantsImage && sCommpageImageID == -1) {
if (sCommpageImageID == -1) {
status = get_commpage_image_id(B_CURRENT_TEAM);
if (status < B_OK)
return status;
sCommpageImageID = status;
}
}
if (wantsSymbol && sCommpageSymbolCount == -1) {
image_id systemCommpageID = get_commpage_image_id(B_SYSTEM_TEAM);
if (systemCommpageID < B_OK)
return systemCommpageID;
int32 symbolCount = 0;
size_t stringTableSize = 0;
status = _kern_read_kernel_image_symbols(systemCommpageID, NULL,
&symbolCount, NULL, &stringTableSize, NULL);
if (status < B_OK)
return status;
size_t memorySize = symbolCount * sizeof(elf_sym) + stringTableSize + 1;
void* buffer = malloc(memorySize);
if (buffer == NULL)
return B_NO_MEMORY;
elf_sym* symbols = (elf_sym*)buffer;
char* stringTable = (char*)buffer + symbolCount * sizeof(elf_sym);
status = _kern_read_kernel_image_symbols(systemCommpageID, symbols, &symbolCount,
stringTable, &stringTableSize, NULL);
if (status < B_OK) {
free(buffer);
return status;
}
sCommpageSymbolCount = symbolCount;
sCommpageSymbolsBuffer = buffer;
sCommpageSymbols = symbols;
sCommpageStringTable = stringTable;
}
if (_imageID != NULL)
*_imageID = sCommpageImageID;
if (_imagePath != NULL)
*_imagePath = (char*)kCommpageName;
if (_imageName != NULL)
*_imageName = (char*)kCommpageName;
bool exactMatch = false;
elf_sym* foundSymbol = NULL;
addr_t foundLocation = (addr_t)NULL;
for (int32 i = 0; i < sCommpageSymbolCount && !exactMatch; i++) {
elf_sym* symbol = &sCommpageSymbols[i];
addr_t location = (addr_t)__gCommPageAddress + symbol->st_value;
if (location <= (addr_t)address && location >= foundLocation) {
foundSymbol = symbol;
foundLocation = location;
if (location + symbol->st_size > (addr_t)address) {
exactMatch = true;
break;
}
}
}
if (_exactMatch != NULL)
*_exactMatch = exactMatch;
if (foundSymbol != NULL) {
*_symbolName = sCommpageStringTable + foundSymbol->st_name;
if (_type != NULL) {
if (foundSymbol->Type() == STT_FUNC)
*_type = B_SYMBOL_TYPE_TEXT;
else if (foundSymbol->Type() == STT_OBJECT)
*_type = B_SYMBOL_TYPE_DATA;
else
*_type = B_SYMBOL_TYPE_ANY;
}
if (_location != NULL)
*_location = (void*)foundLocation;
} else {
*_symbolName = NULL;
if (_location != NULL)
*_location = NULL;
}
return B_OK;
}