Changeset 82806 in vbox
- Timestamp:
- Jan 21, 2020 1:45:13 AM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r0drv/darwin/dbgkrnlinfo-r0drv-darwin.cpp
r76553 r82806 120 120 # define RETURN_VERR_LDR_ARCH_MISMATCH do { return VERR_LDR_ARCH_MISMATCH; } while (0) 121 121 #endif 122 #if defined(DEBUG_bird) && !defined(IN_RING3) 123 # define LOG_MISMATCH(...) kprintf(__VA_ARGS__) 124 # define LOG_NOT_PRESENT(...) kprintf(__VA_ARGS__) 125 # define LOG_BAD_SYM(...) kprintf(__VA_ARGS__) 126 # define LOG_SUCCESS(...) kprintf(__VA_ARGS__) 127 #else 128 # define LOG_MISMATCH(...) Log((__VA_ARGS__)) 129 # define LOG_NOT_PRESENT(...) Log((__VA_ARGS__)) 130 # define LOG_BAD_SYM(...) printf(__VA_ARGS__) 131 # define LOG_SUCCESS(...) printf(__VA_ARGS__) 132 #endif 122 133 /** @} */ 123 134 … … 142 153 /** Reference counter. */ 143 154 uint32_t volatile cRefs; 155 156 /** Set if this is an in-memory rather than on-disk instance. */ 157 bool fIsInMem; 158 bool afAlignment[7]; 144 159 145 160 /** @name Result. … … 151 166 /** The file offset of the string table. */ 152 167 uint32_t offStrTab; 168 /** The link address of the string table. */ 169 uintptr_t uStrTabLinkAddr; 153 170 /** Pointer to the symbol table. */ 154 171 MY_NLIST *paSyms; … … 157 174 /** The file offset of the symbol table. */ 158 175 uint32_t offSyms; 176 /** The link address of the symbol table. */ 177 uintptr_t uSymTabLinkAddr; 178 /** The link address of the text segment. */ 179 uintptr_t uTextSegLinkAddr; 180 /** Size of the text segment. */ 181 uintptr_t cbTextSeg; 159 182 /** Offset between link address and actual load address. */ 160 183 uintptr_t offLoad; 184 /** The minimum OS version (A.B.C; A is 16 bits, B & C each 8 bits). */ 185 uint32_t uMinOsVer; 186 /** The SDK version (A.B.C; A is 16 bits, B & C each 8 bits). */ 187 uint32_t uSdkVer; 188 /** The source version (A.B.C.D.E; A is 24 bits, the rest 10 each). */ 189 uint64_t uSrcVer; 161 190 /** @} */ 162 191 … … 175 204 /** The load commands. */ 176 205 load_command_t *pLoadCmds; 206 /** The number of segments. */ 207 uint32_t cSegments; 208 /** The number of sections. */ 209 uint32_t cSections; 210 /** Section pointer table (points into the load commands). */ 211 MY_SEGMENT_COMMAND const *apSegments[MACHO_MAX_SECT / 2]; 177 212 /** Section pointer table (points into the load commands). */ 178 213 MY_SECTION const *apSections[MACHO_MAX_SECT]; 179 /** The number of sections. */180 uint32_t cSections;181 214 /** @} */ 182 215 … … 201 234 static void rtR0DbgKrnlDarwinLoadDone(RTDBGKRNLINFOINT *pThis) 202 235 { 203 RTFileClose(pThis->hFile); 236 if (!pThis->fIsInMem) 237 RTFileClose(pThis->hFile); 204 238 pThis->hFile = NIL_RTFILE; 205 239 206 RTMemFree(pThis->pLoadCmds); 240 if (!pThis->fIsInMem) 241 RTMemFree(pThis->pLoadCmds); 207 242 pThis->pLoadCmds = NULL; 208 memset((void *)&pThis->apSections[0], 0, sizeof(pThis->apSections[0]) * MACHO_MAX_SECT); 243 RT_ZERO(pThis->apSections); 244 RT_ZERO(pThis->apSegments); 209 245 } 210 246 … … 259 295 * @returns IPRT status code. 260 296 * @param pThis The internal scratch data. 261 */ 262 static int rtR0DbgKrnlDarwinCheckStandardSymbols(RTDBGKRNLINFOINT *pThis) 297 * @param pszKernelFile The name of the kernel file. 298 */ 299 static int rtR0DbgKrnlDarwinCheckStandardSymbols(RTDBGKRNLINFOINT *pThis, const char *pszKernelFile) 263 300 { 264 301 static struct … … 388 425 #endif 389 426 { 390 AssertLogRelMsgFailed(("%s (%p != %p)\n", s_aStandardCandles[i].pszName, uAddr, s_aStandardCandles[i].uAddr)); 427 #if defined(IN_RING0) && defined(DEBUG_bird) 428 kprintf("RTR0DbgKrnlInfoOpen: error: %s (%p != %p) in %s\n", 429 s_aStandardCandles[i].pszName, (void *)uAddr, (void *)s_aStandardCandles[i].uAddr, pszKernelFile); 430 #endif 431 printf("RTR0DbgKrnlInfoOpen: error: %s (%p != %p) in %s\n", 432 s_aStandardCandles[i].pszName, (void *)uAddr, (void *)s_aStandardCandles[i].uAddr, pszKernelFile); 391 433 return VERR_INTERNAL_ERROR_2; 392 434 } … … 403 445 * @param pszKernelFile The name of the kernel file. 404 446 */ 405 static int rtR0DbgKrnlDarwinLoadSymTab(RTDBGKRNLINFOINT *pThis, const char *pszKernelFile) 406 { 407 /* 408 * Load the tables. 409 */ 410 pThis->paSyms = (MY_NLIST *)RTMemAllocZ(pThis->cSyms * sizeof(MY_NLIST)); 411 if (!pThis->paSyms) 412 return VERR_NO_MEMORY; 413 414 int rc = RTFileReadAt(pThis->hFile, pThis->offArch + pThis->offSyms, 415 pThis->paSyms, pThis->cSyms * sizeof(MY_NLIST), NULL); 416 if (RT_FAILURE(rc)) 417 return rc; 418 419 pThis->pachStrTab = (char *)RTMemAllocZ(pThis->cbStrTab + 1); 420 if (!pThis->pachStrTab) 421 return VERR_NO_MEMORY; 422 423 rc = RTFileReadAt(pThis->hFile, pThis->offArch + pThis->offStrTab, 424 pThis->pachStrTab, pThis->cbStrTab, NULL); 425 if (RT_FAILURE(rc)) 426 return rc; 427 447 static int rtR0DbgKrnlDarwinParseSymTab(RTDBGKRNLINFOINT *pThis, const char *pszKernelFile) 448 { 428 449 /* 429 450 * The first string table symbol must be a zero length name. … … 442 463 if ((uint32_t)pSym->n_un.n_strx >= pThis->cbStrTab) 443 464 { 444 printf("RTR0DbgKrnlInfoOpen: %s: Symbol #%u has a bad string table index: %#x vs cbStrTab=%#x\n",445 pszKernelFile, iSym, pSym->n_un.n_strx, pThis->cbStrTab);465 LOG_BAD_SYM("RTR0DbgKrnlInfoOpen: %s: Symbol #%u has a bad string table index: %#x vs cbStrTab=%#x\n", 466 pszKernelFile, iSym, pSym->n_un.n_strx, pThis->cbStrTab); 446 467 RETURN_VERR_BAD_EXE_FORMAT; 447 468 } … … 461 482 if (pSym->n_sect == MACHO_NO_SECT) 462 483 { 463 printf("RTR0DbgKrnlInfoOpen: %s: Symbol #%u '%s' problem: n_sect = MACHO_NO_SECT\n",464 pszKernelFile, iSym, pszSym);484 LOG_BAD_SYM("RTR0DbgKrnlInfoOpen: %s: Symbol #%u '%s' problem: n_sect = MACHO_NO_SECT\n", 485 pszKernelFile, iSym, pszSym); 465 486 RETURN_VERR_BAD_EXE_FORMAT; 466 487 } 467 488 if (pSym->n_sect > pThis->cSections) 468 489 { 469 printf("RTR0DbgKrnlInfoOpen: %s: Symbol #%u '%s' problem: n_sect (%u) is higher than cSections (%u)\n",470 pszKernelFile, iSym, pszSym, pSym->n_sect, pThis->cSections);490 LOG_BAD_SYM("RTR0DbgKrnlInfoOpen: %s: Symbol #%u '%s' problem: n_sect (%u) is higher than cSections (%u)\n", 491 pszKernelFile, iSym, pszSym, pSym->n_sect, pThis->cSections); 471 492 RETURN_VERR_BAD_EXE_FORMAT; 472 493 } 473 494 if (pSym->n_desc & ~(REFERENCED_DYNAMICALLY | N_WEAK_DEF)) 474 495 { 475 printf("RTR0DbgKrnlInfoOpen: %s: Symbol #%u '%s' problem: Unexpected value n_desc=%#x\n",476 pszKernelFile, iSym, pszSym, pSym->n_desc);496 LOG_BAD_SYM("RTR0DbgKrnlInfoOpen: %s: Symbol #%u '%s' problem: Unexpected value n_desc=%#x\n", 497 pszKernelFile, iSym, pszSym, pSym->n_desc); 477 498 RETURN_VERR_BAD_EXE_FORMAT; 478 499 } … … 480 501 && strcmp(pszSym, "__mh_execute_header")) /* in 10.8 it's no longer absolute (PIE?). */ 481 502 { 482 printf("RTR0DbgKrnlInfoOpen: %s: Symbol #%u '%s' problem: n_value (%#llx) < section addr (%#llx)\n",483 pszKernelFile, iSym, pszSym, pSym->n_value, pThis->apSections[pSym->n_sect - 1]->addr);503 LOG_BAD_SYM("RTR0DbgKrnlInfoOpen: %s: Symbol #%u '%s' problem: n_value (%#llx) < section addr (%#llx)\n", 504 pszKernelFile, iSym, pszSym, pSym->n_value, pThis->apSections[pSym->n_sect - 1]->addr); 484 505 RETURN_VERR_BAD_EXE_FORMAT; 485 506 } … … 488 509 && strcmp(pszSym, "__mh_execute_header")) /* see above. */ 489 510 { 490 printf("RTR0DbgKrnlInfoOpen: %s: Symbol #%u '%s' problem: n_value (%#llx) >= end of section (%#llx + %#llx)\n",491 pszKernelFile, iSym, pszSym, pSym->n_value, pThis->apSections[pSym->n_sect - 1]->addr,492 pThis->apSections[pSym->n_sect - 1]->size);511 LOG_BAD_SYM("RTR0DbgKrnlInfoOpen: %s: Symbol #%u '%s' problem: n_value (%#llx) >= end of section (%#llx + %#llx)\n", 512 pszKernelFile, iSym, pszSym, pSym->n_value, pThis->apSections[pSym->n_sect - 1]->addr, 513 pThis->apSections[pSym->n_sect - 1]->size); 493 514 RETURN_VERR_BAD_EXE_FORMAT; 494 515 } … … 500 521 || pSym->n_sect > pThis->cSections) ) 501 522 { 502 printf("RTR0DbgKrnlInfoOpen: %s: Abs symbol #%u '%s' problem: n_sect (%u) is not MACHO_NO_SECT (cSections is %u)\n",503 pszKernelFile, iSym, pszSym, pSym->n_sect, pThis->cSections);523 LOG_BAD_SYM("RTR0DbgKrnlInfoOpen: %s: Abs symbol #%u '%s' problem: n_sect (%u) is not MACHO_NO_SECT (cSections is %u)\n", 524 pszKernelFile, iSym, pszSym, pSym->n_sect, pThis->cSections); 504 525 RETURN_VERR_BAD_EXE_FORMAT; 505 526 } 506 527 if (pSym->n_desc & ~(REFERENCED_DYNAMICALLY | N_WEAK_DEF)) 507 528 { 508 printf("RTR0DbgKrnlInfoOpen: %s: Abs symbol #%u '%s' problem: Unexpected value n_desc=%#x\n",509 pszKernelFile, iSym, pszSym, pSym->n_desc);529 LOG_BAD_SYM("RTR0DbgKrnlInfoOpen: %s: Abs symbol #%u '%s' problem: Unexpected value n_desc=%#x\n", 530 pszKernelFile, iSym, pszSym, pSym->n_desc); 510 531 RETURN_VERR_BAD_EXE_FORMAT; 511 532 } … … 514 535 case MACHO_N_UNDF: 515 536 /* No undefined or common symbols in the kernel. */ 516 printf("RTR0DbgKrnlInfoOpen: %s: Unexpected undefined symbol #%u '%s'\n", pszKernelFile, iSym, pszSym);537 LOG_BAD_SYM("RTR0DbgKrnlInfoOpen: %s: Unexpected undefined symbol #%u '%s'\n", pszKernelFile, iSym, pszSym); 517 538 RETURN_VERR_BAD_EXE_FORMAT; 518 539 519 540 case MACHO_N_INDR: 520 541 /* No indirect symbols in the kernel. */ 521 printf("RTR0DbgKrnlInfoOpen: %s: Unexpected indirect symbol #%u '%s'\n", pszKernelFile, iSym, pszSym);542 LOG_BAD_SYM("RTR0DbgKrnlInfoOpen: %s: Unexpected indirect symbol #%u '%s'\n", pszKernelFile, iSym, pszSym); 522 543 RETURN_VERR_BAD_EXE_FORMAT; 523 544 524 545 case MACHO_N_PBUD: 525 546 /* No prebound symbols in the kernel. */ 526 printf("RTR0DbgKrnlInfoOpen: %s: Unexpected prebound symbol #%u '%s'\n", pszKernelFile, iSym, pszSym);547 LOG_BAD_SYM("RTR0DbgKrnlInfoOpen: %s: Unexpected prebound symbol #%u '%s'\n", pszKernelFile, iSym, pszSym); 527 548 RETURN_VERR_BAD_EXE_FORMAT; 528 549 529 550 default: 530 printf("RTR0DbgKrnlInfoOpen: %s: Unexpected symbol n_type %#x for symbol #%u '%s'\n",531 pszKernelFile, pSym->n_type, iSym, pszSym);551 LOG_BAD_SYM("RTR0DbgKrnlInfoOpen: %s: Unexpected symbol n_type %#x for symbol #%u '%s'\n", 552 pszKernelFile, pSym->n_type, iSym, pszSym); 532 553 RETURN_VERR_BAD_EXE_FORMAT; 533 554 } … … 541 562 542 563 /** 543 * Loads the load commands and validates them. 564 * Uses the segment table to translate a file offset into a virtual memory 565 * address. 566 * 567 * @returns The virtual memory address on success, 0 if not found. 568 * @param pThis The instance. 569 * @param offFile The file offset to translate. 570 */ 571 static uintptr_t rtR0DbgKrnlDarwinFileOffToVirtAddr(RTDBGKRNLINFOINT *pThis, uint64_t offFile) 572 { 573 uint32_t iSeg = pThis->cSegments; 574 while (iSeg-- > 0) 575 { 576 uint64_t offSeg = offFile - pThis->apSegments[iSeg]->fileoff; 577 if (offSeg < pThis->apSegments[iSeg]->vmsize) 578 return pThis->apSegments[iSeg]->vmaddr + (uintptr_t)offSeg; 579 } 580 return 0; 581 } 582 583 584 /** 585 * Parses and validates the load commands. 544 586 * 545 587 * @returns IPRT status code. 546 588 * @param pThis The internal scratch data. 547 589 */ 548 static int rtR0DbgKrnlDarwinLoadCommands(RTDBGKRNLINFOINT *pThis) 549 { 550 pThis->offStrTab = 0; 551 pThis->cbStrTab = 0; 552 pThis->offSyms = 0; 553 pThis->cSyms = 0; 554 pThis->cSections = 0; 555 556 pThis->pLoadCmds = (load_command_t *)RTMemAlloc(pThis->cbLoadCmds); 557 if (!pThis->pLoadCmds) 558 return VERR_NO_MEMORY; 559 560 int rc = RTFileReadAt(pThis->hFile, pThis->offArch + sizeof(MY_MACHO_HEADER), 561 pThis->pLoadCmds, pThis->cbLoadCmds, NULL); 562 if (RT_FAILURE(rc)) 563 return rc; 590 static int rtR0DbgKrnlDarwinParseCommands(RTDBGKRNLINFOINT *pThis) 591 { 592 Assert(pThis->pLoadCmds); 593 594 /* 595 * Reset the state. 596 */ 597 pThis->offStrTab = 0; 598 pThis->cbStrTab = 0; 599 pThis->offSyms = 0; 600 pThis->cSyms = 0; 601 pThis->cSections = 0; 602 pThis->uTextSegLinkAddr = 0; 603 pThis->cbTextSeg = 0; 604 pThis->uMinOsVer = 0; 605 pThis->uSdkVer = 0; 606 pThis->uSrcVer = 0; 564 607 565 608 /* … … 700 743 701 744 /* Add to the section table. */ 702 if (pThis->cSections == MACHO_MAX_SECT)745 if (pThis->cSections >= RT_ELEMENTS(pThis->apSections)) 703 746 RETURN_VERR_BAD_EXE_FORMAT; 704 747 pThis->apSections[pThis->cSections++] = &paSects[i]; … … 710 753 && pSeg->vmsize != 0) 711 754 RETURN_VERR_BAD_EXE_FORMAT; 755 756 /* 757 * Add to the segment table. 758 */ 759 if (pThis->cSegments >= RT_ELEMENTS(pThis->apSegments)) 760 RETURN_VERR_BAD_EXE_FORMAT; 761 pThis->apSegments[pThis->cSegments++] = pSeg; 762 763 /* 764 * Take down the text segment size and link address (for in-mem variant): 765 */ 766 if (!strcmp(pSeg->segname, "__TEXT")) 767 { 768 if (pThis->cbTextSeg != 0) 769 RETURN_VERR_BAD_EXE_FORMAT; 770 pThis->uTextSegLinkAddr = pSeg->vmaddr; 771 pThis->cbTextSeg = pSeg->vmsize; 772 } 712 773 break; 713 774 } … … 725 786 case LC_MAIN: 726 787 case LC_DATA_IN_CODE: 727 case LC_SOURCE_VERSION:728 788 case LC_ENCRYPTION_INFO_64: 729 789 case LC_LINKER_OPTION: … … 732 792 case LC_VERSION_MIN_WATCHOS: 733 793 case LC_NOTE: 794 break; 795 734 796 case LC_BUILD_VERSION: 797 if (pCmd->cmdsize >= RT_UOFFSETOF(build_version_command_t, aTools)) 798 { 799 build_version_command_t *pBldVerCmd = (build_version_command_t *)pCmd; 800 pThis->uMinOsVer = pBldVerCmd->minos; 801 pThis->uSdkVer = pBldVerCmd->sdk; 802 } 803 break; 804 805 case LC_SOURCE_VERSION: 806 if (pCmd->cmdsize == sizeof(source_version_command_t)) 807 { 808 source_version_command_t *pSrcVerCmd = (source_version_command_t *)pCmd; 809 pThis->uSrcVer = pSrcVerCmd->version; 810 } 735 811 break; 736 812 … … 789 865 } 790 866 867 /* 868 * Try figure out the virtual addresses for the symbol and string tables. 869 */ 870 if (pThis->cbStrTab > 0) 871 pThis->uStrTabLinkAddr = rtR0DbgKrnlDarwinFileOffToVirtAddr(pThis, pThis->offStrTab); 872 if (pThis->cSyms > 0) 873 pThis->uSymTabLinkAddr = rtR0DbgKrnlDarwinFileOffToVirtAddr(pThis, pThis->offSyms); 874 791 875 return VINF_SUCCESS; 876 } 877 878 879 /** 880 * Loads and validates the symbol and string tables. 881 * 882 * @returns IPRT status code. 883 * @param pThis The internal scratch data. 884 * @param pszKernelFile The name of the kernel file. 885 */ 886 static int rtR0DbgKrnlDarwinLoadSymTab(RTDBGKRNLINFOINT *pThis, const char *pszKernelFile) 887 { 888 /* 889 * Load the tables. 890 */ 891 int rc; 892 pThis->paSyms = (MY_NLIST *)RTMemAllocZ(pThis->cSyms * sizeof(MY_NLIST)); 893 if (pThis->paSyms) 894 { 895 rc = RTFileReadAt(pThis->hFile, pThis->offArch + pThis->offSyms, pThis->paSyms, pThis->cSyms * sizeof(MY_NLIST), NULL); 896 if (RT_SUCCESS(rc)) 897 { 898 pThis->pachStrTab = (char *)RTMemAllocZ(pThis->cbStrTab + 1); 899 if (pThis->pachStrTab) 900 { 901 rc = RTFileReadAt(pThis->hFile, pThis->offArch + pThis->offStrTab, pThis->pachStrTab, pThis->cbStrTab, NULL); 902 if (RT_SUCCESS(rc)) 903 { 904 /* 905 * Join paths with the in-memory code path. 906 */ 907 rc = rtR0DbgKrnlDarwinParseSymTab(pThis, pszKernelFile); 908 } 909 } 910 else 911 rc = VERR_NO_MEMORY; 912 } 913 } 914 else 915 rc = VERR_NO_MEMORY; 916 return rc; 917 } 918 919 920 /** 921 * Loads the load commands and validates them. 922 * 923 * @returns IPRT status code. 924 * @param pThis The internal scratch data. 925 */ 926 static int rtR0DbgKrnlDarwinLoadCommands(RTDBGKRNLINFOINT *pThis) 927 { 928 int rc; 929 pThis->pLoadCmds = (load_command_t *)RTMemAlloc(pThis->cbLoadCmds); 930 if (pThis->pLoadCmds) 931 { 932 rc = RTFileReadAt(pThis->hFile, pThis->offArch + sizeof(MY_MACHO_HEADER), pThis->pLoadCmds, pThis->cbLoadCmds, NULL); 933 if (RT_SUCCESS(rc)) 934 rc = rtR0DbgKrnlDarwinParseCommands(pThis); 935 } 936 else 937 rc = VERR_NO_MEMORY; 938 return rc; 792 939 } 793 940 … … 907 1054 pThis->u32Magic = ~RTDBGKRNLINFO_MAGIC; 908 1055 909 RTMemFree(pThis->pachStrTab); 1056 if (!pThis->fIsInMem) 1057 RTMemFree(pThis->pachStrTab); 910 1058 pThis->pachStrTab = NULL; 911 1059 912 RTMemFree(pThis->paSyms); 1060 if (!pThis->fIsInMem) 1061 RTMemFree(pThis->paSyms); 913 1062 pThis->paSyms = NULL; 914 1063 915 1064 RTMemFree(pThis); 1065 } 1066 1067 1068 /** 1069 * Completes a handle, logging details. 1070 * 1071 * @returns VINF_SUCCESS 1072 * @param phKrnlInfo Where to return the handle. 1073 * @param pThis The instance to complete. 1074 * @param pszKernelFile What kernel file it's based on. 1075 */ 1076 static int rtR0DbgKrnlDarwinSuccess(PRTDBGKRNLINFO phKrnlInfo, RTDBGKRNLINFOINT *pThis, const char *pszKernelFile) 1077 { 1078 pThis->u32Magic = RTDBGKRNLINFO_MAGIC; 1079 pThis->cRefs = 1; 1080 1081 #if defined(DEBUG) || defined(IN_RING3) 1082 LOG_SUCCESS("RTR0DbgKrnlInfoOpen: Found: %#zx + %#zx - %s\n", pThis->uTextSegLinkAddr, pThis->offLoad, pszKernelFile); 1083 #else 1084 LOG_SUCCESS("RTR0DbgKrnlInfoOpen: Found: %s\n", pThis->uTextSegLinkAddr, pThis->offLoad, pszKernelFile); 1085 #endif 1086 LOG_SUCCESS("RTR0DbgKrnlInfoOpen: SDK version: %u.%u.%u MinOS version: %u.%u.%u Source version: %u.%u.%u.%u.%u\n", 1087 pThis->uSdkVer >> 16, (pThis->uSdkVer >> 8) & 0xff, pThis->uSdkVer & 0xff, 1088 pThis->uMinOsVer >> 16, (pThis->uMinOsVer >> 8) & 0xff, pThis->uMinOsVer & 0xff, 1089 (uint32_t)(pThis->uSrcVer >> 40), 1090 (uint32_t)(pThis->uSrcVer >> 30) & 0x3ff, 1091 (uint32_t)(pThis->uSrcVer >> 20) & 0x3ff, 1092 (uint32_t)(pThis->uSrcVer >> 10) & 0x3ff, 1093 (uint32_t)(pThis->uSrcVer) & 0x3ff); 1094 1095 *phKrnlInfo = pThis; 1096 return VINF_SUCCESS; 916 1097 } 917 1098 … … 941 1122 pThis->offLoad = (uintptr_t)&kernel_map - uLinkAddr; 942 1123 #endif 943 rc = rtR0DbgKrnlDarwinCheckStandardSymbols(pThis );1124 rc = rtR0DbgKrnlDarwinCheckStandardSymbols(pThis, pszKernelFile); 944 1125 } 945 1126 946 1127 rtR0DbgKrnlDarwinLoadDone(pThis); 947 1128 if (RT_SUCCESS(rc)) 948 { 949 pThis->u32Magic = RTDBGKRNLINFO_MAGIC; 950 pThis->cRefs = 1; 951 *phKrnlInfo = pThis; 952 } 1129 rtR0DbgKrnlDarwinSuccess(phKrnlInfo, pThis, pszKernelFile); 953 1130 else 954 1131 rtR0DbgKrnlDarwinDtor(pThis); … … 957 1134 958 1135 1136 #ifdef IN_RING0 1137 1138 /** 1139 * Checks if a page is present. 1140 * @returns true if it is, false if it isn't. 1141 * @param uPageAddr The address of/in the page to check. 1142 */ 1143 static bool rtR0DbgKrnlDarwinIsPagePresent(uintptr_t uPageAddr) 1144 { 1145 /** @todo the dtrace code subjects the result to pmap_is_valid, but that 1146 * isn't exported, so we'll have to make to with != 0 here. */ 1147 return pmap_find_phys(kernel_pmap, uPageAddr) != 0; 1148 } 1149 1150 1151 /** 1152 * Used to check whether a memory range is present or not. 1153 * 1154 * This is applied to the to the load commands and selected portions of the link 1155 * edit segment. 1156 * 1157 * @returns true if all present, false if not. 1158 * @param uAddress The start address. 1159 * @param cb Number of bytes to check. 1160 * @param pszWhat What we're checking, for logging. 1161 * @param pHdr The header address (for logging). 1162 */ 1163 static bool rtR0DbgKrnlDarwinIsRangePresent(uintptr_t uAddress, size_t cb, 1164 const char *pszWhat, MY_MACHO_HEADER const volatile *pHdr) 1165 { 1166 uintptr_t const uStartAddress = uAddress; 1167 intptr_t cPages = RT_ALIGN_Z(cb + (uAddress & PAGE_OFFSET_MASK), PAGE_SIZE); 1168 for (;;) 1169 { 1170 if (!rtR0DbgKrnlDarwinIsPagePresent(uAddress)) 1171 { 1172 LOG_NOT_PRESENT("RTR0DbgInfo: %p: Page in %s is not present: %#zx - rva %#zx; in structure %#zx (%#zx LB %#zx)\n", 1173 pHdr, pszWhat, uAddress, uAddress - (uintptr_t)pHdr, uAddress - uStartAddress, uStartAddress, cb); 1174 return false; 1175 } 1176 1177 cPages -= 1; 1178 if (cPages <= 0) 1179 uAddress += PAGE_SIZE; 1180 else 1181 return true; 1182 } 1183 } 1184 1185 1186 /** 1187 * Try "open" the in-memory kernel image 1188 * 1189 * @returns IPRT stauts code 1190 * @param phKrnlInfo Where to return the info instance on success. 1191 */ 1192 static int rtR0DbgKrnlDarwinOpenInMemory(PRTDBGKRNLINFO phKrnlInfo) 1193 { 1194 RTDBGKRNLINFOINT *pThis = (RTDBGKRNLINFOINT *)RTMemAllocZ(sizeof(*pThis)); 1195 if (!pThis) 1196 return VERR_NO_MEMORY; 1197 pThis->hFile = NIL_RTFILE; 1198 pThis->fIsInMem = true; 1199 1200 /* 1201 * Figure the search range based on a symbol that is supposed to be in 1202 * kernel text segment, using it as the upper boundrary. The lower boundary 1203 * is determined by subtracting a max kernel size of 64MB (the largest kernel 1204 * file, kernel.kasan, is around 45MB, but the end of __TEXT is about 27 MB, 1205 * which means we should still have plenty of room for future growth with 64MB). 1206 */ 1207 uintptr_t const uSomeKernelAddr = (uintptr_t)&absolutetime_to_nanoseconds; 1208 uintptr_t const uLowestKernelAddr = uSomeKernelAddr - _64M; 1209 1210 /* 1211 * The kernel is probably aligned at some boundrary larger than a page size, 1212 * so to speed things up we start by assuming the alignment is page directory 1213 * sized. In case we're wrong and it's smaller, we decrease the alignment till 1214 * we've reach the page size. 1215 */ 1216 uintptr_t fPrevAlignMask = ~(uintptr_t)0; 1217 uintptr_t uCurAlign = _2M; /* ASSUMES the kernel is typically 2MB aligned. */ 1218 while (uCurAlign >= PAGE_SIZE) 1219 { 1220 /* 1221 * Search down from the symbol address looking for a mach-O header that 1222 * looks like it might belong to the kernel. 1223 */ 1224 for (uintptr_t uCur = uSomeKernelAddr & ~(uCurAlign - 1); uCur >= uLowestKernelAddr; uCur -= uCurAlign) 1225 { 1226 /* Skip pages we've checked in previous iterations and pages that aren't present: */ 1227 /** @todo This is a little bogus in case the header is paged out. */ 1228 if ( (uCur & fPrevAlignMask) 1229 && rtR0DbgKrnlDarwinIsPagePresent(uCur)) 1230 { 1231 /* 1232 * Look for valid mach-o header (we skip cpusubtype on purpose here). 1233 */ 1234 MY_MACHO_HEADER const volatile *pHdr = (MY_MACHO_HEADER const volatile *)uCur; 1235 if ( pHdr->magic == MY_MACHO_MAGIC 1236 && pHdr->filetype == MH_EXECUTE 1237 && pHdr->cputype == MY_CPU_TYPE) 1238 { 1239 /* More header validation: */ 1240 pThis->cLoadCmds = pHdr->ncmds; 1241 pThis->cbLoadCmds = pHdr->sizeofcmds; 1242 if (pHdr->ncmds < 4) 1243 LOG_MISMATCH("RTR0DbgInfo: %p: ncmds=%u is too small\n", pHdr, pThis->cLoadCmds); 1244 else if (pThis->cLoadCmds > 256) 1245 LOG_MISMATCH("RTR0DbgInfo: %p: ncmds=%u is too big\n", pHdr, pThis->cLoadCmds); 1246 else if (pThis->cbLoadCmds <= pThis->cLoadCmds * sizeof(load_command_t)) 1247 LOG_MISMATCH("RTR0DbgInfo: %p: sizeofcmds=%u is too small for ncmds=%u\n", 1248 pHdr, pThis->cbLoadCmds, pThis->cLoadCmds); 1249 else if (pThis->cbLoadCmds >= _1M) 1250 LOG_MISMATCH("RTR0DbgInfo: %p: sizeofcmds=%u is too big\n", pHdr, pThis->cbLoadCmds); 1251 else if (pHdr->flags & ~MH_VALID_FLAGS) 1252 LOG_MISMATCH("RTR0DbgInfo: %p: invalid flags=%#x\n", pHdr, pHdr->flags); 1253 /* 1254 * Check that we can safely read the load commands, then parse & validate them. 1255 */ 1256 else if (rtR0DbgKrnlDarwinIsRangePresent((uintptr_t)(pHdr + 1), pThis->cbLoadCmds, "load commands", pHdr)) 1257 { 1258 pThis->pLoadCmds = (load_command_t *)(pHdr + 1); 1259 int rc = rtR0DbgKrnlDarwinParseCommands(pThis); 1260 if (RT_SUCCESS(rc)) 1261 { 1262 /* Calculate the slide value. This is typically zero as the 1263 load commands has been relocated (the case with 10.14.0 at least). */ 1264 /** @todo ASSUMES that the __TEXT segment comes first and includes the 1265 * mach-o header and load commands and all that. */ 1266 pThis->offLoad = uCur - pThis->uTextSegLinkAddr; 1267 1268 /* Check that the kernel symbol is in the text segment: */ 1269 uintptr_t const offSomeKernAddr = uSomeKernelAddr - uCur; 1270 if (offSomeKernAddr >= pThis->cbTextSeg) 1271 LOG_MISMATCH("RTR0DbgInfo: %p: Our symbol at %zx (off %zx) isn't within the text segment (size %#zx)\n", 1272 pHdr, uSomeKernelAddr, offSomeKernAddr, pThis->cbTextSeg); 1273 /* 1274 * Parse the symbol+string tables. 1275 */ 1276 else if (pThis->uSymTabLinkAddr == 0) 1277 LOG_MISMATCH("RTR0DbgInfo: %p: No symbol table VA (off %#x L %#x)\n", 1278 pHdr, pThis->offSyms, pThis->cSyms); 1279 else if (pThis->uStrTabLinkAddr == 0) 1280 LOG_MISMATCH("RTR0DbgInfo: %p: No string table VA (off %#x LB %#x)\n", 1281 pHdr, pThis->offSyms, pThis->cbStrTab); 1282 else if ( rtR0DbgKrnlDarwinIsRangePresent(pThis->uStrTabLinkAddr + pThis->offLoad, 1283 pThis->cbStrTab, "string table", pHdr) 1284 && rtR0DbgKrnlDarwinIsRangePresent(pThis->uSymTabLinkAddr + pThis->offLoad, 1285 pThis->cSyms * sizeof(pThis->paSyms), 1286 "symbol table", pHdr)) 1287 { 1288 pThis->pachStrTab = (char *)pThis->uStrTabLinkAddr + pThis->offLoad; 1289 pThis->paSyms = (MY_NLIST *)pThis->uSymTabLinkAddr + pThis->offLoad; 1290 rc = rtR0DbgKrnlDarwinParseSymTab(pThis, "in-memory"); 1291 if (RT_SUCCESS(rc)) 1292 { 1293 /* 1294 * Finally check the standard candles. 1295 */ 1296 rc = rtR0DbgKrnlDarwinCheckStandardSymbols(pThis, "in-memory"); 1297 rtR0DbgKrnlDarwinLoadDone(pThis); 1298 if (RT_SUCCESS(rc)) 1299 return rtR0DbgKrnlDarwinSuccess(phKrnlInfo, pThis, "in-memory"); 1300 } 1301 } 1302 } 1303 1304 RT_ZERO(pThis->apSections); 1305 RT_ZERO(pThis->apSegments); 1306 pThis->pLoadCmds = NULL; 1307 } 1308 } 1309 } 1310 } 1311 1312 fPrevAlignMask = uCurAlign - 1; 1313 uCurAlign >>= 1; 1314 } 1315 1316 RTMemFree(pThis); 1317 return VERR_GENERAL_FAILURE; 1318 } 1319 1320 #endif /* IN_RING0 */ 1321 959 1322 RTR0DECL(int) RTR0DbgKrnlInfoOpen(PRTDBGKRNLINFO phKrnlInfo, uint32_t fFlags) 960 1323 { … … 962 1325 *phKrnlInfo = NIL_RTDBGKRNLINFO; 963 1326 AssertReturn(!fFlags, VERR_INVALID_PARAMETER); 1327 1328 #ifdef IN_RING0 1329 /* 1330 * Try see if we can use the kernel memory directly. This depends on not 1331 * having the __LINKEDIT segment jettisoned or swapped out. For older 1332 * kernels this is typically the case, unless kallsyms=1 is in boot-args. 1333 */ 1334 int rc = rtR0DbgKrnlDarwinOpenInMemory(phKrnlInfo); 1335 if (RT_SUCCESS(rc)) 1336 { 1337 Log(("RTR0DbgKrnlInfoOpen: Using in-memory kernel.\n")); 1338 return rc; 1339 } 1340 #else 1341 int rc = VERR_WRONG_ORDER; /* shut up stupid MSC */ 1342 #endif 964 1343 965 1344 /* … … 987 1366 { "/mach_kernel", VERR_WRONG_ORDER }, 988 1367 }; 989 int rc = VERR_WRONG_ORDER; /* shut up stupid MSC */990 1368 for (uint32_t i = 0; i < RT_ELEMENTS(aKernels); i++) 991 1369 {
Note:
See TracChangeset
for help on using the changeset viewer.