- Timestamp:
- Feb 15, 2015 11:34:11 PM (10 years ago)
- svn:sync-xref-src-repo-rev:
- 98276
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Debugger/DBGPlugInLinux.cpp
r50665 r54212 49 49 * (For fending off illegal interface method calls.) */ 50 50 bool fValid; 51 /** Set if 64-bit, clear if 32-bit. */ 52 bool f64Bit; 51 53 52 54 /** The address of the linux banner. … … 54 56 DBGFADDRESS AddrLinuxBanner; 55 57 /** Kernel base address. 56 * This is set during probing . */58 * This is set during probing, refined during kallsyms parsing. */ 57 59 DBGFADDRESS AddrKernelBase; 60 /** The kernel size. */ 61 uint32_t cbKernel; 62 63 /** The number of kernel symbols (kallsyms_num_syms). 64 * This is set during init. */ 65 uint32_t cKernelSymbols; 66 /** The size of the kernel name table (sizeof(kallsyms_names)). */ 67 uint32_t cbKernelNames; 68 /** Number of entries in the kernel_markers table. */ 69 uint32_t cKernelNameMarkers; 70 /** The size of the kernel symbol token table. */ 71 uint32_t cbKernelTokenTable; 72 /** The address of the encoded kernel symbol names (kallsyms_names). */ 73 DBGFADDRESS AddrKernelNames; 74 /** The address of the kernel symbol addresses (kallsyms_addresses). */ 75 DBGFADDRESS AddrKernelAddresses; 76 /** The address of the kernel symbol name markers (kallsyms_markers). */ 77 DBGFADDRESS AddrKernelNameMarkers; 78 /** The address of the kernel symbol token table (kallsyms_token_table). */ 79 DBGFADDRESS AddrKernelTokenTable; 80 /** The address of the kernel symbol token index table (kallsyms_token_index). */ 81 DBGFADDRESS AddrKernelTokenIndex; 82 58 83 } DBGDIGGERLINUX; 59 84 /** Pointer to the linux guest OS digger instance data. */ … … 66 91 /** Validates a 32-bit linux kernel address */ 67 92 #define LNX32_VALID_ADDRESS(Addr) ((Addr) > UINT32_C(0x80000000) && (Addr) < UINT32_C(0xfffff000)) 93 /** Validates a 64-bit linux kernel address */ 94 #define LNX64_VALID_ADDRESS(Addr) ((Addr) > UINT64_C(0xffff800000000000) && (Addr) < UINT64_C(0xfffffffffffff000)) 68 95 69 96 /** The max kernel size. */ 70 #define LNX_MAX_KERNEL_SIZE 0x0f000000 97 #define LNX_MAX_KERNEL_SIZE UINT32_C(0x0f000000) 98 99 /** The maximum size we expect for kallsyms_names. */ 100 #define LNX_MAX_KALLSYMS_NAMES_SIZE UINT32_C(0x200000) 101 /** The maximum size we expect for kallsyms_token_table. */ 102 #define LNX_MAX_KALLSYMS_TOKEN_TABLE_SIZE UINT32_C(0x10000) 103 /** The minimum number of symbols we expect in kallsyms_num_syms. */ 104 #define LNX_MIN_KALLSYMS_SYMBOLS UINT32_C(2048) 105 /** The maximum number of symbols we expect in kallsyms_num_syms. */ 106 #define LNX_MAX_KALLSYMS_SYMBOLS UINT32_C(1048576) 107 /** The min length an encoded symbol in kallsyms_names is expected to have. */ 108 #define LNX_MIN_KALLSYMS_ENC_LENGTH UINT8_C(1) 109 /** The max length an encoded symbol in kallsyms_names is expected to have. 110 * @todo check real life here. */ 111 #define LNX_MAX_KALLSYMS_ENC_LENGTH UINT8_C(28) 112 /** The approximate maximum length of a string token. */ 113 #define LNX_MAX_KALLSYMS_TOKEN_LEN UINT16_C(32) 114 115 116 /** Module tag for linux ('linuxmod' on little endian ASCII systems). */ 117 #define DIG_LNX_MOD_TAG UINT64_C(0x545f5d78758e898c) 71 118 72 119 … … 156 203 157 204 /** 205 * Worker for dbgDiggerLinuxFindStartOfNamesAndSymbolCount that update the 206 * digger data. 207 * 208 * @returns VINF_SUCCESS. 209 * @param pThis The Linux digger data to update. 210 * @param pAddrKernelNames The kallsyms_names address. 211 * @param cKernelSymbols The number of kernel symbol. 212 * @param cbAddress The guest address size. 213 */ 214 static int dbgDiggerLinuxFoundStartOfNames(PDBGDIGGERLINUX pThis, PCDBGFADDRESS pAddrKernelNames, 215 uint32_t cKernelSymbols, uint32_t cbAddress) 216 { 217 pThis->cKernelSymbols = cKernelSymbols; 218 pThis->AddrKernelNames = *pAddrKernelNames; 219 pThis->AddrKernelAddresses = *pAddrKernelNames; 220 DBGFR3AddrSub(&pThis->AddrKernelAddresses, (cKernelSymbols + 1) * cbAddress); 221 222 Log(("dbgDiggerLinuxFoundStartOfNames: AddrKernelAddresses=%RGv\n" 223 "dbgDiggerLinuxFoundStartOfNames: cKernelSymbols=%#x (at %RGv)\n" 224 "dbgDiggerLinuxFoundStartOfNames: AddrKernelName=%RGv\n", 225 pThis->AddrKernelAddresses.FlatPtr, 226 pThis->cKernelSymbols, pThis->AddrKernelNames.FlatPtr - cbAddress, 227 pThis->AddrKernelNames.FlatPtr)); 228 return VINF_SUCCESS; 229 } 230 231 232 /** 233 * Tries to find the address of the kallsyms_names, kallsyms_num_syms and 234 * kallsyms_addresses symbols. 235 * 236 * The kallsyms_num_syms is read and stored in pThis->cKernelSymbols, while the 237 * addresses of the other two are stored as pThis->AddrKernelNames and 238 * pThis->AddrKernelAddresses. 239 * 240 * @returns VBox status code, success indicating that all three variables have 241 * been found and taken down. 242 * @param pUVM The user mode VM handle. 243 * @param pThis The Linux digger data. 244 * @param pHitAddr An address we think is inside kallsyms_names. 245 */ 246 static int dbgDiggerLinuxFindStartOfNamesAndSymbolCount(PUVM pUVM, PDBGDIGGERLINUX pThis, PCDBGFADDRESS pHitAddr) 247 { 248 /* 249 * Search backwards in chunks. 250 */ 251 union 252 { 253 uint8_t ab[0x1000]; 254 uint32_t au32[0x1000 / sizeof(uint32_t)]; 255 uint64_t au64[0x1000 / sizeof(uint64_t)]; 256 } uBuf; 257 uint32_t cbLeft = LNX_MAX_KALLSYMS_NAMES_SIZE; 258 uint32_t cbBuf = pHitAddr->FlatPtr & (sizeof(uBuf) - 1); 259 DBGFADDRESS CurAddr = *pHitAddr; 260 DBGFR3AddrSub(&CurAddr, cbBuf); 261 cbBuf += sizeof(uint64_t) - 1; /* In case our kobj hit is in the first 4/8 bytes. */ 262 for (;;) 263 { 264 int rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &CurAddr, &uBuf, sizeof(uBuf)); 265 if (RT_FAILURE(rc)) 266 return rc; 267 268 /* 269 * We assume that the three symbols are aligned on guest pointer boundrary. 270 * 271 * The boundrary between the two tables should be noticable as the number 272 * is unlikely to be more than 16 millions, there will be at least one zero 273 * byte where it is, 64-bit will have 5 zero bytes. Zero bytes aren't all 274 * that common in the kallsyms_names table. 275 * 276 * Also the kallsyms_names table starts with a length byte, which means 277 * we're likely to see a byte in the range 1..31. 278 * 279 * The kallsyms_addresses are mostly sorted (except for the start where the 280 * absolute symbols are), so we'll spot a bunch of kernel addresses 281 * immediately preceeding the kallsyms_num_syms field. 282 * 283 * Lazy bird: If kallsyms_num_syms is on a buffer boundrary, we skip 284 * the check for kernel addresses preceeding it. 285 */ 286 if (pThis->f64Bit) 287 { 288 uint32_t i = cbBuf / sizeof(uint64_t); 289 while (i-- > 0) 290 if ( uBuf.au64[i] <= LNX_MAX_KALLSYMS_SYMBOLS 291 && uBuf.au64[i] >= LNX_MIN_KALLSYMS_SYMBOLS) 292 { 293 uint8_t *pb = (uint8_t *)&uBuf.au64[i + 1]; 294 if ( pb[0] <= LNX_MAX_KALLSYMS_ENC_LENGTH 295 && pb[0] >= LNX_MIN_KALLSYMS_ENC_LENGTH) 296 { 297 if ( (i <= 0 || LNX64_VALID_ADDRESS(uBuf.au64[i - 1])) 298 && (i <= 1 || LNX64_VALID_ADDRESS(uBuf.au64[i - 2])) 299 && (i <= 2 || LNX64_VALID_ADDRESS(uBuf.au64[i - 3]))) 300 return dbgDiggerLinuxFoundStartOfNames(pThis, 301 DBGFR3AddrAdd(&CurAddr, (i + 1) * sizeof(uint64_t)), 302 (uint32_t)uBuf.au64[i], sizeof(uint64_t)); 303 } 304 } 305 } 306 else 307 { 308 uint32_t i = cbBuf / sizeof(uint32_t); 309 while (i-- > 0) 310 if ( uBuf.au32[i] <= LNX_MAX_KALLSYMS_SYMBOLS 311 && uBuf.au32[i] >= LNX_MIN_KALLSYMS_SYMBOLS) 312 { 313 uint8_t *pb = (uint8_t *)&uBuf.au32[i + 1]; 314 if ( pb[0] <= LNX_MAX_KALLSYMS_ENC_LENGTH 315 && pb[0] >= LNX_MIN_KALLSYMS_ENC_LENGTH) 316 { 317 if ( (i <= 0 || LNX32_VALID_ADDRESS(uBuf.au32[i - 1])) 318 && (i <= 1 || LNX32_VALID_ADDRESS(uBuf.au32[i - 2])) 319 && (i <= 2 || LNX32_VALID_ADDRESS(uBuf.au32[i - 3]))) 320 return dbgDiggerLinuxFoundStartOfNames(pThis, 321 DBGFR3AddrAdd(&CurAddr, (i + 1) * sizeof(uint32_t)), 322 uBuf.au32[i], sizeof(uint32_t)); 323 } 324 } 325 } 326 327 /* 328 * Advance 329 */ 330 if (RT_UNLIKELY(cbLeft <= sizeof(uBuf))) 331 { 332 Log(("dbgDiggerLinuxFindStartOfNamesAndSymbolCount: failed (pHitAddr=%RGv)\n", pHitAddr->FlatPtr)); 333 return VERR_NOT_FOUND; 334 } 335 cbLeft -= sizeof(uBuf); 336 DBGFR3AddrSub(&CurAddr, sizeof(uBuf)); 337 cbBuf = sizeof(uBuf); 338 } 339 } 340 341 342 /** 343 * Worker for dbgDiggerLinuxFindEndNames that records the findings. 344 * 345 * @returns VINF_SUCCESS 346 * @param pThis The linux digger data to update. 347 * @param pAddrMarkers The address of the marker (kallsyms_markers). 348 * @param cbMarkerEntry The size of a marker entry (32-bit or 64-bit). 349 */ 350 static int dbgDiggerLinuxFoundMarkers(PDBGDIGGERLINUX pThis, PCDBGFADDRESS pAddrMarkers, uint32_t cbMarkerEntry) 351 { 352 pThis->cbKernelNames = pAddrMarkers->FlatPtr - pThis->AddrKernelNames.FlatPtr - 1; 353 pThis->AddrKernelNameMarkers = *pAddrMarkers; 354 pThis->cKernelNameMarkers = RT_ALIGN_32(pThis->cKernelSymbols, 256) / 256; 355 pThis->AddrKernelTokenTable = *pAddrMarkers; 356 DBGFR3AddrAdd(&pThis->AddrKernelTokenTable, pThis->cKernelNameMarkers * cbMarkerEntry); 357 358 Log(("dbgDiggerLinuxFoundMarkers: AddrKernelNames=%RGv cbKernelNames=%#x\n" 359 "dbgDiggerLinuxFoundMarkers: AddrKernelNameMarkers=%RGv cKernelNameMarkers=%#x\n" 360 "dbgDiggerLinuxFoundMarkers: AddrKernelTokenTable=%RGv\n", 361 pThis->AddrKernelNames.FlatPtr, pThis->cbKernelNames, 362 pThis->AddrKernelNameMarkers.FlatPtr, pThis->cKernelNameMarkers, 363 pThis->AddrKernelTokenTable.FlatPtr)); 364 return VINF_SUCCESS; 365 } 366 367 368 /** 369 * Tries to find the end of kallsyms_names and thereby the start of 370 * kallsyms_markers and kallsyms_token_table. 371 * 372 * The kallsyms_names size is stored in pThis->cbKernelNames, the addresses of 373 * the two other symbols in pThis->AddrKernelNameMarkers and 374 * pThis->AddrKernelTokenTable. The number of marker entries is stored in 375 * pThis->cKernelNameMarkers. 376 * 377 * @returns VBox status code, success indicating that all three variables have 378 * been found and taken down. 379 * @param pUVM The user mode VM handle. 380 * @param pThis The Linux digger data. 381 * @param pHitAddr An address we think is inside kallsyms_names. 382 */ 383 static int dbgDiggerLinuxFindEndOfNamesAndMore(PUVM pUVM, PDBGDIGGERLINUX pThis, PCDBGFADDRESS pHitAddr) 384 { 385 /* 386 * Search forward in chunks. 387 */ 388 union 389 { 390 uint8_t ab[0x1000]; 391 uint32_t au32[0x1000 / sizeof(uint32_t)]; 392 uint64_t au64[0x1000 / sizeof(uint64_t)]; 393 } uBuf; 394 bool fPendingZeroHit = false; 395 uint32_t cbLeft = LNX_MAX_KALLSYMS_NAMES_SIZE + sizeof(uBuf); 396 uint32_t offBuf = pHitAddr->FlatPtr & (sizeof(uBuf) - 1); 397 DBGFADDRESS CurAddr = *pHitAddr; 398 DBGFR3AddrSub(&CurAddr, offBuf); 399 for (;;) 400 { 401 int rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &CurAddr, &uBuf, sizeof(uBuf)); 402 if (RT_FAILURE(rc)) 403 return rc; 404 405 /* 406 * The kallsyms_names table is followed by kallsyms_markers we assume, 407 * using sizeof(unsigned long) alignment like the preceeding symbols. 408 * 409 * The kallsyms_markers table has entried sizeof(unsigned long) and 410 * contains offsets into kallsyms_names. The kallsyms_markers used to 411 * index kallsyms_names and reduce seek time when looking up the name 412 * of an address/symbol. Each entry in kallsyms_markers covers 256 413 * symbol names. 414 * 415 * Because of this, the first entry is always zero and all the entries 416 * are ascending. It also follows that the size of the table can be 417 * calculated from kallsyms_num_syms. 418 * 419 * Note! We could also have walked kallsyms_names by skipping 420 * kallsyms_num_syms names, but this is faster and we will 421 * validate the encoded names later. 422 */ 423 if (pThis->f64Bit) 424 { 425 if ( RT_UNLIKELY(fPendingZeroHit) 426 && uBuf.au64[0] >= (LNX_MIN_KALLSYMS_ENC_LENGTH + 1) * 256 427 && uBuf.au64[0] <= (LNX_MAX_KALLSYMS_ENC_LENGTH + 1) * 256) 428 return dbgDiggerLinuxFoundMarkers(pThis, DBGFR3AddrSub(&CurAddr, sizeof(uint64_t)), sizeof(uint64_t)); 429 430 uint32_t const cEntries = sizeof(uBuf) / sizeof(uint64_t); 431 for (uint32_t i = offBuf / sizeof(uint64_t); i < cEntries; i++) 432 if (uBuf.au64[i] == 0) 433 { 434 if (RT_UNLIKELY(i + 1 >= cEntries)) 435 { 436 fPendingZeroHit = true; 437 break; 438 } 439 if ( uBuf.au64[i + 1] >= (LNX_MIN_KALLSYMS_ENC_LENGTH + 1) * 256 440 && uBuf.au64[i + 1] <= (LNX_MAX_KALLSYMS_ENC_LENGTH + 1) * 256) 441 return dbgDiggerLinuxFoundMarkers(pThis, DBGFR3AddrAdd(&CurAddr, i * sizeof(uint64_t)), sizeof(uint64_t)); 442 } 443 } 444 else 445 { 446 if ( RT_UNLIKELY(fPendingZeroHit) 447 && uBuf.au32[0] >= (LNX_MIN_KALLSYMS_ENC_LENGTH + 1) * 256 448 && uBuf.au32[0] <= (LNX_MAX_KALLSYMS_ENC_LENGTH + 1) * 256) 449 return dbgDiggerLinuxFoundMarkers(pThis, DBGFR3AddrSub(&CurAddr, sizeof(uint32_t)), sizeof(uint32_t)); 450 451 uint32_t const cEntries = sizeof(uBuf) / sizeof(uint32_t); 452 for (uint32_t i = offBuf / sizeof(uint32_t); i < cEntries; i++) 453 if (uBuf.au32[i] == 0) 454 { 455 if (RT_UNLIKELY(i + 1 >= cEntries)) 456 { 457 fPendingZeroHit = true; 458 break; 459 } 460 if ( uBuf.au32[i + 1] >= (LNX_MIN_KALLSYMS_ENC_LENGTH + 1) * 256 461 && uBuf.au32[i + 1] <= (LNX_MAX_KALLSYMS_ENC_LENGTH + 1) * 256) 462 return dbgDiggerLinuxFoundMarkers(pThis, DBGFR3AddrAdd(&CurAddr, i * sizeof(uint32_t)), sizeof(uint32_t)); 463 } 464 } 465 466 /* 467 * Advance 468 */ 469 if (RT_UNLIKELY(cbLeft <= sizeof(uBuf))) 470 { 471 Log(("dbgDiggerLinuxFindEndOfNamesAndMore: failed (pHitAddr=%RGv)\n", pHitAddr->FlatPtr)); 472 return VERR_NOT_FOUND; 473 } 474 cbLeft -= sizeof(uBuf); 475 DBGFR3AddrAdd(&CurAddr, sizeof(uBuf)); 476 offBuf = 0; 477 } 478 } 479 480 481 /** 482 * Locates the kallsyms_token_index table. 483 * 484 * Storing the address in pThis->AddrKernelTokenIndex and the size of the token 485 * table in pThis->cbKernelTokenTable. 486 * 487 * @returns VBox status code. 488 * @param pUVM The user mode VM handle. 489 * @param pThis The Linux digger data. 490 */ 491 static int dbgDiggerLinuxFindTokenIndex(PUVM pUVM, PDBGDIGGERLINUX pThis) 492 { 493 /* 494 * The kallsyms_token_table is very much like a string table. Due to the 495 * nature of the compression algorithm it is reasonably short (one example 496 * here is 853 bytes), so we'll not be reading it in chunks but in full. 497 * To be on the safe side, we read 8KB, ASSUMING we won't run into unmapped 498 * memory or any other nasty stuff... 499 */ 500 union 501 { 502 uint8_t ab[0x2000]; 503 uint16_t au16[0x2000 / sizeof(uint16_t)]; 504 } uBuf; 505 DBGFADDRESS CurAddr = pThis->AddrKernelTokenTable; 506 int rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &CurAddr, &uBuf, sizeof(uBuf)); 507 if (RT_FAILURE(rc)) 508 return rc; 509 510 /* 511 * We've got two choices here, either walk the string table or look for 512 * the next structure, kallsyms_token_index. 513 * 514 * The token index is a table of 256 uint16_t entries (index by bytes 515 * from kallsyms_names) that gives offsets in kallsyms_token_table. It 516 * starts with a zero entry and the following entries are sorted in 517 * ascending order. The range of the entries are reasonably small since 518 * kallsyms_token_table is small. 519 * 520 * The alignment seems to be sizeof(unsigned long), just like 521 * kallsyms_token_table. 522 * 523 * So, we start by looking for a zero 16-bit entry. 524 */ 525 uint32_t cIncr = (pThis->f64Bit ? sizeof(uint64_t) : sizeof(uint32_t)) / sizeof(uint16_t); 526 527 for (uint32_t i = 0; i < sizeof(uBuf) / sizeof(uint16_t) - 16; i += cIncr) 528 if ( uBuf.au16[i] == 0 529 && uBuf.au16[i + 1] > 0 530 && uBuf.au16[i + 1] <= LNX_MAX_KALLSYMS_TOKEN_LEN 531 && (uint16_t)(uBuf.au16[i + 2] - uBuf.au16[i + 1] - 1U) <= (uint16_t)LNX_MAX_KALLSYMS_TOKEN_LEN 532 && (uint16_t)(uBuf.au16[i + 3] - uBuf.au16[i + 2] - 1U) <= (uint16_t)LNX_MAX_KALLSYMS_TOKEN_LEN 533 && (uint16_t)(uBuf.au16[i + 4] - uBuf.au16[i + 3] - 1U) <= (uint16_t)LNX_MAX_KALLSYMS_TOKEN_LEN 534 && (uint16_t)(uBuf.au16[i + 5] - uBuf.au16[i + 4] - 1U) <= (uint16_t)LNX_MAX_KALLSYMS_TOKEN_LEN 535 && (uint16_t)(uBuf.au16[i + 6] - uBuf.au16[i + 5] - 1U) <= (uint16_t)LNX_MAX_KALLSYMS_TOKEN_LEN 536 ) 537 { 538 pThis->AddrKernelTokenIndex = CurAddr; 539 DBGFR3AddrAdd(&pThis->AddrKernelTokenIndex, i * sizeof(uint16_t)); 540 pThis->cbKernelTokenTable = i * sizeof(uint16_t); 541 return VINF_SUCCESS; 542 } 543 544 Log(("dbgDiggerLinuxFindTokenIndex: Failed (%RGv..%RGv)\n", CurAddr.FlatPtr, CurAddr.FlatPtr + (RTGCUINTPTR)sizeof(uBuf))); 545 return VERR_NOT_FOUND; 546 } 547 548 549 /** 550 * Loads the kernel symbols from the kallsyms tables. 551 * 552 * @returns VBox status code. 553 * @param pUVM The user mode VM handle. 554 * @param pThis The Linux digger data. 555 */ 556 static int dbgDiggerLinuxLoadKernelSymbols(PUVM pUVM, PDBGDIGGERLINUX pThis) 557 { 558 /* 559 * Allocate memory for temporary table copies, reading the tables as we go. 560 */ 561 uint32_t const cbGuestAddr = pThis->f64Bit ? sizeof(uint64_t) : sizeof(uint32_t); 562 void *pvAddresses = RTMemAllocZ(pThis->cKernelSymbols * cbGuestAddr); 563 int rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &pThis->AddrKernelAddresses, pvAddresses, pThis->cKernelSymbols * cbGuestAddr); 564 if (RT_SUCCESS(rc)) 565 { 566 uint8_t *pbNames = (uint8_t *)RTMemAllocZ(pThis->cbKernelNames); 567 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &pThis->AddrKernelNames, pbNames, pThis->cbKernelNames); 568 if (RT_SUCCESS(rc)) 569 { 570 char *pszzTokens = (char *)RTMemAllocZ(pThis->cbKernelTokenTable); 571 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &pThis->AddrKernelTokenTable, pszzTokens, pThis->cbKernelTokenTable); 572 if (RT_SUCCESS(rc)) 573 { 574 uint16_t *paoffTokens = (uint16_t *)RTMemAllocZ(256 * sizeof(uint16_t)); 575 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &pThis->AddrKernelTokenIndex, paoffTokens, 256 * sizeof(uint16_t)); 576 if (RT_SUCCESS(rc)) 577 { 578 /* 579 * Figure out the kernel start and end. 580 */ 581 RTGCUINTPTR uKernelStart = pThis->AddrKernelAddresses.FlatPtr; 582 RTGCUINTPTR uKernelEnd = pThis->AddrKernelTokenIndex.FlatPtr + 256 * sizeof(uint16_t); 583 uint32_t i; 584 if (cbGuestAddr == sizeof(uint64_t)) 585 { 586 uint64_t *pauAddrs = (uint64_t *)pvAddresses; 587 for (i = 0; i < pThis->cKernelSymbols; i++) 588 if ( pauAddrs[i] < uKernelStart 589 && LNX64_VALID_ADDRESS(pauAddrs[i]) 590 && uKernelStart - pauAddrs[i] < LNX_MAX_KERNEL_SIZE) 591 uKernelStart = pauAddrs[i]; 592 593 for (i = pThis->cKernelSymbols - 1; i > 0; i--) 594 if ( pauAddrs[i] > uKernelEnd 595 && LNX64_VALID_ADDRESS(pauAddrs[i]) 596 && pauAddrs[i] - uKernelEnd < LNX_MAX_KERNEL_SIZE) 597 uKernelEnd = pauAddrs[i]; 598 } 599 else 600 { 601 uint32_t *pauAddrs = (uint32_t *)pvAddresses; 602 for (i = 0; i < pThis->cKernelSymbols; i++) 603 if ( pauAddrs[i] < uKernelStart 604 && LNX32_VALID_ADDRESS(pauAddrs[i]) 605 && uKernelStart - pauAddrs[i] < LNX_MAX_KERNEL_SIZE) 606 uKernelStart = pauAddrs[i]; 607 608 for (i = pThis->cKernelSymbols - 1; i > 0; i--) 609 if ( pauAddrs[i] > uKernelEnd 610 && LNX32_VALID_ADDRESS(pauAddrs[i]) 611 && pauAddrs[i] - uKernelEnd < LNX_MAX_KERNEL_SIZE) 612 uKernelEnd = pauAddrs[i]; 613 } 614 615 RTGCUINTPTR cbKernel = uKernelEnd - uKernelStart; 616 pThis->cbKernel = (uint32_t)cbKernel; 617 DBGFR3AddrFromFlat(pUVM, &pThis->AddrKernelBase, uKernelStart); 618 Log(("dbgDiggerLinuxLoadKernelSymbols: uKernelStart=%RGv cbKernel=%#x\n", uKernelStart, cbKernel)); 619 620 /* 621 * Create a module for the kernel. 622 */ 623 RTDBGMOD hMod; 624 rc = RTDbgModCreate(&hMod, "vmlinux", cbKernel, 0 /*fFlags*/); 625 if (RT_SUCCESS(rc)) 626 { 627 rc = RTDbgModSetTag(hMod, DIG_LNX_MOD_TAG); AssertRC(rc); 628 rc = VINF_SUCCESS; 629 630 /* 631 * Enumerate the symbols. 632 */ 633 uint8_t const *pbCurAddr = (uint8_t const *)pvAddresses; 634 uint32_t offName = 0; 635 uint32_t cLeft = pThis->cKernelSymbols; 636 while (cLeft-- > 0 && RT_SUCCESS(rc)) 637 { 638 /* Decode the symbol name first. */ 639 if (RT_LIKELY(offName < pThis->cbKernelNames)) 640 { 641 uint8_t cbName = pbNames[offName++]; 642 if (RT_LIKELY(offName + cbName <= pThis->cbKernelNames)) 643 { 644 char szSymbol[4096]; 645 uint32_t offSymbol = 0; 646 while (cbName-- > 0) 647 { 648 uint8_t bEnc = pbNames[offName++]; 649 uint16_t offToken = paoffTokens[bEnc]; 650 if (RT_LIKELY(offToken < pThis->cbKernelTokenTable)) 651 { 652 const char *pszToken = &pszzTokens[offToken]; 653 char ch; 654 while ((ch = *pszToken++) != '\0') 655 if (offSymbol < sizeof(szSymbol) - 1) 656 szSymbol[offSymbol++] = ch; 657 } 658 else 659 { 660 rc = VERR_INVALID_UTF8_ENCODING; 661 break; 662 } 663 } 664 szSymbol[offSymbol < sizeof(szSymbol) ? offSymbol : sizeof(szSymbol) - 1] = '\0'; 665 666 /* The address. */ 667 RTGCUINTPTR uSymAddr = cbGuestAddr == sizeof(uint64_t) 668 ? *(uint64_t *)pbCurAddr : *(uint32_t *)pbCurAddr; 669 pbCurAddr += cbGuestAddr; 670 671 /* Add it without the type char. */ 672 if (uSymAddr - uKernelStart <= cbKernel) 673 { 674 rc = RTDbgModSymbolAdd(hMod, &szSymbol[1], RTDBGSEGIDX_RVA, uSymAddr - uKernelStart, 675 0 /*cb*/, 0 /*fFlags*/, NULL); 676 if (RT_FAILURE(rc)) 677 { 678 if ( rc == VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE 679 || rc == VERR_DBG_INVALID_RVA 680 || rc == VERR_DBG_ADDRESS_CONFLICT 681 || rc == VERR_DBG_DUPLICATE_SYMBOL) 682 { 683 Log2(("dbgDiggerLinuxLoadKernelSymbols: RTDbgModSymbolAdd(,%s,) failed %Rrc (ignored)\n", szSymbol, rc)); 684 rc = VINF_SUCCESS; 685 } 686 else 687 Log(("dbgDiggerLinuxLoadKernelSymbols: RTDbgModSymbolAdd(,%s,) failed %Rrc\n", szSymbol, rc)); 688 } 689 } 690 } 691 else 692 { 693 rc = VERR_END_OF_STRING; 694 Log(("dbgDiggerLinuxLoadKernelSymbols: offName=%#x cLeft=%#x cbName=%#x cbKernelNames=%#x\n", 695 offName, cLeft, cbName, pThis->cbKernelNames)); 696 } 697 } 698 else 699 { 700 rc = VERR_END_OF_STRING; 701 Log(("dbgDiggerLinuxLoadKernelSymbols: offName=%#x cLeft=%#x cbKernelNames=%#x\n", 702 offName, cLeft, pThis->cbKernelNames)); 703 } 704 } 705 706 /* 707 * Link the module into the address space. 708 */ 709 if (RT_SUCCESS(rc)) 710 { 711 RTDBGAS hAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL); 712 if (hAs != NIL_RTDBGAS) 713 rc = RTDbgAsModuleLink(hAs, hMod, uKernelStart, RTDBGASLINK_FLAGS_REPLACE); 714 else 715 rc = VERR_INTERNAL_ERROR; 716 RTDbgAsRelease(hAs); 717 } 718 else 719 Log(("dbgDiggerLinuxFindTokenIndex: Failed: %Rrc\n", rc)); 720 RTDbgModRelease(hMod); 721 } 722 else 723 Log(("dbgDiggerLinuxFindTokenIndex: RTDbgModCreate failed: %Rrc\n", rc)); 724 } 725 else 726 Log(("dbgDiggerLinuxFindTokenIndex: Reading token index at %RGv failed: %Rrc\n", 727 pThis->AddrKernelTokenIndex.FlatPtr, rc)); 728 RTMemFree(paoffTokens); 729 } 730 else 731 Log(("dbgDiggerLinuxFindTokenIndex: Reading token table at %RGv failed: %Rrc\n", 732 pThis->AddrKernelTokenTable.FlatPtr, rc)); 733 RTMemFree(pszzTokens); 734 } 735 else 736 Log(("dbgDiggerLinuxFindTokenIndex: Reading encoded names at %RGv failed: %Rrc\n", 737 pThis->AddrKernelNames.FlatPtr, rc)); 738 RTMemFree(pbNames); 739 } 740 else 741 Log(("dbgDiggerLinuxFindTokenIndex: Reading symbol addresses at %RGv failed: %Rrc\n", 742 pThis->AddrKernelAddresses.FlatPtr, rc)); 743 RTMemFree(pvAddresses); 744 return rc; 745 } 746 747 748 /** 749 * Checks if there is a likely kallsyms_names fragment at pHitAddr. 750 * 751 * @returns true if it's a likely fragment, false if not. 752 * @param pUVM The user mode VM handle. 753 * @param pHitAddr The address where paNeedle was found. 754 * @param pabNeedle The fragment we've been searching for. 755 * @param cbNeedle The length of the fragment. 756 */ 757 static bool dbgDiggerLinuxIsLikelyNameFragment(PUVM pUVM, PCDBGFADDRESS pHitAddr, uint8_t const *pabNeedle, uint8_t cbNeedle) 758 { 759 /* 760 * Examples of lead and tail bytes of our choosen needle in a randomly 761 * picked kernel: 762 * k o b j 763 * 22 6b 6f 62 6a aa 764 * fc 6b 6f 62 6a aa 765 * 82 6b 6f 62 6a 5f - ascii trail byte (_). 766 * ee 6b 6f 62 6a aa 767 * fc 6b 6f 62 6a 5f - ascii trail byte (_). 768 * 0a 74 6b 6f 62 6a 5f ea - ascii lead (t) and trail (_) bytes. 769 * 0b 54 6b 6f 62 6a aa - ascii lead byte (T). 770 * ... omitting 29 samples similar to the last two ... 771 * d8 6b 6f 62 6a aa 772 * d8 6b 6f 62 6a aa 773 * d8 6b 6f 62 6a aa 774 * d8 6b 6f 62 6a aa 775 * f9 5f 6b 6f 62 6a 5f 94 - ascii lead and trail bytes (_) 776 * f9 5f 6b 6f 62 6a 0c - ascii lead byte (_). 777 * fd 6b 6f 62 6a 0f 778 * ... enough. 779 */ 780 uint8_t abBuf[32]; 781 DBGFADDRESS ReadAddr = *pHitAddr; 782 DBGFR3AddrSub(&ReadAddr, 2); 783 int rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &ReadAddr, abBuf, 2 + cbNeedle + 2); 784 if (RT_SUCCESS(rc)) 785 { 786 if (memcmp(&abBuf[2], pabNeedle, cbNeedle) == 0) /* paranoia */ 787 { 788 uint8_t const bLead = abBuf[1] == '_' || abBuf[1] == 'T' || abBuf[1] == 't' ? abBuf[0] : abBuf[1]; 789 uint8_t const offTail = 2 + cbNeedle; 790 uint8_t const bTail = abBuf[offTail] == '_' ? abBuf[offTail] : abBuf[offTail + 1]; 791 if ( bLead >= 1 && (bLead < 0x20 || bLead >= 0x80) 792 && bTail >= 1 && (bTail < 0x20 || bTail >= 0x80)) 793 return true; 794 Log(("dbgDiggerLinuxIsLikelyNameFragment: failed at %RGv: bLead=%#x bTail=%#x (offTail=%#x)\n", 795 pHitAddr->FlatPtr, bLead, bTail, offTail)); 796 } 797 else 798 Log(("dbgDiggerLinuxIsLikelyNameFragment: failed at %RGv: Needle changed!\n", pHitAddr->FlatPtr)); 799 } 800 else 801 Log(("dbgDiggerLinuxIsLikelyNameFragment: failed at %RGv: %Rrc\n", pHitAddr->FlatPtr, rc)); 802 803 return false; 804 } 805 806 807 /** 158 808 * @copydoc DBGFOSREG::pfnInit 159 809 */ … … 162 812 PDBGDIGGERLINUX pThis = (PDBGDIGGERLINUX)pvData; 163 813 Assert(!pThis->fValid); 164 #if 0 /* later */ 165 int rc; 166 167 /* 168 * Algorithm to find the ksymtab: 169 * 1. Find a known export string in kstrtab ("init_task", "enable_hlt" or something). 170 * 2. Search for the address its at, this should give you the corresponding ksymtab entry. 171 * 3. Search backwards assuming that kstrtab is corresponding to ksymtab. 172 */ 173 DBGFADDRESS AddrKernelKsymTab; 174 175 176 #endif 814 815 /* 816 * Assume 64-bit kernels all live way beyond 32-bit address space. 817 */ 818 pThis->f64Bit = pThis->AddrLinuxBanner.FlatPtr > UINT32_MAX; 819 820 /* 821 * Go looking for the kallsyms table. If it's there, it will be somewhere 822 * after the linux_banner symbol, so use it for starting the search. 823 */ 824 DBGFADDRESS CurAddr = pThis->AddrLinuxBanner; 825 uint32_t cbLeft = LNX_MAX_KERNEL_SIZE; 826 while (cbLeft > 4096) 827 { 828 static const uint8_t s_abNeedle[] = "kobj"; 829 DBGFADDRESS HitAddr; 830 int rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &CurAddr, cbLeft, 1 /*uAlign*/, 831 s_abNeedle, sizeof(s_abNeedle) - 1, &HitAddr); 832 if (RT_FAILURE(rc)) 833 break; 834 if (dbgDiggerLinuxIsLikelyNameFragment(pUVM, &HitAddr, s_abNeedle, sizeof(s_abNeedle) - 1)) 835 { 836 /* There will be another hit near by. */ 837 DBGFR3AddrAdd(&HitAddr, 1); 838 rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &HitAddr, LNX_MAX_KALLSYMS_NAMES_SIZE, 1 /*uAlign*/, 839 s_abNeedle, sizeof(s_abNeedle) - 1, &HitAddr); 840 if ( RT_SUCCESS(rc) 841 && dbgDiggerLinuxIsLikelyNameFragment(pUVM, &HitAddr, s_abNeedle, sizeof(s_abNeedle) - 1)) 842 { 843 /* 844 * We've got a very likely candidate for a location inside kallsyms_names. 845 * Try find the start of it, that is to say, try find kallsyms_num_syms. 846 * kallsyms_num_syms is aligned on sizeof(unsigned long) boundrary 847 */ 848 rc = dbgDiggerLinuxFindStartOfNamesAndSymbolCount(pUVM, pThis, &HitAddr); 849 if (RT_SUCCESS(rc)) 850 rc = dbgDiggerLinuxFindEndOfNamesAndMore(pUVM, pThis, &HitAddr); 851 if (RT_SUCCESS(rc)) 852 rc = dbgDiggerLinuxFindTokenIndex(pUVM, pThis); 853 if (RT_SUCCESS(rc)) 854 rc = dbgDiggerLinuxLoadKernelSymbols(pUVM, pThis); 855 856 } 857 } 858 859 /* 860 * Advance. 861 */ 862 RTGCUINTPTR cbDistance = HitAddr.FlatPtr - CurAddr.FlatPtr + sizeof(s_abNeedle) - 1; 863 if (RT_UNLIKELY(cbDistance >= cbLeft)) 864 { 865 Log(("dbgDiggerLinuxInit: Failed to find kallsyms\n")); 866 break; 867 } 868 cbLeft -= cbDistance; 869 DBGFR3AddrAdd(&CurAddr, cbDistance); 870 871 } 872 177 873 pThis->fValid = true; 178 874 return VINF_SUCCESS; … … 190 886 * Look for "Linux version " at the start of the rodata segment. 191 887 * Hope that this comes before any message buffer or other similar string. 192 * .193 * Note! Only Linux version 2.x.y, where x in {0..6}. .888 * 889 * Note! Only Linux version 2.x.y, where x in {0..6}. 194 890 */ 195 891 for (unsigned i = 0; i < RT_ELEMENTS(g_au64LnxKernelAddresses); i++)
Note:
See TracChangeset
for help on using the changeset viewer.