├── Android.mk ├── kallsyms_in_memory.h └── kallsyms_in_memory.c /Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | 5 | LOCAL_SRC_FILES := \ 6 | kallsyms_in_memory.c \ 7 | 8 | LOCAL_MODULE := libkallsyms 9 | LOCAL_MODULE_TAGS := optional 10 | 11 | include $(BUILD_STATIC_LIBRARY) 12 | -------------------------------------------------------------------------------- /kallsyms_in_memory.h: -------------------------------------------------------------------------------- 1 | #ifndef __KALLSYMSPRINT_H__ 2 | #define __KALLSYMSPRINT_H__ 3 | 4 | #include 5 | #include 6 | 7 | typedef struct _kallsyms kallsyms; 8 | 9 | kallsyms * kallsyms_in_memory_init (unsigned long *mem, size_t len); 10 | void kallsyms_in_memory_free (kallsyms *kallsyms); 11 | unsigned long kallsyms_in_memory_lookup_name (kallsyms *kallsyms, const char *name); 12 | bool kallsyms_in_memory_lookup_names (kallsyms *kallsyms, const char *name, 13 | unsigned long *addresses, size_t n_addresses); 14 | const char *kallsyms_in_memory_lookup_address(kallsyms *kallsyms, unsigned long address); 15 | 16 | bool is_address_in_kallsyms_table(kallsyms *kallsyms, void *mapped_address); 17 | 18 | void kallsyms_in_memory_set_verbose(bool verbose); 19 | void kallsyms_in_memory_print_all(kallsyms *kallsyms); 20 | void kallsyms_in_memory_print_all_to_file(kallsyms *kallsyms, FILE *fp); 21 | 22 | #endif /* __KALLSYMSPRINT_H__ */ 23 | 24 | /* 25 | vi:ts=2:nowrap:ai:expandtab:sw=2 26 | */ 27 | -------------------------------------------------------------------------------- /kallsyms_in_memory.c: -------------------------------------------------------------------------------- 1 | #define _LARGEFILE64_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "kallsyms_in_memory.h" 9 | 10 | #ifndef le32toh 11 | #define le32toh letoh32 12 | #endif 13 | 14 | #ifndef le16toh 15 | #define le16toh letoh16 16 | #endif 17 | 18 | #ifdef __LP64__ 19 | #define letoh le64toh 20 | #define htole htole64 21 | #else 22 | #define letoh le32toh 23 | #define htole htole32 24 | #endif 25 | 26 | 27 | #define PATTERN_MAX 8 28 | 29 | static bool verbose_output; 30 | 31 | #define DBGPRINT(fmt...) do { if (verbose_output) { fprintf(stderr, fmt); } } while (0) 32 | 33 | #define ARRAY_SIZE(n) (sizeof (n) / sizeof (*n)) 34 | 35 | struct _kallsyms { 36 | unsigned long num_syms; 37 | unsigned long *addresses; 38 | uint8_t *names; 39 | uint8_t *token_table; 40 | uint16_t *token_index; 41 | unsigned long *markers; 42 | int has_type_table; 43 | }; 44 | 45 | /* 46 | * Expand a compressed symbol data into the resulting uncompressed string, 47 | * given the offset to where the symbol is in the compressed stream. 48 | */ 49 | static unsigned int 50 | kallsyms_in_memory_expand_symbol(kallsyms *info, unsigned int off, char *result) 51 | { 52 | int len, skipped_type_marker = info->has_type_table; 53 | const uint8_t *tptr, *data; 54 | 55 | /* Get the compressed symbol length from the first symbol byte. */ 56 | data = &info->names[off]; 57 | len = *data; 58 | data++; 59 | 60 | /* 61 | * Update the offset to return the offset for the next symbol on 62 | * the compressed stream. 63 | */ 64 | off += len + 1; 65 | 66 | /* 67 | * For every byte on the compressed symbol data, copy the table 68 | * entry for that byte. 69 | */ 70 | while (len) { 71 | tptr = &info->token_table[le16toh(info->token_index[*data])]; 72 | data++; 73 | len--; 74 | 75 | while (*tptr) { 76 | if (skipped_type_marker) { 77 | *result = *tptr; 78 | result++; 79 | } 80 | else { 81 | skipped_type_marker = 1; 82 | } 83 | 84 | tptr++; 85 | } 86 | } 87 | 88 | *result = '\0'; 89 | 90 | /* Return to offset to the next symbol. */ 91 | return off; 92 | } 93 | 94 | /* Lookup the address for this symbol. Returns 0 if not found. */ 95 | unsigned long 96 | kallsyms_in_memory_lookup_name(kallsyms *info, const char *name) 97 | { 98 | char namebuf[1024]; 99 | unsigned long i; 100 | unsigned int off; 101 | 102 | if (!info) { 103 | return 0; 104 | } 105 | 106 | for (i = 0, off = 0; i < info->num_syms; i++) { 107 | off = kallsyms_in_memory_expand_symbol(info, off, namebuf); 108 | if (strcmp(namebuf, name) == 0) { 109 | return letoh(info->addresses[i]); 110 | } 111 | } 112 | return 0; 113 | } 114 | 115 | bool 116 | kallsyms_in_memory_lookup_names(kallsyms *info, const char *name, 117 | unsigned long *addresses, size_t n_addresses) 118 | { 119 | char namebuf[1024]; 120 | unsigned long i, count; 121 | unsigned int off; 122 | 123 | if (!info) { 124 | return false; 125 | } 126 | 127 | for (i = 0, off = 0, count = 0; 128 | i < info->num_syms && count < n_addresses; 129 | i++) { 130 | off = kallsyms_in_memory_expand_symbol(info, off, namebuf); 131 | if (strcmp(namebuf, name) == 0) { 132 | addresses[count] = letoh(info->addresses[i]); 133 | count++; 134 | } 135 | } 136 | if (!count) { 137 | return false; 138 | } 139 | 140 | return true; 141 | } 142 | 143 | /* Lookup the symbol for this address. Returns NULL if not found. */ 144 | const char * 145 | kallsyms_in_memory_lookup_address(kallsyms *info, unsigned long address) 146 | { 147 | static char namebuf[1024]; 148 | unsigned long i; 149 | unsigned int off; 150 | 151 | if (!info) { 152 | return NULL; 153 | } 154 | 155 | for (i = 0, off = 0; i < info->num_syms; i++) { 156 | off = kallsyms_in_memory_expand_symbol(info, off, namebuf); 157 | if (letoh(info->addresses[i]) == address) { 158 | return namebuf; 159 | } 160 | } 161 | return NULL; 162 | } 163 | 164 | static const unsigned long const pattern_kallsyms_addresses_1[PATTERN_MAX] = { 165 | #ifdef __LP64__ 166 | 0xffffffc000080000, // _text 167 | 0xffffffc000080040, // stext 168 | 0xffffffc000080080, // __h_error 169 | 0xffffffc000080080, // __h_error_p 170 | 0xffffffc0000800c0, // __h_enable_mmu 171 | 0xffffffc0000800d8, // __h_turn_mmu_on 172 | 0xffffffc0000800e4, // __vet_fdt 173 | #else 174 | //00000000, // __vectors_start 175 | 0x00001000, // __stubs_start 176 | 0x00001004, // vector_rst 177 | 0x00001020, // vector_irq 178 | 0x000010a0, // vector_dabt 179 | #endif 180 | 0 181 | }; 182 | 183 | static const unsigned long const pattern_kallsyms_addresses_2[PATTERN_MAX] = { 184 | #ifdef __LP64__ 185 | 0xffffffc000081000, // T do_undefinstr 186 | 0xffffffc000081000, // T _stext 187 | 0xffffffc000081000, // T __exception_text_start 188 | #else 189 | 0xc0008000, // __init_begin 190 | 0xc0008000, // _sinittext 191 | 0xc0008000, // stext 192 | 0xc0008000, // _text 193 | #endif 194 | 0 195 | }; 196 | 197 | static const unsigned long const pattern_kallsyms_addresses_3[PATTERN_MAX] = { 198 | 0xc0008000, // stext 199 | 0xc0008000, // _text 200 | 0 201 | }; 202 | 203 | static const unsigned long const pattern_kallsyms_addresses_4[PATTERN_MAX] = { 204 | 0xc00081c0, // asm_do_IRQ 205 | 0xc00081c0, // _stext 206 | 0xc00081c0, // __exception_text_start 207 | 0 208 | }; 209 | 210 | static const unsigned long const pattern_kallsyms_addresses_5[PATTERN_MAX] = { 211 | 0xc0008180, // asm_do_IRQ 212 | 0xc0008180, // _stext 213 | 0xc0008180, // __exception_text_start 214 | 0 215 | }; 216 | 217 | static const unsigned long const pattern_kallsyms_addresses_6[PATTERN_MAX] = { 218 | 0xc0100000, // asm_do_IRQ 219 | 0xc0100000, // _stext 220 | 0xc0100000, // __exception_text_start 221 | 0xc0100004, // do_undefinstr 222 | 0 223 | }; 224 | 225 | static const unsigned long const * const pattern_kallsyms_addresses[] = { 226 | pattern_kallsyms_addresses_1, 227 | pattern_kallsyms_addresses_2, 228 | pattern_kallsyms_addresses_3, 229 | pattern_kallsyms_addresses_4, 230 | pattern_kallsyms_addresses_5, 231 | pattern_kallsyms_addresses_6, 232 | }; 233 | 234 | static unsigned long * 235 | search_pattern(unsigned long *base, unsigned long count, const unsigned long *const pattern) 236 | { 237 | unsigned long *addr = base; 238 | unsigned long i; 239 | int pattern_count; 240 | 241 | for (pattern_count = 0; pattern[pattern_count]; pattern_count++) { 242 | ; 243 | } 244 | 245 | for (i = 0; i < count - pattern_count; i++) { 246 | if(addr[i] != pattern[0]) { 247 | continue; 248 | } 249 | 250 | if (memcmp(&addr[i], pattern, sizeof (pattern[0]) * pattern_count) == 0) { 251 | return &addr[i]; 252 | } 253 | } 254 | return 0; 255 | } 256 | 257 | static bool 258 | is_type_table(const unsigned int *mem, unsigned long length) 259 | { 260 | int i; 261 | 262 | if (length < 256 * 4) { 263 | return false; 264 | } 265 | 266 | for (i = 0; i < 256; i++) { 267 | unsigned int data = mem[i] & ~0x20202020; 268 | 269 | if (data != 0x54545454) { 270 | return false; 271 | } 272 | } 273 | 274 | return true; 275 | } 276 | 277 | static int 278 | get_kallsyms_in_memory_addresses(kallsyms *info, unsigned long *mem, unsigned long length, unsigned long offset) 279 | { 280 | unsigned long *addr = mem; 281 | unsigned long *end = (unsigned long*)((unsigned long)mem + length); 282 | 283 | if (!info) { 284 | return -1; 285 | } 286 | 287 | while (addr < end) { 288 | unsigned long *search = addr; 289 | unsigned long i; 290 | 291 | // get kallsyms_in_memory_addresses pointer 292 | for (i = 0; i < sizeof (pattern_kallsyms_addresses) / sizeof (pattern_kallsyms_addresses[0]); i++) { 293 | unsigned long pattern_le[PATTERN_MAX]; 294 | int j; 295 | 296 | for (j = 0; j < PATTERN_MAX; j++) { 297 | pattern_le[j] = htole(pattern_kallsyms_addresses[i][j]); 298 | } 299 | 300 | addr = search_pattern(search, end - search, pattern_le); 301 | if (addr) { 302 | break; 303 | } 304 | } 305 | 306 | if (!addr) { 307 | return 0; 308 | } 309 | 310 | info->addresses = addr; 311 | 312 | // search end of kallsyms_in_memory_addresses 313 | unsigned long n=0; 314 | #ifdef __LP64__ 315 | while (letoh(addr[0]) <= 0xffffffc000080000LL) { 316 | #else 317 | while (letoh(addr[0]) <= 0xc0000000) { 318 | #endif 319 | n++; 320 | addr++; 321 | if (addr >= end) { 322 | return 0; 323 | } 324 | } 325 | #ifdef __LP64__ 326 | while (letoh(addr[0]) > 0xffffffc000080000LL) { 327 | #else 328 | while (letoh(addr[0]) > 0xc0000000) { 329 | #endif 330 | n++; 331 | addr++; 332 | if (addr >= end) { 333 | return 0; 334 | } 335 | } 336 | 337 | // skip there is filled by 0x0 338 | while (addr[0] == 0x00000000) { 339 | addr++; 340 | if (addr >= end) { 341 | return 0; 342 | } 343 | } 344 | 345 | info->num_syms = letoh(addr[0]); 346 | addr++; 347 | if (addr >= end) { 348 | return 0; 349 | } 350 | 351 | // adjust if it has one more address that equals zero 352 | if (info->num_syms == n + 1) { 353 | if (info->addresses > mem 354 | && info->addresses[-1] == 0) { 355 | info->addresses--; 356 | n++; 357 | } 358 | } 359 | 360 | DBGPRINT("[+]kallsyms_addresses=%08lx\n", (unsigned long)info->addresses + offset); 361 | DBGPRINT(" count=%08x\n", (unsigned int)n); 362 | DBGPRINT("[+]kallsyms_num_syms=%08x\n", (unsigned int)info->num_syms); 363 | 364 | // check kallsyms_in_memory_num_syms 365 | if (info->num_syms != n) { 366 | continue; 367 | } 368 | 369 | // skip there is filled by 0x0 370 | while (addr[0] == 0x00000000) { 371 | addr++; 372 | if (addr >= end) { 373 | return 0; 374 | } 375 | } 376 | 377 | info->names = (uint8_t*)addr; 378 | DBGPRINT("[+]kallsyms_names=%08lx\n", (unsigned long)info->names + offset); 379 | 380 | // search end of kallsyms_in_memory_names 381 | unsigned int off; 382 | for (i = 0, off = 0; i < info->num_syms; i++) { 383 | int len = info->names[off]; 384 | off += len + 1; 385 | if (&info->names[off] >= (uint8_t*)end) { 386 | return 0; 387 | } 388 | } 389 | 390 | // adjust 391 | #ifdef __LP64__ 392 | addr = (unsigned long*)((((unsigned long)&info->names[off]-1)|0x7)+1); 393 | #else 394 | addr = (unsigned long*)((((unsigned long)&info->names[off]-1)|0x3)+1); 395 | #endif 396 | if (addr >= end) { 397 | return 0; 398 | } 399 | 400 | // skip there is filled by 0x0 401 | while (addr[0] == 0x00000000) { 402 | addr++; 403 | if (addr >= end) { 404 | return 0; 405 | } 406 | } 407 | 408 | if (is_type_table((void *)addr, (unsigned long)end - (unsigned long)addr)) { 409 | DBGPRINT("[+]kallsyms_type_table=%08lx\n", (unsigned long)addr + offset); 410 | info->has_type_table = 1; 411 | 412 | // skip kallsyms_type_table if exist 413 | while (addr[0] != 0x00000000) { 414 | 415 | addr++; 416 | if (addr >= end) { 417 | return 0; 418 | } 419 | } 420 | 421 | // skip there is filled by 0x0 422 | while (addr[0] == 0x00000000) { 423 | addr++; 424 | if (addr >= end) { 425 | return 0; 426 | } 427 | } 428 | } 429 | 430 | // but kallsyms_in_memory_markers shoud be start 0x00000000 431 | addr--; 432 | 433 | info->markers = addr; 434 | DBGPRINT("[+]kallsyms_markers=%08lx\n", (unsigned long)info->markers + offset); 435 | 436 | // end of kallsyms_in_memory_markers 437 | addr = &info->markers[((info->num_syms-1)>>8)+1]; 438 | if (addr >= end) { 439 | return 0; 440 | } 441 | 442 | // skip there is filled by 0x0 443 | while (addr[0] == 0x00000000) { 444 | addr++; 445 | if (addr >= end) { 446 | return 0; 447 | } 448 | } 449 | 450 | info->token_table = (uint8_t*)addr; 451 | DBGPRINT("[+]kallsyms_token_table=%08lx\n", (unsigned long)info->token_table + offset); 452 | 453 | // search end of kallsyms_in_memory_token_table 454 | i = 0; 455 | while (info->token_table[i] != 0x00 || info->token_table[i+1] != 0x00) { 456 | i++; 457 | if (&info->token_table[i-1] >= (uint8_t*)end) { 458 | return 0; 459 | } 460 | } 461 | 462 | // skip there is filled by 0x0 463 | while (info->token_table[i] == 0x00) { 464 | i++; 465 | if (&info->token_table[i-1] >= (uint8_t*)end) { 466 | return 0; 467 | } 468 | } 469 | 470 | // but kallsyms_in_memory_markers shoud be start 0x0000 471 | info->token_index = (uint16_t*)&info->token_table[i-2]; 472 | DBGPRINT("[+]kallsyms_token_index=%08lx\n", (unsigned long)info->token_index + offset); 473 | 474 | return 1; 475 | } 476 | return 0; 477 | } 478 | 479 | kallsyms * 480 | kallsyms_in_memory_init(unsigned long *mem, size_t len) 481 | { 482 | kallsyms *info; 483 | #ifdef __LP64__ 484 | unsigned long mmap_offset = 0xffffffc000080000LL - (unsigned long)mem; 485 | #else 486 | unsigned long mmap_offset = 0xc0008000 - (unsigned long)mem; 487 | #endif 488 | DBGPRINT("[+]mmap\n"); 489 | DBGPRINT(" mem=%08lx length=%08x offset=%08lx\n", (unsigned long)mem, (unsigned int)len, (unsigned long)mmap_offset); 490 | 491 | info = calloc(sizeof(*info), 1); 492 | if (info == NULL) { 493 | return NULL; 494 | } 495 | 496 | int ret = get_kallsyms_in_memory_addresses(info, mem, len, mmap_offset); 497 | if (!ret) { 498 | fprintf(stderr, "kallsyms_in_memory_addresses search failed\n"); 499 | free(info); 500 | return NULL; 501 | } 502 | 503 | //kallsyms_in_memory_print_all(); 504 | DBGPRINT("[+]kallsyms_lookup_name\n"); 505 | 506 | return info; 507 | } 508 | 509 | bool 510 | is_address_in_kallsyms_table(kallsyms *info, void *mapped_address) 511 | { 512 | DBGPRINT("check %p <= %p <= %p\n", 513 | info->addresses, mapped_address, &info->addresses[info->num_syms]); 514 | 515 | if (mapped_address < (void *)info->addresses) 516 | return false; 517 | 518 | if (mapped_address > (void *)&info->addresses[info->num_syms]) 519 | return false; 520 | 521 | return true; 522 | } 523 | 524 | void 525 | kallsyms_in_memory_print_all_to_file(kallsyms *info, FILE *fp) 526 | { 527 | char namebuf[1024]; 528 | unsigned long i; 529 | unsigned int off; 530 | 531 | if (!info) { 532 | return; 533 | } 534 | 535 | for (i = 0, off = 0; i < info->num_syms; i++) { 536 | off = kallsyms_in_memory_expand_symbol(info, off, namebuf); 537 | fprintf(fp, "%08lx %s\n", (unsigned long)letoh(info->addresses[i]), namebuf); 538 | } 539 | return; 540 | } 541 | 542 | void 543 | kallsyms_in_memory_print_all(kallsyms *info) 544 | { 545 | if (!info) { 546 | return; 547 | } 548 | kallsyms_in_memory_print_all_to_file(info, stdout); 549 | } 550 | 551 | void 552 | kallsyms_in_memory_set_verbose(bool verbose) 553 | { 554 | verbose_output = verbose; 555 | } 556 | 557 | void 558 | kallsyms_in_memory_free(kallsyms *info) 559 | { 560 | if (info) { 561 | free(info); 562 | } 563 | } 564 | 565 | #if 0 566 | static bool 567 | do_kallsyms_in_memory(void) 568 | { 569 | bool ret; 570 | void *address; 571 | 572 | if (!map_kernel_memory()) { 573 | printf("Failed to mmap due to %s.\n", strerror(errno)); 574 | 575 | return false; 576 | } 577 | 578 | #ifdef __LP64__ 579 | address = convert_to_kernel_mapped_address((void *)0xffffffc000080000LL); 580 | #else 581 | address = convert_to_kernel_mapped_address((void *)0xc0008000); 582 | #endif 583 | ret = get_kallsyms_in_memory(address, KERNEL_MEMORY_SIZE); 584 | 585 | unmap_kernel_memory(); 586 | return ret; 587 | } 588 | 589 | int 590 | main(int argc, char **argv) 591 | { 592 | if (!do_kallsyms_in_memory()) { 593 | exit(EXIT_FAILURE); 594 | } 595 | 596 | exit(EXIT_SUCCESS); 597 | } 598 | #endif 599 | /* 600 | vi:ts=2:nowrap:ai:expandtab:sw=2 601 | */ 602 | --------------------------------------------------------------------------------