coredumper-solaris.cpp revision c5911784959246642ca03f8a66aab8e35f2aa066
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync * IPRT Testcase - Core Dumper.
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync * Copyright (C) 2010 Oracle Corporation
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync * available from http://www.virtualbox.org. This file is free software;
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * The contents of this file may alternatively be used under the terms
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * of the Common Development and Distribution License Version 1.0
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution, in which case the provisions of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * CDDL are applicable instead of those of the GPL.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * You may elect to license modified versions of this file under the
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync * terms and conditions of either the GPL or the CDDL or both.
154e1d5579ca6c8bee571a8d1ced5d76a0234030vboxsync/*******************************************************************************
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync* Header Files *
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync*******************************************************************************/
40af749e457b7d704c869ea986a042f0d4b6e09avboxsync#endif /* RT_OS_SOLARIS */
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync/*******************************************************************************
cb13ee8e628d04a773894bf4f9e8047d74f2ee21vboxsync*******************************************************************************/
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsyncvolatile static uint64_t g_CoreDumpThread = NIL_RTTHREAD;
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsyncvolatile static bool g_fCoreDumpSignalSetup = false;
40af749e457b7d704c869ea986a042f0d4b6e09avboxsyncvolatile static bool g_fCoreDumpDeliberate = false;
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsyncvolatile static bool g_fCoreDumpInProgress = false;
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync/*******************************************************************************
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync* Defined Constants And Macros *
40af749e457b7d704c869ea986a042f0d4b6e09avboxsync*******************************************************************************/
40af749e457b7d704c869ea986a042f0d4b6e09avboxsync } while (0)
cb13ee8e628d04a773894bf4f9e8047d74f2ee21vboxsync * Wrapper function to write IPRT format style string to the syslog.
cb13ee8e628d04a773894bf4f9e8047d74f2ee21vboxsync * @param pszFormat Format string
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsyncstatic void rtCoreDumperSysLogWrapper(const char *pszFormat, ...)
cb13ee8e628d04a773894bf4f9e8047d74f2ee21vboxsync * Determines endianness of the system. Just for completeness.
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync * @return Will return false if system is little endian, true otherwise.
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync const int i = 1;
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync char *p = (char *)&i;
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync if (p[0] == 1)
cb13ee8e628d04a773894bf4f9e8047d74f2ee21vboxsync return false;
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync return true;
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync * Reads from a file making sure an interruption doesn't cause a failure.
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync * @param hFile Handle to the file to read.
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync * @param pv Where to store the read data.
88acfa6629a7976c0583c1712d2b5b22a87a5121vboxsync * @param cbToRead Size of data to read.
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync * @return VBox status code.
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsyncstatic int ReadFileNoIntr(RTFILE hFile, void *pv, size_t cbToRead)
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync rc = RTFileRead(hFile, pv, cbToRead, NULL /* Read all */);
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync * Writes to a file making sure an interruption doesn't cause a failure.
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync * @param hFile Handle to the file to write.
6cb96ab7d4ba4dab39ef47e8d7c3dcfbf7582959vboxsync * @param pv Pointer to what to write.
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync * @param cbToRead Size of data to write.
6cb96ab7d4ba4dab39ef47e8d7c3dcfbf7582959vboxsync * @return VBox status code.
6cb96ab7d4ba4dab39ef47e8d7c3dcfbf7582959vboxsyncstatic int WriteFileNoIntr(RTFILE hFile, const void *pcv, size_t cbToRead)
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync rc = RTFileWrite(hFile, pcv, cbToRead, NULL /* Write all */);
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync * Read from a given offet in the process' address space.
6cb96ab7d4ba4dab39ef47e8d7c3dcfbf7582959vboxsync * @param pVBoxProc Pointer to the VBox process.
6cb96ab7d4ba4dab39ef47e8d7c3dcfbf7582959vboxsync * @param pv Where to read the data into.
6cb96ab7d4ba4dab39ef47e8d7c3dcfbf7582959vboxsync * @param cb Size of the read buffer.
6cb96ab7d4ba4dab39ef47e8d7c3dcfbf7582959vboxsync * @param off Offset to read from.
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync * @return VINF_SUCCESS, if all the given bytes was read in, otherwise VERR_READ_ERROR.
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsyncstatic ssize_t ProcReadAddrSpace(PVBOXPROCESS pVBoxProc, RTFOFF off, void *pvBuf, size_t cbToRead)
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync int rc = RTFileReadAt(pVBoxProc->hAs, off, pvBuf, cbToRead, NULL);
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync * Determines if the current process' architecture is suitable for dumping core.
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync * @param pVBoxProc Pointer to the VBox process.
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * @return true if the architecture matches the current one.
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsyncstatic inline bool IsProcessArchNative(PVBOXPROCESS pVBoxProc)
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync return pVBoxProc->ProcInfo.pr_dmodel == PR_MODEL_NATIVE;
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync * Helper function to get the size of a file given it's path.
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync * @param pszPath Pointer to the full path of the file.
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync * @return The size of the file in bytes.
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync int rc = RTFileOpen(&hFile, pszPath, RTFILE_O_OPEN | RTFILE_O_READ);
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync CORELOGRELSYS((CORELOG_NAME "GetFileSize failed to open %s rc=%Rrc\n", pszPath, rc));
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync * Pre-compute and pre-allocate sufficient memory for dumping core.
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync * This is meant to be called once, as a single-large anonymously
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync * mapped memory area which will be used during the core dumping routines.
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync * @param pVBoxCore Pointer to the core object.
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync * @return VBox status code.
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync AssertReturn(pVBoxCore->pvCore == NULL, VERR_ALREADY_EXISTS);
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync AssertReturn(pVBoxCore->VBoxProc.Process != NIL_RTPROCESS, VERR_PROCESS_NOT_FOUND);
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync size_t cbAccounting; /* Size of each accounting entry per entry */
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync { "/proc/%d/map", 0, sizeof(prmap_t), sizeof(VBOXSOLMAPINFO) },
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync { "/proc/%d/auxv", 0, 0, 0 },
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync { "/proc/%d/lpsinfo", sizeof(prheader_t), sizeof(lwpsinfo_t), sizeof(VBOXSOLTHREADINFO) },
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync { "/proc/%d/lstatus", 0, 0, 0 },
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync { "/proc/%d/ldt", 0, 0, 0 },
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync { "/proc/%d/cred", sizeof(prcred_t), sizeof(gid_t), 1 },
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync { "/proc/%d/priv", sizeof(prpriv_t), sizeof(priv_chunk_t), 1 },
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync for (int i = 0; i < (int)RT_ELEMENTS(aPreAllocTable); i++)
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync RTStrPrintf(szPath, sizeof(szPath), aPreAllocTable[i].pszFilePath, (int)pVBoxCore->VBoxProc.Process);
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync cb += ((cbFile - aPreAllocTable[i].cbHeader) / aPreAllocTable[i].cbEntry) * aPreAllocTable[i].cbAccounting;
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync * Make room for our own mapping accountant entry which will also be included in the core.
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync * Allocate the required space, plus some extra room.
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync void *pv = mmap(NULL, cb, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1 /* fd */, 0 /* offset */);
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync CORELOG((CORELOG_NAME "AllocMemoryArea: memory area of %u bytes allocated.\n", cb));
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync CORELOGRELSYS((CORELOG_NAME "AllocMemoryArea: failed cb=%u\n", cb));
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync * Free memory area used by the core object.
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync * @param pVBoxCore Pointer to the core object.
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync CORELOG((CORELOG_NAME "FreeMemoryArea: memory area of %u bytes freed.\n", pVBoxCore->cbCore));
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync * Get a chunk from the area of allocated memory.
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync * @param pVBoxCore Pointer to the core object.
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync * @param cb Size of requested chunk.
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsync * @return Pointer to allocated memory, or NULL on failure.
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsyncstatic void *GetMemoryChunk(PVBOXCORE pVBoxCore, size_t cb)
return pb;
return NULL;
static int ProcReadFileInto(PVBOXCORE pVBoxCore, const char *pszProcFileName, void **ppv, size_t *pcb)
RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/%s", (int)pVBoxCore->VBoxProc.Process, pszProcFileName);
if (*pcb > 0)
if (*ppv)
*pcb = 0;
return rc;
return rc;
return rc;
return rc;
return VERR_INVALID_STATE;
return rc;
return rc;
CORELOG((CORELOG_NAME "ProcReadAuxVecs: cbAuxFile=%u auxv_t size %d cAuxVecs=%u\n", cbAuxFile, sizeof(auxv_t), pVBoxProc->cAuxVecs));
return VINF_SUCCESS;
CORELOGRELSYS((CORELOG_NAME "ProcReadAuxVecs: ReadFileNoIntr failed. rc=%Rrc cbAuxFile=%u\n", rc, cbAuxFile));
CORELOGRELSYS((CORELOG_NAME "ProcReadAuxVecs: no memory for %u bytes\n", cbAuxFile + sizeof(auxv_t)));
CORELOGRELSYS((CORELOG_NAME "ProcReadAuxVecs: aux file too small %u, expecting %u or more\n", cbAuxFile, sizeof(auxv_t)));
return rc;
return rc;
if (pMap)
pVBoxProc->pMapInfoHead = (PVBOXSOLMAPINFO)GetMemoryChunk(pVBoxCore, pVBoxProc->cMappings * sizeof(VBOXSOLMAPINFO));
if (pPrev)
uint64_t k = 0;
CORELOGRELSYS((CORELOG_NAME "ProcReadMappings: skipping mapping. vaddr=%#x rc=%Rrc\n", pCur->pMap.pr_vaddr, rc2));
k += cb;
if (pPrev)
CORELOG((CORELOG_NAME "ProcReadMappings: successfully read in %u mappings\n", pVBoxProc->cMappings));
return VINF_SUCCESS;
CORELOGRELSYS((CORELOG_NAME "ProcReadMappings: GetMemoryChunk failed %u\n", pVBoxProc->cMappings * sizeof(VBOXSOLMAPINFO)));
CORELOGRELSYS((CORELOG_NAME "ProcReadMappings: FileReadNoIntr failed. rc=%Rrc cbMapFile=%u\n", rc, cbMapFile));
return rc;
CORELOG((CORELOG_NAME "ProcReadThreads: read info(%u) status(%u), threads:cInfo=%u cStatus=%u\n", cbInfoHdrAndData,
if ( cStatus == 0
CORELOGRELSYS((CORELOG_NAME "ProcReadThreads: cStatus = %u pStatuslwpid=%d infolwpid=%d\n", cStatus,
cStatus--;
memcpy(&pStatus->pr_fpreg, &pVBoxProc->pCurThreadCtx->uc_mcontext.fpregs, sizeof(pStatus->pr_fpreg));
CORELOG((CORELOG_NAME "ProcReadThreads: patched dumper thread context with pre-dump time context.\n"));
if (pPrev)
if (pPrev)
return VINF_SUCCESS;
CORELOGRELSYS((CORELOG_NAME "ProcReadThreads: GetMemoryChunk failed for %u bytes\n", cbThreadInfo));
CORELOGRELSYS((CORELOG_NAME "ProcReadThreads: huh!? cbStatusHdrAndData=%u prheader_t=%u entsize=%u\n", cbStatusHdrAndData,
CORELOGRELSYS((CORELOG_NAME "ProcReadThreads: huh!? cbInfoHdrAndData=%u entsize=%u\n", cbInfoHdrAndData, pStatusHdr->pr_entsize));
CORELOGRELSYS((CORELOG_NAME "ProcReadThreads: ReadFileNoIntr failed for \"lpsinfo\" rc=%Rrc\n", rc));
CORELOGRELSYS((CORELOG_NAME "ProcReadThreads: ReadFileNoIntr failed for \"lstatus\" rc=%Rrc\n", rc));
return rc;
#ifdef RT_OS_SOLARIS
return VERR_GENERAL_FAILURE;
return VERR_GENERAL_FAILURE;
rc = getzonenamebyid(pVBoxProc->ProcInfo.pr_zoneid, pVBoxProc->szZoneName, sizeof(pVBoxProc->szZoneName));
if (rc < 0)
CORELOGRELSYS((CORELOG_NAME "ProcReadMiscInfo: getzonenamebyid failed. rc=%d errno=%d zoneid=%d\n", rc, errno, pVBoxProc->ProcInfo.pr_zoneid));
return VERR_GENERAL_FAILURE;
return rc;
static void GetOldProcessStatus(PVBOXCORE pVBoxCore, lwpsinfo_t *pInfo, lwpstatus_t *pStatus, prstatus_t *pDst)
return rc;
CORELOG((CORELOG_NAME "SuspendThreads: Stopped %u threads successfully with %u tries\n", cThreads, cTries));
return rc;
#ifdef RT_OS_SOLARIS
return rc;
switch (enmType)
case enmOldEra:
while (pThreadInfo)
case enmNewEra:
while (pThreadInfo)
return cb;
#ifdef RT_OS_SOLARIS
typedef struct ELFWRITENOTE
const char *pszType;
const void *pcv;
} ELFWRITENOTE;
switch (enmType)
case enmOldEra:
CORELOGRELSYS((CORELOG_NAME "ElfWriteNoteSection: ElfWriteNoteHeader failed for %s. rc=%Rrc\n", aElfNotes[i].pszType, rc));
rc = ElfWriteNoteHeader(pVBoxCore, NT_PRFPREG, &pThreadInfo->pStatus->pr_fpreg, sizeof(prfpregset_t));
CORELOGRELSYS((CORELOG_NAME "ElfWriteSegment: ElfWriteNote failed for NT_PRSTATUS. rc=%Rrc\n", rc));
case enmNewEra:
{ "NT_PRPRIVINFO", NT_PRPRIVINFO, pVBoxProc->pcPrivImpl, PRIV_IMPL_INFO_SIZE(pVBoxProc->pcPrivImpl) },
CORELOGRELSYS((CORELOG_NAME "ElfWriteNoteSection: ElfWriteNoteHeader failed for %s. rc=%Rrc\n", aElfNotes[i].pszType, rc));
CORELOGRELSYS((CORELOG_NAME "ElfWriteNoteSection: ElfWriteNoteHeader for NT_LWPSINFO failed. rc=%Rrc\n", rc));
CORELOGRELSYS((CORELOG_NAME "ElfWriteNoteSection: ElfWriteNoteHeader for NT_LWPSTATUS failed. rc=%Rrc\n", rc));
return rc;
while (pMapInfo)
uint64_t k = 0;
CORELOGRELSYS((CORELOG_NAME "ElfWriteMappings: Failed to read mapping, can't recover. Bye. rc=%Rrc\n", rc));
return VERR_INVALID_STATE;
return rc;
k += cb;
return rc;
return VINF_SUCCESS;
while (pMapInfo)
ProgHdr.p_vaddr = pMapInfo->pMap.pr_vaddr; /* Virtual address of this mapping in the process address space */
return rc;
return rc;
return VERR_INVALID_STATE;
if (pfnWriter)
goto WriteCoreDone;
rc = RTFileOpen(&pVBoxCore->hCoreFile, pVBoxCore->szCorePath, RTFILE_O_OPEN_CREATE | RTFILE_O_TRUNCATE | RTFILE_O_READWRITE | RTFILE_O_DENY_ALL);
goto WriteCoreDone;
#ifdef RT_ARCH_AMD64
goto WriteCoreDone;
CORELOGRELSYS((CORELOG_NAME "WriteCore: pfnWriter failed writing old-style ELF program Header. rc=%Rrc\n", rc));
goto WriteCoreDone;
CORELOGRELSYS((CORELOG_NAME "WriteCore: pfnWriter failed writing new-style ELF program header. rc=%Rrc\n", rc));
goto WriteCoreDone;
goto WriteCoreDone;
goto WriteCoreDone;
goto WriteCoreDone;
goto WriteCoreDone;
return rc;
RTProcGetExecutableName(pVBoxProc->szExecPath, sizeof(pVBoxProc->szExecPath)); /* this gets full path not just name */
RTStrPrintf(pVBoxCore->szCorePath, sizeof(pVBoxCore->szCorePath), "%s/core.vb.%s", g_szCoreDumpDir, g_szCoreDumpFile);
CORELOG((CORELOG_NAME "CreateCore: Taking Core %s from Thread %d\n", pVBoxCore->szCorePath, (int)pVBoxProc->hCurThread));
* Read process status, information such as number of active LWPs will be invalid since we just quiesced the process.
struct COREACCUMULATOR
const char *pszName;
bool fOptional;
} aAccumulators[] =
return VINF_SUCCESS;
return rc;
return VERR_INVALID_STATE;
return VINF_SUCCESS;
if (!pContext)
return VERR_INVALID_POINTER;
CORELOGRELSYS((CORELOG_NAME "TakeDump: WriteCore failed. szCorePath=%s rc=%Rrc\n", VBoxCore.szCorePath, rc));
return rc;
bool fCallSystemDump = false;
fCallSystemDump = true;
fCallSystemDump = true;
CORELOGRELSYS((CORELOG_NAME "SignalHandler: Core dump already in progress! Waiting before signalling Sig=%d.\n", Sig));
if (iTimeout <= 0)
if (iTimeout <= 0)
fCallSystemDump = true;
CORELOGRELSYS((CORELOG_NAME "SignalHandler: Core dump seems to be stuck. Signalling new signal %d\n", Sig));
if (fCallSystemDump)
return VERR_WRONG_ORDER;
if (pszOutputFile)
return VINF_SUCCESS;
if (pszOutputDir)
return VINF_SUCCESS;
return VINF_SUCCESS;