#include <CoreSymbolication/CoreSymbolication.h>
#include <CoreSymbolication/CoreSymbolicationPrivate.h>
#include <libkern/OSAtomic.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <dtrace.h>
#include <dt_module.h>
#include <dt_impl.h>
#include <assert.h>
int dtrace_private_probes_requested(void) {
int value = 0;
int err = 0;
size_t len = sizeof(value);
err = sysctlbyname("kern.dtrace.provide_private_probes", &value, &len, NULL, 0);
if (err < 0) {
fprintf(stderr, "Unable to retrieve the kern.dtrace.provide_private_probes state\n");
value = 0;
}
return value;
}
CSSymbolicatorRef dtrace_kernel_symbolicator(bool with_slide) {
static pthread_mutex_t symbolicator_lock = PTHREAD_MUTEX_INITIALIZER;
static CSSymbolicatorRef symbolicator_slide = { 0, 0 }; static CSSymbolicatorRef symbolicator_noslide = { 0, 0 };
assert((!with_slide || geteuid() == 0) && "Retrieving the kernel slide requires to be root");
CSSymbolicatorRef *const symbolicator_ptr = with_slide ? &symbolicator_slide : &symbolicator_noslide;
if (CSIsNull(*symbolicator_ptr)) {
pthread_mutex_lock(&symbolicator_lock);
if (CSIsNull(*symbolicator_ptr)) {
uint32_t flags = kCSSymbolicatorDefaultCreateFlags;
if (with_slide)
flags |= kCSSymbolicatorUseSlidKernelAddresses;
CSSymbolicatorRef temp = CSSymbolicatorCreateWithMachKernelFlagsAndNotification(flags, NULL);
OSMemoryBarrier();
*symbolicator_ptr = temp;
}
pthread_mutex_unlock(&symbolicator_lock);
}
return *symbolicator_ptr;
}
int
dtrace_kernel_path(char *kernel_path, size_t max_length) {
assert(kernel_path);
char const* path = CSSymbolOwnerGetPath(CSSymbolicatorGetAOutSymbolOwner(dtrace_kernel_symbolicator(false)));
if (path) {
if (strlcpy(kernel_path, path, max_length) < max_length)
return 0;
}
return -1;
}
static void filter_module_symbols(CSSymbolOwnerRef owner, int provide_private_probes, CSSymbolIterator valid_symbol)
{
if (TRUE || (CSSymbolOwnerIsObject(owner) && !(CSSymbolOwnerGetDataFlags(owner) & kCSSymbolOwnerDataFoundDsym))) {
CSRegionRef text_region = CSSymbolOwnerGetRegionWithName(owner, "__TEXT __text");
CSRegionForeachSymbol(text_region, ^(CSSymbolRef symbol) {
if ((CSSymbolIsUnnamed(symbol) == false) && (provide_private_probes || CSSymbolIsExternal(symbol))) {
if (CSSymbolGetRange(symbol).length > 0) {
valid_symbol(symbol);
}
}
});
} else {
CSSymbolOwnerForeachSymbol(owner, ^(CSSymbolRef symbol) {
if (CSSymbolIsFunction(symbol) && (CSSymbolGetRange(symbol).length > 0)) {
valid_symbol(symbol);
}
});
}
}
void dtrace_update_kernel_symbols(dtrace_hdl_t* dtp)
{
uint64_t count = 0;
dt_ioctl(dtp, DTRACEIOC_MODUUIDSLIST, &count);
if (count) {
assert(count < 2048);
dtrace_module_uuids_list_t* uuids_list;
if ((uuids_list = calloc(1, DTRACE_MODULE_UUIDS_LIST_SIZE(count))) == NULL) {
fprintf(stderr, "Unable to allocate uuids_list for count %llu\n", count);
return;
}
uuids_list->dtmul_count = count;
if (dt_ioctl(dtp, DTRACEIOC_MODUUIDSLIST, uuids_list) != 0) {
fprintf(stderr, "Unable to get module uuids list from kernel [%s]\n", strerror(errno));
goto uuids_cleanup;
}
CSSymbolicatorRef symbolicator = dtrace_kernel_symbolicator(true);
if (CSIsNull(symbolicator))
{
fprintf(stderr, "Unable to get kernel symbolicator\n");
goto uuids_cleanup;
}
uint32_t i;
for (i=0; i<uuids_list->dtmul_count; i++) {
UUID* uuid = &uuids_list->dtmul_uuid[i];
CFUUIDRef uuid_ref = CFUUIDCreateFromUUIDBytes(NULL, *(CFUUIDBytes*)uuid);
CSSymbolOwnerRef owner = CSSymbolicatorGetSymbolOwnerWithUUIDAtTime(symbolicator, uuid_ref, kCSNow);
if (CSSymbolOwnerGetDataFlags(owner) & kCSSymbolOwnerDataEmpty) {
struct stat statinfo;
if (CSSymbolOwnerGetPath(owner) && (stat(CSSymbolOwnerGetPath(owner), &statinfo) == 0)) {
if (S_ISREG(statinfo.st_mode)) {
fprintf(stderr,"WARNING: The file at [%s] does not match the UUID of the version loaded in the kernel\n", CSSymbolOwnerGetPath(owner));
}
}
}
__block uint64_t module_symbols_count = 0;
filter_module_symbols(owner, dtrace_private_probes_requested(), ^(CSSymbolRef symbol) { module_symbols_count++; });
if (module_symbols_count == 0) {
continue;
}
__block uint32_t module_symbol_index = 0;
dtrace_module_symbols_t* module_symbols;
if ((module_symbols = calloc(1, DTRACE_MODULE_SYMBOLS_SIZE(module_symbols_count))) == NULL) {
fprintf(stderr, "Unable to allocate module_symbols for count %llu\n", module_symbols_count);
goto module_symbols_cleanup;
}
memcpy(module_symbols->dtmodsyms_uuid, uuid, sizeof(UUID));
module_symbols->dtmodsyms_count = module_symbols_count;
filter_module_symbols(owner, dtrace_private_probes_requested(), ^(CSSymbolRef symbol) {
dtrace_symbol_t* dtrace_symbol = &module_symbols->dtmodsyms_symbols[module_symbol_index++];
CSRange range = CSSymbolGetRange(symbol);
dtrace_symbol->dtsym_addr = range.location;
dtrace_symbol->dtsym_size = (uint32_t)range.length;
strlcpy(dtrace_symbol->dtsym_name, CSSymbolGetMangledName(symbol), sizeof(dtrace_symbol->dtsym_name));
});
if (dt_ioctl(dtp, DTRACEIOC_PROVMODSYMS, module_symbols) != 0) {
fprintf(stderr, "Unable to send module symbols for %s (count %lld) to kernel [%s]\n", CSSymbolOwnerGetPath(owner), module_symbols->dtmodsyms_count, strerror(errno));
}
module_symbols_cleanup:
if (module_symbols)
free(module_symbols);
CFRelease(uuid_ref);
}
uuids_cleanup:
if (uuids_list)
free(uuids_list);
}
}
int dtrace_lookup_by_addr(dtrace_hdl_t *dtp,
GElf_Addr addr,
char *aux_sym_name_buffer,
size_t aux_bufsize,
GElf_Sym *symp,
dtrace_syminfo_t *sip)
{
CSSymbolicatorRef kernelSymbolicator = dtrace_kernel_symbolicator(true);
if (CSIsNull(kernelSymbolicator))
return (dt_set_errno(dtp, EDT_NOSYMBOLICATOR));
CSSymbolOwnerRef owner = CSSymbolicatorGetSymbolOwnerWithAddressAtTime(kernelSymbolicator, (mach_vm_address_t)addr, kCSNow);
if (CSIsNull(owner))
return (dt_set_errno(dtp, EDT_NOSYMADDR));
if (symp != NULL) {
CSSymbolOwnerRef symbol = CSSymbolOwnerGetSymbolWithAddress(owner, (mach_vm_address_t)addr);
if (CSIsNull(symbol))
return (dt_set_errno(dtp, EDT_NOSYMADDR));
CSRange addressRange = CSSymbolGetRange(symbol);
symp->st_info = GELF_ST_INFO((STB_GLOBAL), (STT_FUNC));
symp->st_other = 0;
symp->st_shndx = SHN_MACHO;
symp->st_value = addressRange.location;
symp->st_size = addressRange.length;
if (CSSymbolIsUnnamed(symbol)) {
if (aux_sym_name_buffer) {
if (CSArchitectureIs64Bit(CSSymbolOwnerGetArchitecture(CSSymbolGetSymbolOwner(symbol))))
snprintf(aux_sym_name_buffer, aux_bufsize, "0x%016llx", CSSymbolGetRange(symbol).location);
else
snprintf(aux_sym_name_buffer, aux_bufsize, "0x%08llx", CSSymbolGetRange(symbol).location);
}
symp->st_name = (uintptr_t)aux_sym_name_buffer;
} else {
const char *mangledName;
if (_dtrace_mangled &&
(mangledName = CSSymbolGetMangledName(symbol)) &&
strlen(mangledName) >= 3 &&
mangledName[0] == '_' &&
mangledName[1] == '_' &&
mangledName[2] == 'Z') {
symp->st_name = (uintptr_t)mangledName;
} else {
symp->st_name = (uintptr_t)CSSymbolGetName(symbol);
}
}
}
if (sip != NULL) {
sip->dts_object = CSSymbolOwnerGetName(owner);
if (symp != NULL) {
sip->dts_name = (const char *)(uintptr_t)symp->st_name;
} else {
sip->dts_name = NULL;
}
sip->dts_id = 0;
}
return (0);
}