1/* 2 * sym.c 3 * lockstat 4 * 5 * Created by Samuel Gosselin on 10/1/14. 6 * Copyright 2014 Apple Inc. All rights reserved. 7 * 8 */ 9 10#include <CoreSymbolication/CoreSymbolication.h> 11#include <CoreSymbolication/CoreSymbolicationPrivate.h> 12 13#include <libkern/OSAtomic.h> 14#include <sys/sysctl.h> 15 16#define LAST_SEGMENT_TOKEN "__LAST SEGMENT" 17#define SYMBOL_NAME_MAX_LENGTH (16) 18#define MIN_PAGE_SIZE (4 * 1024) 19 20typedef struct { 21 uintptr_t location; 22 size_t length; 23 char const *name; 24} sym_t; 25 26static sym_t *g_symtable; 27static size_t g_nbsyms; 28static size_t g_maxsyms; 29static CSSymbolicatorRef g_symbolicator; 30 31static int 32add_symbol(uintptr_t location, size_t length, char const* name) 33{ 34 sym_t *sym; 35 36 if (g_symtable == NULL || g_nbsyms >= g_maxsyms) 37 return -1; 38 39 sym = &g_symtable[g_nbsyms++]; 40 sym->location = location; 41 sym->length = length; 42 sym->name = name; 43 44 return 0; 45} 46 47static int 48create_fake_symbols(CSRange table_range) 49{ 50 int i, ncpus; 51 size_t len = sizeof(ncpus); 52 char *name; 53 54 assert(table_range.length > 0); 55 assert(table_range.location > NULL); 56 57 /* retrieve the number of cpus */ 58 if (sysctlbyname("hw.ncpu", &ncpus, &len, NULL, 0) < 0) { 59 fprintf(stderr, "could not retrieve the number of cpus in the system\n"); 60 return -1; 61 } 62 63 assert(ncpus > 0); 64 65 /* Check if we will have enough room for the symbols */ 66 if (ncpus > table_range.length) { 67 fprintf(stderr, "symbols table not big enough to store the fake cpu symbols\n"); 68 return -1; 69 } 70 71 /* 72 * Currently, we're only storing fake symbols for the cpus, and the size 73 * is already known. 74 */ 75 g_maxsyms = ncpus; 76 if (!(g_symtable = malloc(sizeof(sym_t) * ncpus))) { 77 fprintf(stderr, "could not allocate memory for the symbols table\n"); 78 return -1; 79 } 80 81 /* allocate a new symbol for each cpu in the system */ 82 for (i = 0; i < ncpus; ++i) { 83 if (!(name = malloc(SYMBOL_NAME_MAX_LENGTH))) { 84 fprintf(stderr, "could not allocate memory for the cpu[%d] symbol\n", i); 85 return -1; 86 } 87 88 (void) snprintf(name, SYMBOL_NAME_MAX_LENGTH, "cpu[%d]", i); 89 90 if (add_symbol(table_range.location + i, 0, name) < 0) { 91 fprintf(stderr, "could not add the symbol [%s] to the symbol table", name); 92 return -1; 93 } 94 } 95 96 return 0; 97} 98 99static int 100find_symtab_range(CSRange *res) 101{ 102 __block CSSegmentRef last_segment; 103 __block CSRange last_section_range; 104 CSRange last_segment_range; 105 106 assert(res); 107 108 /* locate the kernel last segment */ 109 CSSymbolicatorForeachSegmentAtTime(g_symbolicator, kCSNow, ^(CSSegmentRef it) { 110 if (!strcmp(LAST_SEGMENT_TOKEN, CSRegionGetName(it))) 111 last_segment = it; 112 }); 113 114 /* ensure that the segment can store our symbols table */ 115 last_segment_range = CSRegionGetRange(last_segment); 116 if (last_segment_range.length < MIN_PAGE_SIZE) 117 return -1; 118 119 /* locate the last section in the last segment */ 120 CSSegmentForeachSection(last_segment, ^(CSSectionRef it) { 121 last_section_range = CSRegionGetRange(it); 122 }); 123 124 /* no section found, create an empty section */ 125 if (!last_section_range.location) 126 last_section_range = CSRangeMake(last_segment_range.location, 0); 127 128 /* initialize the symbols table range */ 129 res->location = CSRangeMax(last_section_range); 130 res->length = CSRangeMax(last_segment_range) - res->location; 131 132 /* be sure that we're not returning an incorrect range */ 133 assert(CSRangeContainsRange(last_segment_range, *res)); 134 135 return 0; 136} 137 138int 139symtab_init(void) 140{ 141 CSRange table_range; 142 143 enum CSSymbolicatorPrivateFlags symflags = 0x0; 144 symflags |= kCSSymbolicatorDefaultCreateFlags; 145 symflags |= kCSSymbolicatorUseSlidKernelAddresses; 146 147 /* retrieve the kernel symbolicator */ 148 g_symbolicator = CSSymbolicatorCreateWithMachKernelFlagsAndNotification(symflags, NULL); 149 if (CSIsNull(g_symbolicator)) { 150 fprintf(stderr, "could not retrieve the kernel symbolicator\n"); 151 return -1; 152 } 153 154 /* retrieve the range for the table */ 155 if (find_symtab_range(&table_range) < 0) { 156 fprintf(stderr, "could not find a valid range for the symbols table\n"); 157 return -1; 158 } 159 160 return create_fake_symbols(table_range); 161} 162 163char const* 164addr_to_sym(uintptr_t addr, uintptr_t *offset, size_t *sizep) 165{ 166 CSSymbolRef symbol; 167 CSRange range; 168 int i; 169 170 assert(offset); 171 assert(sizep); 172 173 symbol = CSSymbolicatorGetSymbolWithAddressAtTime(g_symbolicator, addr, kCSNow); 174 if (!CSIsNull(symbol)) { 175 range = CSSymbolGetRange(symbol); 176 *offset = addr - range.location; 177 *sizep = range.length; 178 return CSSymbolGetName(symbol); 179 } 180 181 for (i = 0; i < g_nbsyms; ++i) { 182 sym_t* sym = &g_symtable[i]; 183 if ((addr >= sym->location) && (addr <= sym->location + sym->length)) { 184 *offset = addr - sym->location; 185 *sizep = sym->length; 186 return sym->name; 187 } 188 } 189 190 return NULL; 191} 192 193uintptr_t 194sym_to_addr(char *name) 195{ 196 CSSymbolRef symbol; 197 int i; 198 199 symbol = CSSymbolicatorGetSymbolWithNameAtTime(g_symbolicator, name, kCSNow); 200 if (!CSIsNull(symbol)) 201 return CSSymbolGetRange(symbol).location; 202 203 for (i = 0; i < g_nbsyms; ++i) 204 if (!strcmp(name, g_symtable[i].name)) 205 return g_symtable[i].location; 206 207 return NULL; 208} 209 210size_t 211sym_size(char *name) 212{ 213 CSSymbolRef symbol; 214 int i; 215 216 symbol = CSSymbolicatorGetSymbolWithNameAtTime(g_symbolicator, name, kCSNow); 217 if (!CSIsNull(symbol)) 218 return CSSymbolGetRange(symbol).length; 219 220 for (i = 0; i < g_nbsyms; ++i) 221 if (!strcmp(name, g_symtable[i].name)) 222 return g_symtable[i].length; 223 224 return NULL; 225} 226 227