coredumper-solaris.cpp revision 9a664a49177968632ad57f58a3e32700aa60d2b8
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * IPRT - Custom Core Dumper, Solaris.
9496b6f77d66eb89f088668752b8838d578d6e10vboxsync * Copyright (C) 2010-2011 Oracle Corporation
9496b6f77d66eb89f088668752b8838d578d6e10vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9496b6f77d66eb89f088668752b8838d578d6e10vboxsync * available from http://www.virtualbox.org. This file is free software;
9496b6f77d66eb89f088668752b8838d578d6e10vboxsync * you can redistribute it and/or modify it under the terms of the GNU
9496b6f77d66eb89f088668752b8838d578d6e10vboxsync * General Public License (GPL) as published by the Free Software
9496b6f77d66eb89f088668752b8838d578d6e10vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync * The contents of this file may alternatively be used under the terms
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync * of the Common Development and Distribution License Version 1.0
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync * VirtualBox OSE distribution, in which case the provisions of the
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync * CDDL are applicable instead of those of the GPL.
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync * You may elect to license modified versions of this file under the
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * terms and conditions of either the GPL or the CDDL or both.
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync/*******************************************************************************
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync* Header Files *
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync*******************************************************************************/
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsync#endif /* RT_OS_SOLARIS */
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync/*******************************************************************************
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsync*******************************************************************************/
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsyncstatic RTNATIVETHREAD volatile g_CoreDumpThread = NIL_RTNATIVETHREAD;
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsyncstatic bool volatile g_fCoreDumpSignalSetup = false;
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync/*******************************************************************************
0c8b774aca1168c2007424a49f6fa159fc23e42bvboxsync* Defined Constants And Macros *
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync*******************************************************************************/
53e1c27c7564c45ad0b92676ddea561591a3e869vboxsync } while (0)
b459362b1c9b5ce5e6bf4ceb32ffe1294c08be07vboxsync * ELFNOTEHDR: ELF NOTE header.
53e1c27c7564c45ad0b92676ddea561591a3e869vboxsynctypedef struct ELFNOTEHDR
0c8b774aca1168c2007424a49f6fa159fc23e42bvboxsync * Wrapper function to write IPRT format style string to the syslog.
0c8b774aca1168c2007424a49f6fa159fc23e42bvboxsync * @param pszFormat Format string
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsyncstatic void rtCoreDumperSysLogWrapper(const char *pszFormat, ...)
41e3b5da61b49017cb647f2f32a231c524fc370avboxsync * Determines endianness of the system. Just for completeness.
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync * @return Will return false if system is little endian, true otherwise.
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync const int i = 1;
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync char *p = (char *)&i;
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync if (p[0] == 1)
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync return false;
cfd41a3683178a30bac4417128b4673806653797vboxsync return true;
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync * Reads from a file making sure an interruption doesn't cause a failure.
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync * @param fd Handle to the file to read.
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync * @param pv Where to store the read data.
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync * @param cbToRead Size of data to read.
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync * @return IPRT status code.
613c0d015cbaef93be47fc03f0708744c5c24f79vboxsyncstatic int ReadFileNoIntr(int fd, void *pv, size_t cbToRead)
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync * Writes to a file making sure an interruption doesn't cause a failure.
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync * @param fd Handle to the file to write to.
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync * @param pv Pointer to what to write.
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync * @param cbToWrite Size of data to write.
9c59bcefe2993070fafaf0d6cee9673f48479128vboxsync * @return IPRT status code.
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsyncstatic int WriteFileNoIntr(int fd, const void *pv, size_t cbToWrite)
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync * Read from a given offset in the process' address space.
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync * @param pSolProc Pointer to the solaris process.
9c59bcefe2993070fafaf0d6cee9673f48479128vboxsync * @param pv Where to read the data into.
9c59bcefe2993070fafaf0d6cee9673f48479128vboxsync * @param cb Size of the read buffer.
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync * @param off Offset to read from.
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync * @return VINF_SUCCESS, if all the given bytes was read in, otherwise VERR_READ_ERROR.
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsyncstatic ssize_t ProcReadAddrSpace(PRTSOLCOREPROCESS pSolProc, RTFOFF off, void *pvBuf, size_t cbToRead)
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync ssize_t cbRead = pread(pSolProc->fdAs, pvBuf, cbToRead, off);
2c18e977ea3600677b8c58c9de0caa61792ba428vboxsync * Determines if the current process' architecture is suitable for dumping core.
2c18e977ea3600677b8c58c9de0caa61792ba428vboxsync * @param pSolProc Pointer to the solaris process.
2c18e977ea3600677b8c58c9de0caa61792ba428vboxsync * @return true if the architecture matches the current one.
01f38d7bedc71f105edc6e67f8cbb9a0bf325442vboxsyncstatic inline bool IsProcessArchNative(PRTSOLCOREPROCESS pSolProc)
01f38d7bedc71f105edc6e67f8cbb9a0bf325442vboxsync return pSolProc->ProcInfo.pr_dmodel == PR_MODEL_NATIVE;
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync * Helper function to get the size_t compatible file size from a file
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync * descriptor.
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync * @return The file size (in bytes).
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync * @param fd The file descriptor.
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync return (off_t)cbFile == st.st_size ? cbFile : ~(size_t)0;
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync CORELOGRELSYS((CORELOG_NAME "GetFileSizeByFd: fstat failed rc=%Rrc\n", RTErrConvertFromErrno(errno)));
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync * Helper function to get the size_t compatible size of a file given its path.
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync * @return The file size (in bytes).
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync * @param pszPath Pointer to the full path of the file.
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsyncstatic size_t GetFileSizeByName(const char *pszPath)
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync CORELOGRELSYS((CORELOG_NAME "GetFileSizeByName: failed to open %s rc=%Rrc\n", pszPath, RTErrConvertFromErrno(errno)));
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync * Pre-compute and pre-allocate sufficient memory for dumping core.
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync * This is meant to be called once, as a single-large anonymously
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync * mapped memory area which will be used during the core dumping routines.
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync * @param pSolCore Pointer to the core object.
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync * @return IPRT status code.
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync AssertReturn(pSolCore->pvCore == NULL, VERR_ALREADY_EXISTS);
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync static struct
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync size_t cbAccounting; /* Size of each accounting entry per entry */
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync { "/proc/%d/map", 0, sizeof(prmap_t), sizeof(RTSOLCOREMAPINFO) },
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync { "/proc/%d/auxv", 0, 0, 0 },
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync { "/proc/%d/lpsinfo", sizeof(prheader_t), sizeof(lwpsinfo_t), sizeof(RTSOLCORETHREADINFO) },
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync { "/proc/%d/lstatus", 0, 0, 0 },
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync { "/proc/%d/ldt", 0, 0, 0 },
9ced981a0263f6280ccbf5dc64c0e81fbe4a2fdavboxsync { "/proc/%d/cred", sizeof(prcred_t), sizeof(gid_t), 0 },
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync { "/proc/%d/priv", sizeof(prpriv_t), sizeof(priv_chunk_t), 0 },
1ace73711fa06807748eff26632c7273a1f7c2dbvboxsync for (unsigned i = 0; i < RT_ELEMENTS(s_aPreAllocTable); i++)
1ace73711fa06807748eff26632c7273a1f7c2dbvboxsync RTStrPrintf(szPath, sizeof(szPath), s_aPreAllocTable[i].pszFilePath, (int)pSolCore->SolProc.Process);
1ace73711fa06807748eff26632c7273a1f7c2dbvboxsync cb += ((cbFile - s_aPreAllocTable[i].cbHeader) / s_aPreAllocTable[i].cbEntry)
5f9ec43969b9ba00f6c2d03bafc9ac36a41c95e1vboxsync * (s_aPreAllocTable[i].cbAccounting > 0 ? s_aPreAllocTable[i].cbAccounting : 1);
5f9ec43969b9ba00f6c2d03bafc9ac36a41c95e1vboxsync * Make room for our own mapping accountant entry which will also be included in the core.
5f9ec43969b9ba00f6c2d03bafc9ac36a41c95e1vboxsync * Allocate the required space, plus some extra room.
e12a6ea07ddb7a02b3575e78b24960e13f42bf4cvboxsync void *pv = mmap(NULL, cb, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1 /* fd */, 0 /* offset */);
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync CORELOG((CORELOG_NAME "AllocMemoryArea: memory area of %u bytes allocated.\n", cb));
1d258b8772ee104b5fab3d1743eabc2f5cfe2fa4vboxsync CORELOGRELSYS((CORELOG_NAME "AllocMemoryArea: failed cb=%u\n", cb));
1d258b8772ee104b5fab3d1743eabc2f5cfe2fa4vboxsync * Free memory area used by the core object.
1d258b8772ee104b5fab3d1743eabc2f5cfe2fa4vboxsync * @param pSolCore Pointer to the core object.
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync CORELOG((CORELOG_NAME "FreeMemoryArea: memory area of %u bytes freed.\n", pSolCore->cbCore));
674c51d0cb8c72a2852b315b70f76d11d82b20f5vboxsync * Get a chunk from the area of allocated memory.
674c51d0cb8c72a2852b315b70f76d11d82b20f5vboxsync * @param pSolCore Pointer to the core object.
674c51d0cb8c72a2852b315b70f76d11d82b20f5vboxsync * @param cb Size of requested chunk.
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync * @return Pointer to allocated memory, or NULL on failure.
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsyncstatic void *GetMemoryChunk(PRTSOLCORE pSolCore, size_t cb)
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync size_t cbAllocated = (char *)pSolCore->pvFree - (char *)pSolCore->pvCore;
9a1578b66f9e563cf99c75ffa881db476f477e3avboxsync * Reads the proc file's content into a newly allocated buffer.
9b5e4e8f5c00e8cd2289a73d173c96e551c79397vboxsync * @param pSolCore Pointer to the core object.
69069b36d01e6c0e9965baca5fcb58d57a1030b6vboxsync * @param pszFileFmt Only the name of the file to read from (/proc/<pid> will be prepended)
9b5e4e8f5c00e8cd2289a73d173c96e551c79397vboxsync * @param ppv Where to store the allocated buffer.
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync * @param pcb Where to store size of the buffer.
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync * @return IPRT status code. If the proc file is 0 bytes, VINF_SUCCESS is
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync * returned with pointed to values of @c ppv, @c pcb set to NULL and 0
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync * respectively.
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsyncstatic int ProcReadFileInto(PRTSOLCORE pSolCore, const char *pszProcFileName, void **ppv, size_t *pcb)
d95b7fbc09277b5375b98812fa76b08c6ce8535cvboxsync RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/%s", (int)pSolCore->SolProc.Process, pszProcFileName);
*pcb = 0;
return rc;
if (fd >= 0)
return rc;
if (fd >= 0)
return rc;
return rc;
return VERR_INVALID_STATE;
return rc;
if (fd < 0)
return rc;
CORELOG((CORELOG_NAME "ProcReadAuxVecs: cbAuxFile=%u auxv_t size %d cAuxVecs=%u\n", cbAuxFile, sizeof(auxv_t),
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;
if (fdMap < 0)
return rc;
if (pMap)
if (pPrev)
uint64_t k = 0;
k += cb;
if (pPrev)
CORELOG((CORELOG_NAME "ProcReadMappings: successfully read in %u mappings\n", pSolProc->cMappings));
return VINF_SUCCESS;
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, &pSolProc->pCurThreadCtx->uc_mcontext.fpregs, sizeof(pStatus->pr_fpreg));
if (pPrev)
if (pPrev)
return VINF_SUCCESS;
CORELOGRELSYS((CORELOG_NAME "ProcReadThreads: GetMemoryChunk failed for %u bytes\n", cbThreadInfo));
CORELOGRELSYS((CORELOG_NAME "ProcReadThreads: Invalid state information for threads. rc=%Rrc\n", rc));
CORELOGRELSYS((CORELOG_NAME "ProcReadThreads: huh!? cbStatusHdrAndData=%u prheader_t=%u entsize=%u\n",
CORELOGRELSYS((CORELOG_NAME "ProcReadThreads: huh!? cbInfoHdrAndData=%u entsize=%u\n", cbInfoHdrAndData,
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(pSolProc->ProcInfo.pr_zoneid, pSolProc->szZoneName, sizeof(pSolProc->szZoneName));
if (rc < 0)
CORELOGRELSYS((CORELOG_NAME "ProcReadMiscInfo: getzonenamebyid failed. rc=%d errno=%d zoneid=%d\n", rc, errno,
return VERR_GENERAL_FAILURE;
return rc;
static void GetOldProcessStatus(PRTSOLCORE pSolCore, lwpsinfo_t *pInfo, lwpstatus_t *pStatus, prstatus_t *pDst)
return VINF_SUCCESS;
return VINF_SUCCESS;
static int rtCoreDumperForEachThread(PRTSOLCORE pSolCore, uint64_t *pcThreads, PFNRTSOLCORETHREADWORKER pfnWorker)
if (fd >= 0)
if (pcThreads)
return rc;
return rc;
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:
rc = ElfWriteNoteHeader(pSolCore, 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, pSolProc->pcPrivImpl, PRIV_IMPL_INFO_SIZE(pSolProc->pcPrivImpl) },
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;
#ifdef RT_ARCH_AMD64
return rc;
CORELOGRELSYS((CORELOG_NAME "WriteCore: pfnWriter failed writing old-style ELF program Header. rc=%Rrc\n", rc));
return rc;
CORELOGRELSYS((CORELOG_NAME "WriteCore: pfnWriter failed writing new-style ELF program header. rc=%Rrc\n", rc));
return rc;
return rc;
return rc;
return rc;
return rc;
return rc;
return VERR_INVALID_STATE;
if (pfnWriter)
int rc;
if (fd >= 0)
if (fd >= 0)
return rc;
static int rtCoreDumperCreateCore(PRTSOLCORE pSolCore, ucontext_t *pContext, const char *pszCoreFilePath)
RTProcGetExecutablePath(pSolProc->szExecPath, sizeof(pSolProc->szExecPath)); /* this gets full path not just name */
if (!pszCoreFilePath)
RTStrPrintf(pSolCore->szCorePath, sizeof(pSolCore->szCorePath), "%s/core.vb.%s", g_szCoreDumpDir, g_szCoreDumpFile);
CORELOG((CORELOG_NAME "CreateCore: Taking Core %s from Thread %d\n", pSolCore->szCorePath, (int)pSolProc->hCurThread));
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", SolCore.szCorePath, rc));
return rc;
bool fCallSystemDump = false;
bool fRc;
if (fRc)
CORELOGRELSYS((CORELOG_NAME "SignalHandler: Core dumper (thread %u) crashed Sig=%d. Triggering system dump\n",
fCallSystemDump = true;
CORELOGRELSYS((CORELOG_NAME "SignalHandler: Core dump already in progress! Waiting a while for completion Sig=%d.\n",
Sig));
if (iTimeout <= 0)
if (iTimeout <= 0)
fCallSystemDump = true;
CORELOGRELSYS((CORELOG_NAME "SignalHandler: Core dumper seems to be stuck. Signalling new signal %d\n", Sig));
if (fCallSystemDump)
abort();
if (!rc)
if (!fLiveCore)
abort();
return rc;
if (pszOutputDir)
return VERR_NOT_A_DIRECTORY;
return VINF_SUCCESS;
return VINF_SUCCESS;