/** * Adds a file or directory. * * @returns Program exit code. * @param pszPath The user supplied path to the file or directory. * @param pszCache The path to the cache. * @param fRecursive Whether to process directories recursively. * @param fOverwriteOnConflict Whether to overwrite existing cache entry on * conflict, or just leave it. */ static RTEXITCODE rtDbgSymCacheAddFileOrDir(const char *pszPath, const char *pszCache, bool fRecursive, bool fOverwriteOnConflict) { RT_NOREF1(fOverwriteOnConflict); RTDBGSYMCACHEADDCFG Cfg; Cfg.fRecursive = fRecursive; Cfg.pszCache = pszCache; Cfg.pszFilter = NULL; int rc; RTDBGSYMCACHEFILETYPE enmType = rtDbgSymCacheFigureType(pszPath); switch (enmType) { default: case RTDBGSYMCACHEFILETYPE_INVALID: return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid: '%s'", pszPath); case RTDBGSYMCACHEFILETYPE_DIR_FILTER: Cfg.pszFilter = RTPathFilename(pszPath); /* fall thru */ case RTDBGSYMCACHEFILETYPE_DIR: rc = rtDbgSymCacheAddDir(pszPath, &Cfg); break; case RTDBGSYMCACHEFILETYPE_DEBUG_FILE: rc = rtDbgSymCacheAddDebugFile(pszPath, &Cfg); break; case RTDBGSYMCACHEFILETYPE_IMAGE_FILE: rc = rtDbgSymCacheAddImageFile(pszPath, NULL /*pszExtraSuff*/, RTDBG_CACHE_UUID_MAP_DIR_IMAGES, &Cfg); break; case RTDBGSYMCACHEFILETYPE_DEBUG_BUNDLE: case RTDBGSYMCACHEFILETYPE_IMAGE_BUNDLE: { size_t cchPath = strlen(pszPath); size_t cchFilename = strlen(RTPathFilename(pszPath)); char szPathBuf[RTPATH_MAX]; if (cchPath < sizeof(szPathBuf)) { memcpy(szPathBuf, pszPath, cchPath + 1); if (enmType == RTDBGSYMCACHEFILETYPE_DEBUG_BUNDLE) rc = rtDbgSymCacheAddDebugBundle(szPathBuf, cchPath - cchFilename, cchFilename, &Cfg); else { RTDIRENTRYEX DirEntry; rc = rtDbgSymCacheAddImageBundle(szPathBuf, cchPath - cchFilename, cchFilename, &DirEntry, &Cfg); } } else rc = RTMsgErrorRc(VERR_FILENAME_TOO_LONG, "Filename too long: '%s'", pszPath); break; } case RTDBGSYMCACHEFILETYPE_IGNORE: rc = RTMsgErrorRc(VERR_INVALID_PARAMETER, "Invalid file: '%s'", pszPath); break; } return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; }
/** * Adds a image bundle of some sort. * * @returns IPRT status code. * @param pszPath Path to the bundle. This a RTPATH_MAX size * buffer that we can write to when creating the * path to the file inside the bundle that we're * interested in. * @param cchPath The length of the path up to the bundle name. * @param cchName The length of the bundle name. * @param pCfg The configuration. */ static int rtDbgSymCacheAddImageBundle(char *pszPath, size_t cchPath, size_t cchName, PCRTDBGSYMCACHEADDCFG pCfg) { /* Assuming these are kexts or simple applications, we only add the image file itself to the cache. No Info.plist or other files. */ /** @todo consider looking for Frameworks and handling framework bundles. */ int rc = rtDbgSymCacheConstructBundlePath(pszPath, cchPath, cchName, "Contents/MacOS/", g_apszBundleSuffixes); if (RT_SUCCESS(rc)) rc = rtDbgSymCacheAddImageFile(pszPath, NULL, "image-uuids", pCfg); return rc; }
/** * Adds a image bundle of some sort. * * @returns IPRT status code. * @param pszPath Path to the bundle. This a RTPATH_MAX size * buffer that we can write to when creating the * path to the file inside the bundle that we're * interested in. * @param cchPath The length of the path up to the bundle name. * @param cchName The length of the bundle name. * @param pDirEntry The directory entry buffer, for handling bundle * within bundle recursion. * @param pCfg The configuration. */ static int rtDbgSymCacheAddImageBundle(char *pszPath, size_t cchPath, size_t cchName, PRTDIRENTRYEX pDirEntry, PCRTDBGSYMCACHEADDCFG pCfg) { /* * Assuming these are kexts or simple applications, we only add the image * file itself to the cache. No Info.plist or other files. */ /** @todo consider looking for Frameworks and handling framework bundles. */ int rc = rtDbgSymCacheConstructBundlePath(pszPath, cchPath, cchName, "Contents/MacOS/", g_apszBundleSuffixes); if (RT_SUCCESS(rc)) rc = rtDbgSymCacheAddImageFile(pszPath, NULL, RTDBG_CACHE_UUID_MAP_DIR_IMAGES, pCfg); /* * Look for plugins and other sub-bundles. */ if (pCfg->fRecursive) { static char const * const s_apszSubBundleDirs[] = { "Contents/Plugins/", /** @todo Frameworks ++ */ }; for (uint32_t i = 0; i < RT_ELEMENTS(s_apszSubBundleDirs); i++) { pszPath[cchPath + cchName] = '\0'; int rc2 = RTPathAppend(pszPath, RTPATH_MAX - 1, s_apszSubBundleDirs[i]); if (RT_SUCCESS(rc2)) { if (RTDirExists(pszPath)) { size_t cchPath2 = strlen(pszPath); if (!RTPATH_IS_SLASH(pszPath[cchPath2 - 1])) { pszPath[cchPath2++] = RTPATH_SLASH; pszPath[cchPath2] = '\0'; } rc2 = rtDbgSymCacheAddDirWorker(pszPath, cchPath2, pDirEntry, pCfg); } } else { pszPath[cchPath + cchName] = '\0'; RTMsgError("Error constructing bundle subdir path for '%s' + '%s': %Rrc", pszPath, s_apszSubBundleDirs[i], rc); } if (RT_FAILURE(rc2) && RT_SUCCESS(rc)) rc = rc2; } } return rc; }
/** * Adds a debug bundle. * * @returns IPRT status code. * @param pszPath Path to the bundle. This a RTPATH_MAX size * buffer that we can write to when creating the * path to the file inside the bundle that we're * interested in. * @param cchPath The length of the path up to the bundle name. * @param cchName The length of the bundle name. * @param pCfg The configuration. */ static int rtDbgSymCacheAddDebugBundle(char *pszPath, size_t cchPath, size_t cchName, PCRTDBGSYMCACHEADDCFG pCfg) { /* * The current policy is not to add the whole .dSYM (or .sym) bundle, but * rather just the dwarf image instide it. The <UUID>.plist and Info.plist * files generally doesn't contain much extra information that's really * necessary, I hope. At least this is what the uuidmap example in the * lldb hints at (it links to the dwarf file, not the .dSYM dir). * * To avoid confusion with a .dSYM bundle, as well as collision with the * image file, we use .dwarf suffix for the file. * * For details on the uuid map see rtDbgSymCacheAddImageFile as well as * http://lldb.llvm.org/symbols.html . * * ASSUMES bundles contains Mach-O DWARF files. */ int rc = rtDbgSymCacheConstructBundlePath(pszPath, cchPath, cchName, "Contents/Resources/DWARF/", g_apszDSymBundleSuffixes); if (RT_SUCCESS(rc)) rc = rtDbgSymCacheAddImageFile(pszPath, RTDBG_CACHE_DSYM_FILE_SUFFIX, RTDBG_CACHE_UUID_MAP_DIR_DSYMS, pCfg); return rc; }
/** * Recursive worker for rtDbgSymCacheAddDir, for minimal stack wasting. * * @returns IPRT status code (fully bitched). * @param pszPath Pointer to a RTPATH_MAX size buffer containing * the path to the current directory ending with a * slash. * @param cchPath The size of the current directory path. * @param pDirEntry Pointer to the RTDIRENTRYEX structure to use. * @param pCfg The configuration. */ static int rtDbgSymCacheAddDirWorker(char *pszPath, size_t cchPath, PRTDIRENTRYEX pDirEntry, PCRTDBGSYMCACHEADDCFG pCfg) { /* * Open the directory. */ PRTDIR pDir; int rc, rc2; if (pCfg->pszFilter) { rc = RTStrCopy(&pszPath[cchPath], RTPATH_MAX - cchPath, pCfg->pszFilter); if (RT_FAILURE(rc)) { pszPath[cchPath] = '\0'; return RTMsgErrorRc(rc, "Filename too long (%Rrc): '%s" RTPATH_SLASH_STR "%s'", rc, pszPath, pCfg->pszFilter); } rc = RTDirOpenFiltered(&pDir, pszPath, RTDIRFILTER_WINNT, 0 /*fFlags*/); } else rc = RTDirOpen(&pDir, pszPath); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "RTDirOpen%s failed on '%s': %Rrc", pCfg->pszFilter ? "Filtered" : "", pszPath, rc); /* * Enumerate the files. */ for (;;) { rc2 = RTDirReadEx(pDir, pDirEntry, NULL, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK); if (RT_FAILURE(rc2)) { pszPath[cchPath] = '\0'; if (rc2 != VERR_NO_MORE_FILES) { RTMsgError("RTDirReadEx failed in '%s': %Rrc\n", pszPath, rc2); rc = rc2; } break; } /* Skip dot and dot-dot. */ if (RTDirEntryExIsStdDotLink(pDirEntry)) continue; /* Construct a full path. */ rc = RTStrCopy(&pszPath[cchPath], RTPATH_MAX, pDirEntry->szName); if (RT_FAILURE(rc)) { pszPath[cchPath] = '\0'; RTMsgError("File name too long in '%s': '%s' (%Rrc)", pszPath, pDirEntry->szName, rc); break; } switch (rtDbgSymCacheFigureType2(pszPath, &pDirEntry->Info)) { case RTDBGSYMCACHEFILETYPE_DIR: if (!pCfg->fRecursive) RTMsgInfo("Skipping directory '%s'...", pszPath); else { if (cchPath + pDirEntry->cbName + 3 <= RTPATH_MAX) { pszPath[cchPath + pDirEntry->cbName] = RTPATH_SLASH; pszPath[cchPath + pDirEntry->cbName + 1] = '\0'; rc2 = rtDbgSymCacheAddDirWorker(pszPath, cchPath + pDirEntry->cbName + 1, pDirEntry, pCfg); } else { RTMsgError("File name too long in '%s': '%s' (%Rrc)", pszPath, pDirEntry->szName, rc); rc2 = VERR_FILENAME_TOO_LONG; } } break; case RTDBGSYMCACHEFILETYPE_DEBUG_FILE: rc2 = rtDbgSymCacheAddDebugFile(pszPath, pCfg); break; case RTDBGSYMCACHEFILETYPE_IMAGE_FILE: rc2 = rtDbgSymCacheAddImageFile(pszPath, NULL /*pszExtraSuff*/, RTDBG_CACHE_UUID_MAP_DIR_IMAGES, pCfg); break; case RTDBGSYMCACHEFILETYPE_DEBUG_BUNDLE: rc2 = rtDbgSymCacheAddDebugBundle(pszPath, cchPath, pDirEntry->cbName, pCfg); break; case RTDBGSYMCACHEFILETYPE_IMAGE_BUNDLE: rc2 = rtDbgSymCacheAddImageBundle(pszPath, cchPath, pDirEntry->cbName, pDirEntry, pCfg); break; case RTDBGSYMCACHEFILETYPE_DIR_FILTER: case RTDBGSYMCACHEFILETYPE_INVALID: rc2 = RTMsgErrorRc(VERR_INTERNAL_ERROR_2, "Invalid: '%s'", pszPath); break; case RTDBGSYMCACHEFILETYPE_IGNORE: rc2 = VINF_SUCCESS; break; } if (RT_FAILURE(rc2) && RT_SUCCESS(rc)) rc = rc2; } /* * Clean up. */ rc2 = RTDirClose(pDir); if (RT_FAILURE(rc2)) { RTMsgError("RTDirClose failed in '%s': %Rrc", pszPath, rc); rc = rc2; } return rc; }