1
/* $Id: coredumper-solaris.cpp $ */
3
* IPRT Testcase - Core Dumper.
7
* Copyright (C) 2010 Oracle Corporation
9
* This file is part of VirtualBox Open Source Edition (OSE), as
10
* available from http://www.virtualbox.org. This file is free software;
11
* you can redistribute it and/or modify it under the terms of the GNU
12
* General Public License (GPL) as published by the Free Software
13
* Foundation, in version 2 as it comes in the "COPYING" file of the
14
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17
* The contents of this file may alternatively be used under the terms
18
* of the Common Development and Distribution License Version 1.0
19
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20
* VirtualBox OSE distribution, in which case the provisions of the
21
* CDDL are applicable instead of those of the GPL.
23
* You may elect to license modified versions of this file under the
24
* terms and conditions of either the GPL or the CDDL or both.
27
/*******************************************************************************
29
*******************************************************************************/
30
#define LOG_GROUP LOG_GROUP_CORE_DUMPER
32
#include <iprt/coredumper.h>
33
#include <iprt/types.h>
34
#include <iprt/file.h>
37
#include <iprt/path.h>
38
#include <iprt/string.h>
39
#include <iprt/thread.h>
40
#include <iprt/param.h>
42
#include "coredumper-solaris.h"
51
# include <sys/proc.h>
52
# include <sys/sysmacros.h>
53
# include <sys/systeminfo.h>
54
# include <sys/mman.h>
55
# include <ucontext.h>
56
#endif /* RT_OS_SOLARIS */
58
#include "internal/ldrELF.h"
59
#include "internal/ldrELF64.h"
61
/*******************************************************************************
63
*******************************************************************************/
64
static RTNATIVETHREAD volatile g_CoreDumpThread = NIL_RTNATIVETHREAD;
65
static bool volatile g_fCoreDumpSignalSetup = false;
66
static uint32_t volatile g_fCoreDumpFlags = 0;
67
static char g_szCoreDumpDir[PATH_MAX] = { 0 };
68
static char g_szCoreDumpFile[PATH_MAX] = { 0 };
71
/*******************************************************************************
72
* Defined Constants And Macros *
73
*******************************************************************************/
74
#define CORELOG_NAME "CoreDumper: "
75
#define CORELOG(a) Log(a)
76
#define CORELOGRELSYS(a) \
79
rtCoreDumperSysLogWrapper a; \
84
* ELFNOTEHDR: ELF NOTE header.
86
typedef struct ELFNOTEHDR
88
Elf64_Nhdr Hdr; /* Header of NOTE section */
89
char achName[8]; /* Name of NOTE section */
91
typedef ELFNOTEHDR *PELFNOTEHDR;
94
* Wrapper function to write IPRT format style string to the syslog.
96
* @param pszFormat Format string
98
static void rtCoreDumperSysLogWrapper(const char *pszFormat, ...)
101
va_start(va, pszFormat);
103
RTStrPrintfV(szBuf, sizeof(szBuf), pszFormat, va);
105
syslog(LOG_ERR, "%s", szBuf);
110
* Determines endianness of the system. Just for completeness.
112
* @return Will return false if system is little endian, true otherwise.
114
static bool IsBigEndian()
117
char *p = (char *)&i;
125
* Reads from a file making sure an interruption doesn't cause a failure.
127
* @param hFile Handle to the file to read.
128
* @param pv Where to store the read data.
129
* @param cbToRead Size of data to read.
131
* @return IPRT status code.
133
static int ReadFileNoIntr(RTFILE hFile, void *pv, size_t cbToRead)
135
int rc = VERR_READ_ERROR;
138
rc = RTFileRead(hFile, pv, cbToRead, NULL /* Read all */);
139
if (rc == VERR_INTERRUPTED)
148
* Writes to a file making sure an interruption doesn't cause a failure.
150
* @param hFile Handle to the file to write.
151
* @param pv Pointer to what to write.
152
* @param cbToRead Size of data to write.
154
* @return IPRT status code.
156
static int WriteFileNoIntr(RTFILE hFile, const void *pcv, size_t cbToRead)
158
int rc = VERR_READ_ERROR;
161
rc = RTFileWrite(hFile, pcv, cbToRead, NULL /* Write all */);
162
if (rc == VERR_INTERRUPTED)
171
* Read from a given offet in the process' address space.
173
* @param pVBoxProc Pointer to the VBox process.
174
* @param pv Where to read the data into.
175
* @param cb Size of the read buffer.
176
* @param off Offset to read from.
178
* @return VINF_SUCCESS, if all the given bytes was read in, otherwise VERR_READ_ERROR.
180
static ssize_t ProcReadAddrSpace(PVBOXPROCESS pVBoxProc, RTFOFF off, void *pvBuf, size_t cbToRead)
184
int rc = RTFileReadAt(pVBoxProc->hAs, off, pvBuf, cbToRead, NULL);
185
if (rc == VERR_INTERRUPTED)
193
* Determines if the current process' architecture is suitable for dumping core.
195
* @param pVBoxProc Pointer to the VBox process.
197
* @return true if the architecture matches the current one.
199
static inline bool IsProcessArchNative(PVBOXPROCESS pVBoxProc)
201
return pVBoxProc->ProcInfo.pr_dmodel == PR_MODEL_NATIVE;
206
* Helper function to get the size of a file given it's path.
208
* @param pszPath Pointer to the full path of the file.
210
* @return The size of the file in bytes.
212
static size_t GetFileSize(const char *pszPath)
216
int rc = RTFileOpen(&hFile, pszPath, RTFILE_O_OPEN | RTFILE_O_READ);
219
RTFileGetSize(hFile, &cb);
223
CORELOGRELSYS((CORELOG_NAME "GetFileSize failed to open %s rc=%Rrc\n", pszPath, rc));
224
return cb < ~(size_t)0 ? (size_t)cb : ~(size_t)0;
229
* Pre-compute and pre-allocate sufficient memory for dumping core.
230
* This is meant to be called once, as a single-large anonymously
231
* mapped memory area which will be used during the core dumping routines.
233
* @param pVBoxCore Pointer to the core object.
235
* @return IPRT status code.
237
static int AllocMemoryArea(PVBOXCORE pVBoxCore)
239
AssertReturn(pVBoxCore->pvCore == NULL, VERR_ALREADY_EXISTS);
241
struct VBOXSOLPREALLOCTABLE
243
const char *pszFilePath; /* Proc based path */
244
size_t cbHeader; /* Size of header */
245
size_t cbEntry; /* Size of each entry in file */
246
size_t cbAccounting; /* Size of each accounting entry per entry */
247
} aPreAllocTable[] = {
248
{ "/proc/%d/map", 0, sizeof(prmap_t), sizeof(VBOXSOLMAPINFO) },
249
{ "/proc/%d/auxv", 0, 0, 0 },
250
{ "/proc/%d/lpsinfo", sizeof(prheader_t), sizeof(lwpsinfo_t), sizeof(VBOXSOLTHREADINFO) },
251
{ "/proc/%d/lstatus", 0, 0, 0 },
252
{ "/proc/%d/ldt", 0, 0, 0 },
253
{ "/proc/%d/cred", sizeof(prcred_t), sizeof(gid_t), 0 },
254
{ "/proc/%d/priv", sizeof(prpriv_t), sizeof(priv_chunk_t), 0 },
258
for (int i = 0; i < (int)RT_ELEMENTS(aPreAllocTable); i++)
260
char szPath[PATH_MAX];
261
RTStrPrintf(szPath, sizeof(szPath), aPreAllocTable[i].pszFilePath, (int)pVBoxCore->VBoxProc.Process);
262
size_t cbFile = GetFileSize(szPath);
265
&& aPreAllocTable[i].cbEntry > 0)
267
cb += ((cbFile - aPreAllocTable[i].cbHeader) / aPreAllocTable[i].cbEntry) * (aPreAllocTable[i].cbAccounting > 0 ?
268
aPreAllocTable[i].cbAccounting : 1);
269
cb += aPreAllocTable[i].cbHeader;
274
* Make room for our own mapping accountant entry which will also be included in the core.
276
cb += sizeof(VBOXSOLMAPINFO);
279
* Allocate the required space, plus some extra room.
282
void *pv = mmap(NULL, cb, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1 /* fd */, 0 /* offset */);
283
if (pv != MAP_FAILED)
285
CORELOG((CORELOG_NAME "AllocMemoryArea: memory area of %u bytes allocated.\n", cb));
286
pVBoxCore->pvCore = pv;
287
pVBoxCore->pvFree = pv;
288
pVBoxCore->cbCore = cb;
293
CORELOGRELSYS((CORELOG_NAME "AllocMemoryArea: failed cb=%u\n", cb));
294
return VERR_NO_MEMORY;
300
* Free memory area used by the core object.
302
* @param pVBoxCore Pointer to the core object.
304
static void FreeMemoryArea(PVBOXCORE pVBoxCore)
306
AssertReturnVoid(pVBoxCore);
307
AssertReturnVoid(pVBoxCore->pvCore);
308
AssertReturnVoid(pVBoxCore->cbCore > 0);
310
munmap(pVBoxCore->pvCore, pVBoxCore->cbCore);
311
CORELOG((CORELOG_NAME "FreeMemoryArea: memory area of %u bytes freed.\n", pVBoxCore->cbCore));
313
pVBoxCore->pvCore = NULL;
314
pVBoxCore->pvFree= NULL;
315
pVBoxCore->cbCore = 0;
320
* Get a chunk from the area of allocated memory.
322
* @param pVBoxCore Pointer to the core object.
323
* @param cb Size of requested chunk.
325
* @return Pointer to allocated memory, or NULL on failure.
327
static void *GetMemoryChunk(PVBOXCORE pVBoxCore, size_t cb)
329
AssertReturn(pVBoxCore, NULL);
330
AssertReturn(pVBoxCore->pvCore, NULL);
331
AssertReturn(pVBoxCore->pvFree, NULL);
333
size_t cbAllocated = (char *)pVBoxCore->pvFree - (char *)pVBoxCore->pvCore;
334
if (cbAllocated < pVBoxCore->cbCore)
336
char *pb = (char *)pVBoxCore->pvFree;
337
pVBoxCore->pvFree = pb + cb;
346
* Reads the proc file's content into a newly allocated buffer.
348
* @param pVBoxCore Pointer to the core object.
349
* @param pszFileFmt Only the name of the file to read from (/proc/<pid> will be prepended)
350
* @param ppv Where to store the allocated buffer.
351
* @param pcb Where to store size of the buffer.
353
* @return IPRT status code.
355
static int ProcReadFileInto(PVBOXCORE pVBoxCore, const char *pszProcFileName, void **ppv, size_t *pcb)
357
AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
359
char szPath[PATH_MAX];
360
RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/%s", (int)pVBoxCore->VBoxProc.Process, pszProcFileName);
362
int rc = RTFileOpen(&hFile, szPath, RTFILE_O_OPEN | RTFILE_O_READ);
366
RTFileGetSize(hFile, &u64Size);
367
*pcb = u64Size < ~(size_t)0 ? u64Size : ~(size_t)0;
370
*ppv = GetMemoryChunk(pVBoxCore, *pcb);
372
rc = ReadFileNoIntr(hFile, *ppv, *pcb);
384
CORELOGRELSYS((CORELOG_NAME "ProcReadFileInto: failed to open %s. rc=%Rrc\n", szPath, rc));
390
* Read process information (format psinfo_t) from /proc.
392
* @param pVBoxCore Pointer to the core object.
394
* @return IPRT status code.
396
static int ProcReadInfo(PVBOXCORE pVBoxCore)
398
AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
400
PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
401
char szPath[PATH_MAX];
404
RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/psinfo", (int)pVBoxProc->Process);
405
int rc = RTFileOpen(&hFile, szPath, RTFILE_O_OPEN | RTFILE_O_READ);
408
size_t cbProcInfo = sizeof(psinfo_t);
409
rc = ReadFileNoIntr(hFile, &pVBoxProc->ProcInfo, cbProcInfo);
418
* Read process status (format pstatus_t) from /proc.
420
* @param pVBoxCore Pointer to the core object.
422
* @return IPRT status code.
424
static int ProcReadStatus(PVBOXCORE pVBoxCore)
426
AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
428
PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
430
char szPath[PATH_MAX];
433
RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/status", (int)pVBoxProc->Process);
434
int rc = RTFileOpen(&hFile, szPath, RTFILE_O_OPEN | RTFILE_O_READ);
438
size_t cbProcStatus = sizeof(pstatus_t);
439
AssertCompile(sizeof(pstatus_t) == sizeof(pVBoxProc->ProcStatus));
440
rc = ReadFileNoIntr(hFile, &pVBoxProc->ProcStatus, cbProcStatus);
448
* Read process credential information (format prcred_t + array of guid_t)
450
* @param pVBoxCore Pointer to the core object.
452
* @remarks Should not be called before successful call to @see AllocMemoryArea()
453
* @return IPRT status code.
455
static int ProcReadCred(PVBOXCORE pVBoxCore)
457
AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
459
PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
460
return ProcReadFileInto(pVBoxCore, "cred", &pVBoxProc->pvCred, &pVBoxProc->cbCred);
465
* Read process privilege information (format prpriv_t + array of priv_chunk_t)
467
* @param pVBoxCore Pointer to the core object.
469
* @remarks Should not be called before successful call to @see AllocMemoryArea()
470
* @return IPRT status code.
472
static int ProcReadPriv(PVBOXCORE pVBoxCore)
474
AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
476
PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
477
int rc = ProcReadFileInto(pVBoxCore, "priv", (void **)&pVBoxProc->pPriv, &pVBoxProc->cbPriv);
480
pVBoxProc->pcPrivImpl = getprivimplinfo();
481
if (!pVBoxProc->pcPrivImpl)
483
CORELOGRELSYS((CORELOG_NAME "ProcReadPriv: getprivimplinfo returned NULL.\n"));
484
return VERR_INVALID_STATE;
491
* Read process LDT information (format array of struct ssd) from /proc.
493
* @param pVBoxProc Pointer to the core object.
495
* @remarks Should not be called before successful call to @see AllocMemoryArea()
496
* @return IPRT status code.
498
static int ProcReadLdt(PVBOXCORE pVBoxCore)
500
AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
502
PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
503
return ProcReadFileInto(pVBoxCore, "ldt", &pVBoxProc->pvLdt, &pVBoxProc->cbLdt);
508
* Read process auxiliary vectors (format auxv_t) for the process.
510
* @param pVBoxCore Pointer to the core object.
512
* @remarks Should not be called before successful call to @see AllocMemoryArea()
513
* @return IPRT status code.
515
static int ProcReadAuxVecs(PVBOXCORE pVBoxCore)
517
AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
519
PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
520
char szPath[PATH_MAX];
521
RTFILE hFile = NIL_RTFILE;
522
RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/auxv", (int)pVBoxProc->Process);
523
int rc = RTFileOpen(&hFile, szPath, RTFILE_O_OPEN | RTFILE_O_READ);
526
CORELOGRELSYS((CORELOG_NAME "ProcReadAuxVecs: RTFileOpen %s failed rc=%Rrc\n", szPath, rc));
531
RTFileGetSize(hFile, &u64Size);
532
size_t cbAuxFile = u64Size < ~(size_t)0 ? u64Size : ~(size_t)0;
533
if (cbAuxFile >= sizeof(auxv_t))
535
pVBoxProc->pAuxVecs = (auxv_t*)GetMemoryChunk(pVBoxCore, cbAuxFile + sizeof(auxv_t));
536
if (pVBoxProc->pAuxVecs)
538
rc = ReadFileNoIntr(hFile, pVBoxProc->pAuxVecs, cbAuxFile);
541
/* Terminate list of vectors */
542
pVBoxProc->cAuxVecs = cbAuxFile / sizeof(auxv_t);
543
CORELOG((CORELOG_NAME "ProcReadAuxVecs: cbAuxFile=%u auxv_t size %d cAuxVecs=%u\n", cbAuxFile, sizeof(auxv_t),
544
pVBoxProc->cAuxVecs));
545
if (pVBoxProc->cAuxVecs > 0)
547
pVBoxProc->pAuxVecs[pVBoxProc->cAuxVecs].a_type = AT_NULL;
548
pVBoxProc->pAuxVecs[pVBoxProc->cAuxVecs].a_un.a_val = 0L;
554
CORELOGRELSYS((CORELOG_NAME "ProcReadAuxVecs: Invalid vector count %u\n", pVBoxProc->cAuxVecs));
555
rc = VERR_READ_ERROR;
559
CORELOGRELSYS((CORELOG_NAME "ProcReadAuxVecs: ReadFileNoIntr failed. rc=%Rrc cbAuxFile=%u\n", rc, cbAuxFile));
561
pVBoxProc->pAuxVecs = NULL;
562
pVBoxProc->cAuxVecs = 0;
566
CORELOGRELSYS((CORELOG_NAME "ProcReadAuxVecs: no memory for %u bytes\n", cbAuxFile + sizeof(auxv_t)));
571
CORELOGRELSYS((CORELOG_NAME "ProcReadAuxVecs: aux file too small %u, expecting %u or more\n", cbAuxFile, sizeof(auxv_t)));
579
* Find an element in the process' auxiliary vector.
581
static long GetAuxVal(PVBOXPROCESS pVBoxProc, int Type)
583
AssertReturn(pVBoxProc, -1);
584
if (pVBoxProc->pAuxVecs)
586
auxv_t *pAuxVec = pVBoxProc->pAuxVecs;
587
for (; pAuxVec->a_type != AT_NULL; pAuxVec++)
589
if (pAuxVec->a_type == Type)
590
return pAuxVec->a_un.a_val;
598
* Read the process mappings (format prmap_t array).
600
* @param pVBoxCore Pointer to the core object.
602
* @remarks Should not be called before successful call to @see AllocMemoryArea()
603
* @return IPRT status code.
605
static int ProcReadMappings(PVBOXCORE pVBoxCore)
607
AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
609
PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
610
char szPath[PATH_MAX];
611
RTFILE hFile = NIL_RTFILE;
612
RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/map", (int)pVBoxProc->Process);
613
int rc = RTFileOpen(&hFile, szPath, RTFILE_O_OPEN | RTFILE_O_READ);
617
RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/as", (int)pVBoxProc->Process);
618
rc = RTFileOpen(&pVBoxProc->hAs, szPath, RTFILE_O_OPEN | RTFILE_O_READ);
622
* Allocate and read all the prmap_t objects from proc.
625
RTFileGetSize(hFile, &u64Size);
626
size_t cbMapFile = u64Size < ~(size_t)0 ? u64Size : ~(size_t)0;
627
if (cbMapFile >= sizeof(prmap_t))
629
prmap_t *pMap = (prmap_t*)GetMemoryChunk(pVBoxCore, cbMapFile);
632
rc = ReadFileNoIntr(hFile, pMap, cbMapFile);
635
pVBoxProc->cMappings = cbMapFile / sizeof(prmap_t);
636
if (pVBoxProc->cMappings > 0)
639
* Allocate for each prmap_t object, a corresponding VBOXSOLMAPINFO object.
641
pVBoxProc->pMapInfoHead = (PVBOXSOLMAPINFO)GetMemoryChunk(pVBoxCore, pVBoxProc->cMappings * sizeof(VBOXSOLMAPINFO));
642
if (pVBoxProc->pMapInfoHead)
645
* Associate the prmap_t with the mapping info object.
647
Assert(pVBoxProc->pMapInfoHead == NULL);
648
PVBOXSOLMAPINFO pCur = pVBoxProc->pMapInfoHead;
649
PVBOXSOLMAPINFO pPrev = NULL;
650
for (uint64_t i = 0; i < pVBoxProc->cMappings; i++, pMap++, pCur++)
652
memcpy(&pCur->pMap, pMap, sizeof(pCur->pMap));
659
* Make sure we can read the mapping, otherwise mark them to be skipped.
661
char achBuf[PAGE_SIZE];
663
while (k < pCur->pMap.pr_size)
665
size_t cb = RT_MIN(sizeof(achBuf), pCur->pMap.pr_size - k);
666
int rc2 = ProcReadAddrSpace(pVBoxProc, pCur->pMap.pr_vaddr + k, &achBuf, cb);
669
CORELOGRELSYS((CORELOG_NAME "ProcReadMappings: skipping mapping. vaddr=%#x rc=%Rrc\n",
670
pCur->pMap.pr_vaddr, rc2));
673
* Instead of storing the actual mapping data which we failed to read, the core
674
* will contain an errno in place. So we adjust the prmap_t's size field too
675
* so the program header offsets match.
677
pCur->pMap.pr_size = RT_ALIGN_Z(sizeof(int), 8);
678
pCur->fError = errno;
679
if (pCur->fError == 0) /* huh!? somehow errno got reset? fake one! EFAULT is nice. */
680
pCur->fError = EFAULT;
692
RTFileClose(pVBoxProc->hAs);
693
pVBoxProc->hAs = NIL_RTFILE;
694
CORELOG((CORELOG_NAME "ProcReadMappings: successfully read in %u mappings\n", pVBoxProc->cMappings));
699
CORELOGRELSYS((CORELOG_NAME "ProcReadMappings: GetMemoryChunk failed %u\n",
700
pVBoxProc->cMappings * sizeof(VBOXSOLMAPINFO)));
706
CORELOGRELSYS((CORELOG_NAME "ProcReadMappings: Invalid mapping count %u\n", pVBoxProc->cMappings));
707
rc = VERR_READ_ERROR;
711
CORELOGRELSYS((CORELOG_NAME "ProcReadMappings: FileReadNoIntr failed. rc=%Rrc cbMapFile=%u\n", rc, cbMapFile));
715
CORELOGRELSYS((CORELOG_NAME "ProcReadMappings: GetMemoryChunk failed. cbMapFile=%u\n", cbMapFile));
720
RTFileClose(pVBoxProc->hAs);
721
pVBoxProc->hAs = NIL_RTFILE;
724
CORELOGRELSYS((CORELOG_NAME "ProcReadMappings: failed to open %s. rc=%Rrc\n", szPath, rc));
732
* Reads the thread information for all threads in the process.
734
* @param pVBoxCore Pointer to the core object.
736
* @remarks Should not be called before successful call to @see AllocMemoryArea()
737
* @return IPRT status code.
739
static int ProcReadThreads(PVBOXCORE pVBoxCore)
741
AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
743
PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
744
AssertReturn(pVBoxProc->pCurThreadCtx, VERR_NO_DATA);
747
* Read the information for threads.
748
* Format: prheader_t + array of lwpsinfo_t's.
750
size_t cbInfoHdrAndData;
751
void *pvInfoHdr = NULL;
752
int rc = ProcReadFileInto(pVBoxCore, "lpsinfo", &pvInfoHdr, &cbInfoHdrAndData);
756
* Read the status of threads.
757
* Format: prheader_t + array of lwpstatus_t's.
759
void *pvStatusHdr = NULL;
760
size_t cbStatusHdrAndData;
761
rc = ProcReadFileInto(pVBoxCore, "lstatus", &pvStatusHdr, &cbStatusHdrAndData);
764
prheader_t *pInfoHdr = (prheader_t *)pvInfoHdr;
765
prheader_t *pStatusHdr = (prheader_t *)pvStatusHdr;
766
lwpstatus_t *pStatus = (lwpstatus_t *)((uintptr_t)pStatusHdr + sizeof(prheader_t));
767
lwpsinfo_t *pInfo = (lwpsinfo_t *)((uintptr_t)pInfoHdr + sizeof(prheader_t));
768
uint64_t cStatus = pStatusHdr->pr_nent;
769
uint64_t cInfo = pInfoHdr->pr_nent;
771
CORELOG((CORELOG_NAME "ProcReadThreads: read info(%u) status(%u), threads:cInfo=%u cStatus=%u\n", cbInfoHdrAndData,
772
cbStatusHdrAndData, cInfo, cStatus));
775
* Minor sanity size check (remember sizeof lwpstatus_t & lwpsinfo_t is <= size in file per entry).
777
if ( (cbStatusHdrAndData - sizeof(prheader_t)) % pStatusHdr->pr_entsize == 0
778
&& (cbInfoHdrAndData - sizeof(prheader_t)) % pInfoHdr->pr_entsize == 0)
781
* Make sure we have a matching lstatus entry for an lpsinfo entry unless
782
* it is a zombie thread, in which case we will not have a matching lstatus entry.
784
for (; cInfo != 0; cInfo--)
786
if (pInfo->pr_sname != 'Z') /* zombie */
789
|| pStatus->pr_lwpid != pInfo->pr_lwpid)
791
CORELOGRELSYS((CORELOG_NAME "ProcReadThreads: cStatus = %u pStatuslwpid=%d infolwpid=%d\n", cStatus,
792
pStatus->pr_lwpid, pInfo->pr_lwpid));
793
rc = VERR_INVALID_STATE;
796
pStatus = (lwpstatus_t *)((uintptr_t)pStatus + pStatusHdr->pr_entsize);
799
pInfo = (lwpsinfo_t *)((uintptr_t)pInfo + pInfoHdr->pr_entsize);
805
* Threre can still be more lwpsinfo_t's than lwpstatus_t's, build the
808
pStatus = (lwpstatus_t *)((uintptr_t)pStatusHdr + sizeof(prheader_t));
809
pInfo = (lwpsinfo_t *)((uintptr_t)pInfoHdr + sizeof(prheader_t));
810
cInfo = pInfoHdr->pr_nent;
811
cStatus = pInfoHdr->pr_nent;
813
size_t cbThreadInfo = RT_MAX(cStatus, cInfo) * sizeof(VBOXSOLTHREADINFO);
814
pVBoxProc->pThreadInfoHead = (PVBOXSOLTHREADINFO)GetMemoryChunk(pVBoxCore, cbThreadInfo);
815
if (pVBoxProc->pThreadInfoHead)
817
PVBOXSOLTHREADINFO pCur = pVBoxProc->pThreadInfoHead;
818
PVBOXSOLTHREADINFO pPrev = NULL;
819
for (uint64_t i = 0; i < cInfo; i++, pCur++)
822
if ( pInfo->pr_sname != 'Z'
823
&& pInfo->pr_lwpid == pStatus->pr_lwpid)
826
* Adjust the context of the dumping thread to reflect the context
827
* when the core dump got initiated before whatever signal caused it.
829
if ( pStatus /* noid droid */
830
&& pStatus->pr_lwpid == (id_t)pVBoxProc->hCurThread)
832
AssertCompile(sizeof(pStatus->pr_reg) == sizeof(pVBoxProc->pCurThreadCtx->uc_mcontext.gregs));
833
AssertCompile(sizeof(pStatus->pr_fpreg) == sizeof(pVBoxProc->pCurThreadCtx->uc_mcontext.fpregs));
834
memcpy(&pStatus->pr_reg, &pVBoxProc->pCurThreadCtx->uc_mcontext.gregs, sizeof(pStatus->pr_reg));
835
memcpy(&pStatus->pr_fpreg, &pVBoxProc->pCurThreadCtx->uc_mcontext.fpregs, sizeof(pStatus->pr_fpreg));
837
AssertCompile(sizeof(pStatus->pr_lwphold) == sizeof(pVBoxProc->pCurThreadCtx->uc_sigmask));
838
memcpy(&pStatus->pr_lwphold, &pVBoxProc->pCurThreadCtx->uc_sigmask, sizeof(pStatus->pr_lwphold));
839
pStatus->pr_ustack = (uintptr_t)&pVBoxProc->pCurThreadCtx->uc_stack;
841
CORELOG((CORELOG_NAME "ProcReadThreads: patched dumper thread context with pre-dump time context.\n"));
844
pCur->pStatus = pStatus;
845
pStatus = (lwpstatus_t *)((uintptr_t)pStatus + pStatusHdr->pr_entsize);
849
CORELOGRELSYS((CORELOG_NAME "ProcReadThreads: missing status for lwp %d\n", pInfo->pr_lwpid));
850
pCur->pStatus = NULL;
856
pInfo = (lwpsinfo_t *)((uintptr_t)pInfo + pInfoHdr->pr_entsize);
861
CORELOG((CORELOG_NAME "ProcReadThreads: successfully read %u threads.\n", cInfo));
862
pVBoxProc->cThreads = cInfo;
867
CORELOGRELSYS((CORELOG_NAME "ProcReadThreads: GetMemoryChunk failed for %u bytes\n", cbThreadInfo));
872
CORELOGRELSYS((CORELOG_NAME "ProcReadThreads: Invalid state information for threads.\n", rc));
876
CORELOGRELSYS((CORELOG_NAME "ProcReadThreads: huh!? cbStatusHdrAndData=%u prheader_t=%u entsize=%u\n", cbStatusHdrAndData,
877
sizeof(prheader_t), pStatusHdr->pr_entsize));
878
CORELOGRELSYS((CORELOG_NAME "ProcReadThreads: huh!? cbInfoHdrAndData=%u entsize=%u\n", cbInfoHdrAndData,
879
pStatusHdr->pr_entsize));
880
rc = VERR_INVALID_STATE;
884
CORELOGRELSYS((CORELOG_NAME "ProcReadThreads: ReadFileNoIntr failed for \"lpsinfo\" rc=%Rrc\n", rc));
887
CORELOGRELSYS((CORELOG_NAME "ProcReadThreads: ReadFileNoIntr failed for \"lstatus\" rc=%Rrc\n", rc));
893
* Reads miscellaneous information that is collected as part of a core file.
894
* This may include platform name, zone name and other OS-specific information.
896
* @param pVBoxCore Pointer to the core object.
898
* @return IPRT status code.
900
static int ProcReadMiscInfo(PVBOXCORE pVBoxCore)
902
AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
904
PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
908
* Read the platform name, uname string and zone name.
910
int rc = sysinfo(SI_PLATFORM, pVBoxProc->szPlatform, sizeof(pVBoxProc->szPlatform));
913
CORELOGRELSYS((CORELOG_NAME "ProcReadMiscInfo: sysinfo failed. rc=%d errno=%d\n", rc, errno));
914
return VERR_GENERAL_FAILURE;
916
pVBoxProc->szPlatform[sizeof(pVBoxProc->szPlatform) - 1] = '\0';
918
rc = uname(&pVBoxProc->UtsName);
921
CORELOGRELSYS((CORELOG_NAME "ProcReadMiscInfo: uname failed. rc=%d errno=%d\n", rc, errno));
922
return VERR_GENERAL_FAILURE;
925
rc = getzonenamebyid(pVBoxProc->ProcInfo.pr_zoneid, pVBoxProc->szZoneName, sizeof(pVBoxProc->szZoneName));
928
CORELOGRELSYS((CORELOG_NAME "ProcReadMiscInfo: getzonenamebyid failed. rc=%d errno=%d zoneid=%d\n", rc, errno,
929
pVBoxProc->ProcInfo.pr_zoneid));
930
return VERR_GENERAL_FAILURE;
932
pVBoxProc->szZoneName[sizeof(pVBoxProc->szZoneName) - 1] = '\0';
943
* On Solaris use the old-style procfs interfaces but the core file still should have this
944
* info. for backward and GDB compatibility, hence the need for this ugly function.
946
* @param pVBoxCore Pointer to the core object.
947
* @param pInfo Pointer to the old prpsinfo_t structure to update.
949
static void GetOldProcessInfo(PVBOXCORE pVBoxCore, prpsinfo_t *pInfo)
951
AssertReturnVoid(pVBoxCore);
952
AssertReturnVoid(pInfo);
954
PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
955
psinfo_t *pSrc = &pVBoxProc->ProcInfo;
956
memset(pInfo, 0, sizeof(prpsinfo_t));
957
pInfo->pr_state = pSrc->pr_lwp.pr_state;
958
pInfo->pr_zomb = (pInfo->pr_state == SZOMB);
959
RTStrCopy(pInfo->pr_clname, sizeof(pInfo->pr_clname), pSrc->pr_lwp.pr_clname);
960
RTStrCopy(pInfo->pr_fname, sizeof(pInfo->pr_fname), pSrc->pr_fname);
961
memcpy(&pInfo->pr_psargs, &pSrc->pr_psargs, sizeof(pInfo->pr_psargs));
962
pInfo->pr_nice = pSrc->pr_lwp.pr_nice;
963
pInfo->pr_flag = pSrc->pr_lwp.pr_flag;
964
pInfo->pr_uid = pSrc->pr_uid;
965
pInfo->pr_gid = pSrc->pr_gid;
966
pInfo->pr_pid = pSrc->pr_pid;
967
pInfo->pr_ppid = pSrc->pr_ppid;
968
pInfo->pr_pgrp = pSrc->pr_pgid;
969
pInfo->pr_sid = pSrc->pr_sid;
970
pInfo->pr_addr = (caddr_t)pSrc->pr_addr;
971
pInfo->pr_size = pSrc->pr_size;
972
pInfo->pr_rssize = pSrc->pr_rssize;
973
pInfo->pr_wchan = (caddr_t)pSrc->pr_lwp.pr_wchan;
974
pInfo->pr_start = pSrc->pr_start;
975
pInfo->pr_time = pSrc->pr_time;
976
pInfo->pr_pri = pSrc->pr_lwp.pr_pri;
977
pInfo->pr_oldpri = pSrc->pr_lwp.pr_oldpri;
978
pInfo->pr_cpu = pSrc->pr_lwp.pr_cpu;
979
pInfo->pr_ottydev = cmpdev(pSrc->pr_ttydev);
980
pInfo->pr_lttydev = pSrc->pr_ttydev;
981
pInfo->pr_syscall = pSrc->pr_lwp.pr_syscall;
982
pInfo->pr_ctime = pSrc->pr_ctime;
983
pInfo->pr_bysize = pSrc->pr_size * PAGESIZE;
984
pInfo->pr_byrssize = pSrc->pr_rssize * PAGESIZE;
985
pInfo->pr_argc = pSrc->pr_argc;
986
pInfo->pr_argv = (char **)pSrc->pr_argv;
987
pInfo->pr_envp = (char **)pSrc->pr_envp;
988
pInfo->pr_wstat = pSrc->pr_wstat;
989
pInfo->pr_pctcpu = pSrc->pr_pctcpu;
990
pInfo->pr_pctmem = pSrc->pr_pctmem;
991
pInfo->pr_euid = pSrc->pr_euid;
992
pInfo->pr_egid = pSrc->pr_egid;
993
pInfo->pr_aslwpid = 0;
994
pInfo->pr_dmodel = pSrc->pr_dmodel;
999
* On Solaris use the old-style procfs interfaces but the core file still should have this
1000
* info. for backward and GDB compatibility, hence the need for this ugly function.
1002
* @param pVBoxCore Pointer to the core object.
1003
* @param pInfo Pointer to the thread info.
1004
* @param pStatus Pointer to the thread status.
1005
* @param pDst Pointer to the old-style status structure to update.
1008
static void GetOldProcessStatus(PVBOXCORE pVBoxCore, lwpsinfo_t *pInfo, lwpstatus_t *pStatus, prstatus_t *pDst)
1010
AssertReturnVoid(pVBoxCore);
1011
AssertReturnVoid(pInfo);
1012
AssertReturnVoid(pStatus);
1013
AssertReturnVoid(pDst);
1015
PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
1016
memset(pDst, 0, sizeof(prstatus_t));
1017
if (pStatus->pr_flags & PR_STOPPED)
1018
pDst->pr_flags = 0x0001;
1019
if (pStatus->pr_flags & PR_ISTOP)
1020
pDst->pr_flags = 0x0002;
1021
if (pStatus->pr_flags & PR_DSTOP)
1022
pDst->pr_flags = 0x0004;
1023
if (pStatus->pr_flags & PR_ASLEEP)
1024
pDst->pr_flags = 0x0008;
1025
if (pStatus->pr_flags & PR_FORK)
1026
pDst->pr_flags = 0x0010;
1027
if (pStatus->pr_flags & PR_RLC)
1028
pDst->pr_flags = 0x0020;
1029
/* PR_PTRACE is never set */
1030
if (pStatus->pr_flags & PR_PCINVAL)
1031
pDst->pr_flags = 0x0080;
1032
if (pStatus->pr_flags & PR_ISSYS)
1033
pDst->pr_flags = 0x0100;
1034
if (pStatus->pr_flags & PR_STEP)
1035
pDst->pr_flags = 0x0200;
1036
if (pStatus->pr_flags & PR_KLC)
1037
pDst->pr_flags = 0x0400;
1038
if (pStatus->pr_flags & PR_ASYNC)
1039
pDst->pr_flags = 0x0800;
1040
if (pStatus->pr_flags & PR_PTRACE)
1041
pDst->pr_flags = 0x1000;
1042
if (pStatus->pr_flags & PR_MSACCT)
1043
pDst->pr_flags = 0x2000;
1044
if (pStatus->pr_flags & PR_BPTADJ)
1045
pDst->pr_flags = 0x4000;
1046
if (pStatus->pr_flags & PR_ASLWP)
1047
pDst->pr_flags = 0x8000;
1049
pDst->pr_who = pStatus->pr_lwpid;
1050
pDst->pr_why = pStatus->pr_why;
1051
pDst->pr_what = pStatus->pr_what;
1052
pDst->pr_info = pStatus->pr_info;
1053
pDst->pr_cursig = pStatus->pr_cursig;
1054
pDst->pr_sighold = pStatus->pr_lwphold;
1055
pDst->pr_altstack = pStatus->pr_altstack;
1056
pDst->pr_action = pStatus->pr_action;
1057
pDst->pr_syscall = pStatus->pr_syscall;
1058
pDst->pr_nsysarg = pStatus->pr_nsysarg;
1059
pDst->pr_lwppend = pStatus->pr_lwppend;
1060
pDst->pr_oldcontext = (ucontext_t *)pStatus->pr_oldcontext;
1061
memcpy(pDst->pr_reg, pStatus->pr_reg, sizeof(pDst->pr_reg));
1062
memcpy(pDst->pr_sysarg, pStatus->pr_sysarg, sizeof(pDst->pr_sysarg));
1063
RTStrCopy(pDst->pr_clname, sizeof(pDst->pr_clname), pStatus->pr_clname);
1065
pDst->pr_nlwp = pVBoxProc->ProcStatus.pr_nlwp;
1066
pDst->pr_sigpend = pVBoxProc->ProcStatus.pr_sigpend;
1067
pDst->pr_pid = pVBoxProc->ProcStatus.pr_pid;
1068
pDst->pr_ppid = pVBoxProc->ProcStatus.pr_ppid;
1069
pDst->pr_pgrp = pVBoxProc->ProcStatus.pr_pgid;
1070
pDst->pr_sid = pVBoxProc->ProcStatus.pr_sid;
1071
pDst->pr_utime = pVBoxProc->ProcStatus.pr_utime;
1072
pDst->pr_stime = pVBoxProc->ProcStatus.pr_stime;
1073
pDst->pr_cutime = pVBoxProc->ProcStatus.pr_cutime;
1074
pDst->pr_cstime = pVBoxProc->ProcStatus.pr_cstime;
1075
pDst->pr_brkbase = (caddr_t)pVBoxProc->ProcStatus.pr_brkbase;
1076
pDst->pr_brksize = pVBoxProc->ProcStatus.pr_brksize;
1077
pDst->pr_stkbase = (caddr_t)pVBoxProc->ProcStatus.pr_stkbase;
1078
pDst->pr_stksize = pVBoxProc->ProcStatus.pr_stksize;
1080
pDst->pr_processor = (short)pInfo->pr_onpro;
1081
pDst->pr_bind = (short)pInfo->pr_bindpro;
1082
pDst->pr_instr = pStatus->pr_instr;
1087
* Callback for rtCoreDumperForEachThread to suspend a thread.
1089
* @param pVBoxCore Pointer to the core object.
1090
* @param pvThreadInfo Opaque pointer to thread information.
1092
* @return IPRT status code.
1094
static int suspendThread(PVBOXCORE pVBoxCore, void *pvThreadInfo)
1096
AssertPtrReturn(pvThreadInfo, VERR_INVALID_POINTER);
1099
lwpsinfo_t *pThreadInfo = (lwpsinfo_t *)pvThreadInfo;
1100
CORELOG((CORELOG_NAME ":suspendThread %d\n", (lwpid_t)pThreadInfo->pr_lwpid));
1101
if ((lwpid_t)pThreadInfo->pr_lwpid != pVBoxCore->VBoxProc.hCurThread)
1102
_lwp_suspend(pThreadInfo->pr_lwpid);
1103
return VINF_SUCCESS;
1108
* Callback for rtCoreDumperForEachThread to resume a thread.
1110
* @param pVBoxCore Pointer to the core object.
1111
* @param pvThreadInfo Opaque pointer to thread information.
1113
* @return IPRT status code.
1115
static int resumeThread(PVBOXCORE pVBoxCore, void *pvThreadInfo)
1117
AssertPtrReturn(pvThreadInfo, VERR_INVALID_POINTER);
1120
lwpsinfo_t *pThreadInfo = (lwpsinfo_t *)pvThreadInfo;
1121
CORELOG((CORELOG_NAME ":resumeThread %d\n", (lwpid_t)pThreadInfo->pr_lwpid));
1122
if ((lwpid_t)pThreadInfo->pr_lwpid != (lwpid_t)pVBoxCore->VBoxProc.hCurThread)
1123
_lwp_continue(pThreadInfo->pr_lwpid);
1124
return VINF_SUCCESS;
1129
* Calls a thread worker function for all threads in the process as described by /proc
1131
* @param pVBoxCore Pointer to the core object.
1132
* @param pcThreads Number of threads read.
1133
* @param pfnWorker Callback function for each thread.
1135
* @return IPRT status code.
1137
static int rtCoreDumperForEachThread(PVBOXCORE pVBoxCore, uint64_t *pcThreads, PFNCORETHREADWORKER pfnWorker)
1139
AssertPtrReturn(pVBoxCore, VERR_INVALID_POINTER);
1141
PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
1144
* Read the information for threads.
1145
* Format: prheader_t + array of lwpsinfo_t's.
1147
char szLpsInfoPath[PATH_MAX];
1148
RTStrPrintf(szLpsInfoPath, sizeof(szLpsInfoPath), "/proc/%d/lpsinfo", (int)pVBoxProc->Process);
1150
RTFILE hFile = NIL_RTFILE;
1151
int rc = RTFileOpen(&hFile, szLpsInfoPath, RTFILE_O_READ);
1155
RTFileGetSize(hFile, &u64Size);
1156
size_t cbInfoHdrAndData = u64Size < ~(size_t)0 ? u64Size : ~(size_t)0;
1157
void *pvInfoHdr = mmap(NULL, cbInfoHdrAndData, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1 /* fd */, 0 /* offset */);
1158
if (pvInfoHdr != MAP_FAILED)
1160
rc = RTFileRead(hFile, pvInfoHdr, cbInfoHdrAndData, NULL);
1163
prheader_t *pHeader = (prheader_t *)pvInfoHdr;
1164
lwpsinfo_t *pThreadInfo = (lwpsinfo_t *)((uintptr_t)pvInfoHdr + sizeof(prheader_t));
1165
for (unsigned i = 0; i < pHeader->pr_nent; i++)
1167
pfnWorker(pVBoxCore, pThreadInfo);
1168
pThreadInfo = (lwpsinfo_t *)((uintptr_t)pThreadInfo + pHeader->pr_entsize);
1171
*pcThreads = pHeader->pr_nent;
1174
munmap(pvInfoHdr, cbInfoHdrAndData);
1177
rc = VERR_NO_MEMORY;
1186
* Resume all threads of this process.
1188
* @param pVBoxCore Pointer to the core object.
1190
* @return IPRT status code..
1192
static int rtCoreDumperResumeThreads(PVBOXCORE pVBoxCore)
1194
AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
1198
return rtCoreDumperForEachThread(pVBoxCore, &cThreads, resumeThread);
1200
PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
1202
char szCurThread[128];
1203
char szPath[PATH_MAX];
1206
RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/lwp", (int)pVBoxProc->Process);
1207
RTStrPrintf(szCurThread, sizeof(szCurThread), "%d", (int)pVBoxProc->hCurThread);
1209
int32_t cRunningThreads = 0;
1210
int rc = RTDirOpen(&pDir, szPath);
1214
* Loop through all our threads & resume them.
1216
RTDIRENTRY DirEntry;
1217
while (RT_SUCCESS(RTDirRead(pDir, &DirEntry, NULL)))
1219
if ( !strcmp(DirEntry.szName, ".")
1220
|| !strcmp(DirEntry.szName, ".."))
1223
if ( !strcmp(DirEntry.szName, szCurThread))
1226
int32_t ThreadId = RTStrToInt32(DirEntry.szName);
1227
_lwp_continue((lwpid_t)ThreadId);
1231
CORELOG((CORELOG_NAME "ResumeAllThreads: resumed %d threads\n", cRunningThreads));
1236
CORELOGRELSYS((CORELOG_NAME "ResumeAllThreads: Failed to open %s\n", szPath));
1237
rc = VERR_READ_ERROR;
1245
* Stop all running threads of this process except the current one.
1247
* @param pVBoxCore Pointer to the core object.
1249
* @return IPRT status code.
1251
static int rtCoreDumperSuspendThreads(PVBOXCORE pVBoxCore)
1253
AssertPtrReturn(pVBoxCore, VERR_INVALID_POINTER);
1256
* This function tries to ensures while we suspend threads, no newly spawned threads
1257
* or a combination of spawning and terminating threads can cause any threads to be left running.
1258
* The assumption here is that threads can only increase not decrease across iterations.
1261
uint16_t cTries = 0;
1262
uint64_t aThreads[4];
1264
int rc = VERR_GENERAL_FAILURE;
1267
for (cTries = 0; cTries < RT_ELEMENTS(aThreads); cTries++)
1269
rc = rtCoreDumperForEachThread(pVBoxCore, &aThreads[cTries], suspendThread);
1274
&& aThreads[cTries - 1] != aThreads[cTries - 2])
1276
CORELOGRELSYS((CORELOG_NAME "rtCoreDumperSuspendThreads: possible thread bomb!?\n"));
1281
PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
1283
char szCurThread[128];
1284
char szPath[PATH_MAX];
1287
RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/lwp", (int)pVBoxProc->Process);
1288
RTStrPrintf(szCurThread, sizeof(szCurThread), "%d", (int)pVBoxProc->hCurThread);
1291
uint32_t cThreads = 0;
1292
uint16_t cTries = 0;
1293
for (cTries = 0; cTries < 10; cTries++)
1295
uint32_t cRunningThreads = 0;
1296
rc = RTDirOpen(&pDir, szPath);
1300
* Loop through all our threads & suspend them, multiple calls to _lwp_suspend() are okay.
1302
RTDIRENTRY DirEntry;
1303
while (RT_SUCCESS(RTDirRead(pDir, &DirEntry, NULL)))
1305
if ( !strcmp(DirEntry.szName, ".")
1306
|| !strcmp(DirEntry.szName, ".."))
1309
if ( !strcmp(DirEntry.szName, szCurThread))
1312
int32_t ThreadId = RTStrToInt32(DirEntry.szName);
1313
_lwp_suspend((lwpid_t)ThreadId);
1317
if (cTries > 5 && cThreads == cRunningThreads)
1322
cThreads = cRunningThreads;
1327
CORELOGRELSYS((CORELOG_NAME "SuspendThreads: Failed to open %s cTries=%d\n", szPath, cTries));
1328
rc = VERR_READ_ERROR;
1334
CORELOG((CORELOG_NAME "SuspendThreads: Stopped %u threads successfully with %u tries\n", cThreads, cTries));
1342
* Returns size of an ELF NOTE header given the size of data the NOTE section will contain.
1344
* @param cb Size of the data.
1346
* @return Size of data actually used for NOTE header and section.
1348
static inline size_t ElfNoteHeaderSize(size_t cb)
1350
return sizeof(ELFNOTEHDR) + RT_ALIGN_Z(cb, 4);
1355
* Write an ELF NOTE header into the core file.
1357
* @param pVBoxCore Pointer to the core object.
1358
* @param Type Type of this NOTE section.
1359
* @param pcv Opaque pointer to the data, if NULL only computes size.
1360
* @param cb Size of the data.
1362
* @return IPRT status code.
1364
static int ElfWriteNoteHeader(PVBOXCORE pVBoxCore, uint_t Type, const void *pcv, size_t cb)
1366
AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
1367
AssertReturn(pcv, VERR_INVALID_POINTER);
1368
AssertReturn(cb > 0, VERR_NO_DATA);
1369
AssertReturn(pVBoxCore->pfnWriter, VERR_WRITE_ERROR);
1370
AssertReturn(pVBoxCore->hCoreFile, VERR_INVALID_HANDLE);
1372
int rc = VERR_GENERAL_FAILURE;
1373
#ifdef RT_OS_SOLARIS
1374
ELFNOTEHDR ElfNoteHdr;
1375
RT_ZERO(ElfNoteHdr);
1376
ElfNoteHdr.achName[0] = 'C';
1377
ElfNoteHdr.achName[1] = 'O';
1378
ElfNoteHdr.achName[2] = 'R';
1379
ElfNoteHdr.achName[3] = 'E';
1382
* This is a known violation of the 64-bit ELF spec., see xTracker #5211 comment#3
1383
* for the historic reasons as to the padding and namesz anomalies.
1385
static const char s_achPad[3] = { 0, 0, 0 };
1386
size_t cbAlign = RT_ALIGN_Z(cb, 4);
1387
ElfNoteHdr.Hdr.n_namesz = 5;
1388
ElfNoteHdr.Hdr.n_type = Type;
1389
ElfNoteHdr.Hdr.n_descsz = cbAlign;
1392
* Write note header and description.
1394
rc = pVBoxCore->pfnWriter(pVBoxCore->hCoreFile, &ElfNoteHdr, sizeof(ElfNoteHdr));
1397
rc = pVBoxCore->pfnWriter(pVBoxCore->hCoreFile, pcv, cb);
1401
rc = pVBoxCore->pfnWriter(pVBoxCore->hCoreFile, s_achPad, cbAlign - cb);
1406
CORELOGRELSYS((CORELOG_NAME "ElfWriteNote: pfnWriter failed. Type=%d rc=%Rrc\n", Type, rc));
1415
* Computes the size of NOTE section for the given core type.
1416
* Solaris has two types of program header information (new and old).
1418
* @param pVBoxCore Pointer to the core object.
1419
* @param enmType Type of core file information required.
1421
* @return Size of NOTE section.
1423
static size_t ElfNoteSectionSize(PVBOXCORE pVBoxCore, VBOXSOLCORETYPE enmType)
1425
PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
1431
cb += ElfNoteHeaderSize(sizeof(prpsinfo_t));
1432
cb += ElfNoteHeaderSize(pVBoxProc->cAuxVecs * sizeof(auxv_t));
1433
cb += ElfNoteHeaderSize(strlen(pVBoxProc->szPlatform));
1435
PVBOXSOLTHREADINFO pThreadInfo = pVBoxProc->pThreadInfoHead;
1438
if (pThreadInfo->pStatus)
1440
cb += ElfNoteHeaderSize(sizeof(prstatus_t));
1441
cb += ElfNoteHeaderSize(sizeof(prfpregset_t));
1443
pThreadInfo = pThreadInfo->pNext;
1451
cb += ElfNoteHeaderSize(sizeof(psinfo_t));
1452
cb += ElfNoteHeaderSize(sizeof(pstatus_t));
1453
cb += ElfNoteHeaderSize(pVBoxProc->cAuxVecs * sizeof(auxv_t));
1454
cb += ElfNoteHeaderSize(strlen(pVBoxProc->szPlatform) + 1);
1455
cb += ElfNoteHeaderSize(sizeof(struct utsname));
1456
cb += ElfNoteHeaderSize(sizeof(core_content_t));
1457
cb += ElfNoteHeaderSize(pVBoxProc->cbCred);
1459
if (pVBoxProc->pPriv)
1460
cb += ElfNoteHeaderSize(PRIV_PRPRIV_SIZE(pVBoxProc->pPriv)); /* Ought to be same as cbPriv!? */
1462
if (pVBoxProc->pcPrivImpl)
1463
cb += ElfNoteHeaderSize(PRIV_IMPL_INFO_SIZE(pVBoxProc->pcPrivImpl));
1465
cb += ElfNoteHeaderSize(strlen(pVBoxProc->szZoneName) + 1);
1466
if (pVBoxProc->cbLdt > 0)
1467
cb += ElfNoteHeaderSize(pVBoxProc->cbLdt);
1469
PVBOXSOLTHREADINFO pThreadInfo = pVBoxProc->pThreadInfoHead;
1472
cb += ElfNoteHeaderSize(sizeof(lwpsinfo_t));
1473
if (pThreadInfo->pStatus)
1474
cb += ElfNoteHeaderSize(sizeof(lwpstatus_t));
1476
pThreadInfo = pThreadInfo->pNext;
1484
CORELOGRELSYS((CORELOG_NAME "ElfNoteSectionSize: Unknown segment era %d\n", enmType));
1494
* Write the note section for the given era into the core file.
1495
* Solaris has two types of program header information (new and old).
1497
* @param pVBoxCore Pointer to the core object.
1498
* @param enmType Type of core file information required.
1500
* @return IPRT status code.
1502
static int ElfWriteNoteSection(PVBOXCORE pVBoxCore, VBOXSOLCORETYPE enmType)
1504
AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
1506
PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
1507
int rc = VERR_GENERAL_FAILURE;
1509
#ifdef RT_OS_SOLARIS
1510
typedef int (*PFNELFWRITENOTEHDR)(PVBOXCORE pVBoxCore, uint_t, const void *pcv, size_t cb);
1511
typedef struct ELFWRITENOTE
1513
const char *pszType;
1523
ELFWRITENOTE aElfNotes[] =
1525
{ "NT_PRPSINFO", NT_PRPSINFO, &pVBoxProc->ProcInfoOld, sizeof(prpsinfo_t) },
1526
{ "NT_AUXV", NT_AUXV, pVBoxProc->pAuxVecs, pVBoxProc->cAuxVecs * sizeof(auxv_t) },
1527
{ "NT_PLATFORM", NT_PLATFORM, pVBoxProc->szPlatform, strlen(pVBoxProc->szPlatform) + 1 }
1530
for (unsigned i = 0; i < RT_ELEMENTS(aElfNotes); i++)
1532
rc = ElfWriteNoteHeader(pVBoxCore, aElfNotes[i].Type, aElfNotes[i].pcv, aElfNotes[i].cb);
1535
CORELOGRELSYS((CORELOG_NAME "ElfWriteNoteSection: ElfWriteNoteHeader failed for %s. rc=%Rrc\n", aElfNotes[i].pszType, rc));
1541
* Write old-style thread info., they contain nothing about zombies,
1542
* so we just skip if there is no status information for them.
1544
PVBOXSOLTHREADINFO pThreadInfo = pVBoxProc->pThreadInfoHead;
1545
for (; pThreadInfo; pThreadInfo = pThreadInfo->pNext)
1547
if (!pThreadInfo->pStatus)
1550
prstatus_t OldProcessStatus;
1551
GetOldProcessStatus(pVBoxCore, &pThreadInfo->Info, pThreadInfo->pStatus, &OldProcessStatus);
1552
rc = ElfWriteNoteHeader(pVBoxCore, NT_PRSTATUS, &OldProcessStatus, sizeof(prstatus_t));
1555
rc = ElfWriteNoteHeader(pVBoxCore, NT_PRFPREG, &pThreadInfo->pStatus->pr_fpreg, sizeof(prfpregset_t));
1558
CORELOGRELSYS((CORELOG_NAME "ElfWriteSegment: ElfWriteNote failed for NT_PRFPREF. rc=%Rrc\n", rc));
1564
CORELOGRELSYS((CORELOG_NAME "ElfWriteSegment: ElfWriteNote failed for NT_PRSTATUS. rc=%Rrc\n", rc));
1573
ELFWRITENOTE aElfNotes[] =
1575
{ "NT_PSINFO", NT_PSINFO, &pVBoxProc->ProcInfo, sizeof(psinfo_t) },
1576
{ "NT_PSTATUS", NT_PSTATUS, &pVBoxProc->ProcStatus, sizeof(pstatus_t) },
1577
{ "NT_AUXV", NT_AUXV, pVBoxProc->pAuxVecs, pVBoxProc->cAuxVecs * sizeof(auxv_t) },
1578
{ "NT_PLATFORM", NT_PLATFORM, pVBoxProc->szPlatform, strlen(pVBoxProc->szPlatform) + 1 },
1579
{ "NT_UTSNAME", NT_UTSNAME, &pVBoxProc->UtsName, sizeof(struct utsname) },
1580
{ "NT_CONTENT", NT_CONTENT, &pVBoxProc->CoreContent, sizeof(core_content_t) },
1581
{ "NT_PRCRED", NT_PRCRED, pVBoxProc->pvCred, pVBoxProc->cbCred },
1582
{ "NT_PRPRIV", NT_PRPRIV, pVBoxProc->pPriv, PRIV_PRPRIV_SIZE(pVBoxProc->pPriv) },
1583
{ "NT_PRPRIVINFO", NT_PRPRIVINFO, pVBoxProc->pcPrivImpl, PRIV_IMPL_INFO_SIZE(pVBoxProc->pcPrivImpl) },
1584
{ "NT_ZONENAME", NT_ZONENAME, pVBoxProc->szZoneName, strlen(pVBoxProc->szZoneName) + 1 }
1587
for (unsigned i = 0; i < RT_ELEMENTS(aElfNotes); i++)
1589
rc = ElfWriteNoteHeader(pVBoxCore, aElfNotes[i].Type, aElfNotes[i].pcv, aElfNotes[i].cb);
1592
CORELOGRELSYS((CORELOG_NAME "ElfWriteNoteSection: ElfWriteNoteHeader failed for %s. rc=%Rrc\n", aElfNotes[i].pszType, rc));
1598
* Write new-style thread info., missing lwpstatus_t indicates it's a zombie thread
1599
* we only dump the lwpsinfo_t in that case.
1601
PVBOXSOLTHREADINFO pThreadInfo = pVBoxProc->pThreadInfoHead;
1602
for (; pThreadInfo; pThreadInfo = pThreadInfo->pNext)
1604
rc = ElfWriteNoteHeader(pVBoxCore, NT_LWPSINFO, &pThreadInfo->Info, sizeof(lwpsinfo_t));
1607
CORELOGRELSYS((CORELOG_NAME "ElfWriteNoteSection: ElfWriteNoteHeader for NT_LWPSINFO failed. rc=%Rrc\n", rc));
1611
if (pThreadInfo->pStatus)
1613
rc = ElfWriteNoteHeader(pVBoxCore, NT_LWPSTATUS, pThreadInfo->pStatus, sizeof(lwpstatus_t));
1616
CORELOGRELSYS((CORELOG_NAME "ElfWriteNoteSection: ElfWriteNoteHeader for NT_LWPSTATUS failed. rc=%Rrc\n", rc));
1626
CORELOGRELSYS((CORELOG_NAME "ElfWriteNoteSection: Invalid type %d\n", enmType));
1627
rc = VERR_GENERAL_FAILURE;
1639
* Write mappings into the core file.
1641
* @param pVBoxCore Pointer to the core object.
1643
* @return IPRT status code.
1645
static int ElfWriteMappings(PVBOXCORE pVBoxCore)
1647
PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
1649
int rc = VERR_GENERAL_FAILURE;
1650
PVBOXSOLMAPINFO pMapInfo = pVBoxProc->pMapInfoHead;
1653
if (!pMapInfo->fError)
1656
char achBuf[PAGE_SIZE];
1657
while (k < pMapInfo->pMap.pr_size)
1659
size_t cb = RT_MIN(sizeof(achBuf), pMapInfo->pMap.pr_size - k);
1660
int rc2 = ProcReadAddrSpace(pVBoxProc, pMapInfo->pMap.pr_vaddr + k, &achBuf, cb);
1661
if (RT_FAILURE(rc2))
1663
CORELOGRELSYS((CORELOG_NAME "ElfWriteMappings: Failed to read mapping, can't recover. Bye. rc=%Rrc\n", rc));
1664
return VERR_INVALID_STATE;
1667
rc = pVBoxCore->pfnWriter(pVBoxCore->hCoreFile, achBuf, sizeof(achBuf));
1670
CORELOGRELSYS((CORELOG_NAME "ElfWriteMappings: pfnWriter failed. rc=%Rrc\n", rc));
1678
char achBuf[RT_ALIGN_Z(sizeof(int), 8)];
1680
memcpy(achBuf, &pMapInfo->fError, sizeof(pMapInfo->fError));
1681
if (sizeof(achBuf) != pMapInfo->pMap.pr_size)
1682
CORELOGRELSYS((CORELOG_NAME "ElfWriteMappings: Huh!? something is wrong!\n"));
1683
rc = pVBoxCore->pfnWriter(pVBoxCore->hCoreFile, &achBuf, sizeof(achBuf));
1686
CORELOGRELSYS((CORELOG_NAME "ElfWriteMappings: pfnWriter(2) failed. rc=%Rrc\n", rc));
1691
pMapInfo = pMapInfo->pNext;
1694
return VINF_SUCCESS;
1699
* Write program headers for all mappings into the core file.
1701
* @param pVBoxCore Pointer to the core object.
1703
* @return IPRT status code.
1705
static int ElfWriteMappingHeaders(PVBOXCORE pVBoxCore)
1707
AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
1709
PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
1712
ProgHdr.p_type = PT_LOAD;
1714
int rc = VERR_GENERAL_FAILURE;
1715
PVBOXSOLMAPINFO pMapInfo = pVBoxProc->pMapInfoHead;
1718
ProgHdr.p_vaddr = pMapInfo->pMap.pr_vaddr; /* Virtual address of this mapping in the process address space */
1719
ProgHdr.p_offset = pVBoxCore->offWrite; /* Where this mapping is located in the core file */
1720
ProgHdr.p_memsz = pMapInfo->pMap.pr_size; /* Size of the memory image of the mapping */
1721
ProgHdr.p_filesz = pMapInfo->pMap.pr_size; /* Size of the file image of the mapping */
1723
ProgHdr.p_flags = 0; /* Reset fields in a loop when needed! */
1724
if (pMapInfo->pMap.pr_mflags & MA_READ)
1725
ProgHdr.p_flags |= PF_R;
1726
if (pMapInfo->pMap.pr_mflags & MA_WRITE)
1727
ProgHdr.p_flags |= PF_W;
1728
if (pMapInfo->pMap.pr_mflags & MA_EXEC)
1729
ProgHdr.p_flags |= PF_X;
1731
if (pMapInfo->fError)
1732
ProgHdr.p_flags |= PF_SUNW_FAILURE;
1734
rc = pVBoxCore->pfnWriter(pVBoxCore->hCoreFile, &ProgHdr, sizeof(ProgHdr));
1737
CORELOGRELSYS((CORELOG_NAME "ElfWriteMappingHeaders: pfnWriter failed. rc=%Rrc\n", rc));
1741
pVBoxCore->offWrite += ProgHdr.p_filesz;
1742
pMapInfo = pMapInfo->pNext;
1749
* Write a prepared core file using a user-passed in writer function, requires all threads
1750
* to be in suspended state (i.e. called after CreateCore).
1752
* @param pVBoxCore Pointer to the core object.
1753
* @param pfnWriter Pointer to the writer function to override default writer (NULL uses default).
1755
* @remarks Resumes all suspended threads, unless it's an invalid core.
1756
* @return VBox status.
1758
static int rtCoreDumperWriteCore(PVBOXCORE pVBoxCore, PFNCOREWRITER pfnWriter)
1760
AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
1762
if (!pVBoxCore->fIsValid)
1763
return VERR_INVALID_STATE;
1766
pVBoxCore->pfnWriter = pfnWriter;
1768
PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
1769
char szPath[PATH_MAX];
1772
* Open the process address space file.
1774
RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/as", (int)pVBoxProc->Process);
1775
int rc = RTFileOpen(&pVBoxProc->hAs, szPath, RTFILE_O_OPEN | RTFILE_O_READ);
1778
CORELOGRELSYS((CORELOG_NAME "WriteCore: Failed to open address space, %s. rc=%Rrc\n", szPath, rc));
1783
* Create the core file.
1785
rc = RTFileOpen(&pVBoxCore->hCoreFile, pVBoxCore->szCorePath,
1786
RTFILE_O_OPEN_CREATE | RTFILE_O_TRUNCATE | RTFILE_O_READWRITE | RTFILE_O_DENY_ALL);
1789
CORELOGRELSYS((CORELOG_NAME "WriteCore: failed to open %s. rc=%Rrc\n", pVBoxCore->szCorePath, rc));
1793
pVBoxCore->offWrite = 0;
1794
uint32_t cProgHdrs = pVBoxProc->cMappings + 2; /* two PT_NOTE program headers (old, new style) */
1797
* Write the ELF header.
1801
ElfHdr.e_ident[EI_MAG0] = ELFMAG0;
1802
ElfHdr.e_ident[EI_MAG1] = ELFMAG1;
1803
ElfHdr.e_ident[EI_MAG2] = ELFMAG2;
1804
ElfHdr.e_ident[EI_MAG3] = ELFMAG3;
1805
ElfHdr.e_ident[EI_DATA] = IsBigEndian() ? ELFDATA2MSB : ELFDATA2LSB;
1806
ElfHdr.e_type = ET_CORE;
1807
ElfHdr.e_version = EV_CURRENT;
1808
#ifdef RT_ARCH_AMD64
1809
ElfHdr.e_machine = EM_AMD64;
1810
ElfHdr.e_ident[EI_CLASS] = ELFCLASS64;
1812
ElfHdr.e_machine = EM_386;
1813
ElfHdr.e_ident[EI_CLASS] = ELFCLASS32;
1815
if (cProgHdrs >= PN_XNUM)
1816
ElfHdr.e_phnum = PN_XNUM;
1818
ElfHdr.e_phnum = cProgHdrs;
1819
ElfHdr.e_ehsize = sizeof(ElfHdr);
1820
ElfHdr.e_phoff = sizeof(ElfHdr);
1821
ElfHdr.e_phentsize = sizeof(Elf_Phdr);
1822
ElfHdr.e_shentsize = sizeof(Elf_Shdr);
1823
rc = pVBoxCore->pfnWriter(pVBoxCore->hCoreFile, &ElfHdr, sizeof(ElfHdr));
1826
CORELOGRELSYS((CORELOG_NAME "WriteCore: pfnWriter failed writing ELF header. rc=%Rrc\n", rc));
1831
* Setup program header.
1835
ProgHdr.p_type = PT_NOTE;
1836
ProgHdr.p_flags = PF_R;
1839
* Write old-style NOTE program header.
1841
pVBoxCore->offWrite += sizeof(ElfHdr) + cProgHdrs * sizeof(ProgHdr);
1842
ProgHdr.p_offset = pVBoxCore->offWrite;
1843
ProgHdr.p_filesz = ElfNoteSectionSize(pVBoxCore, enmOldEra);
1844
rc = pVBoxCore->pfnWriter(pVBoxCore->hCoreFile, &ProgHdr, sizeof(ProgHdr));
1847
CORELOGRELSYS((CORELOG_NAME "WriteCore: pfnWriter failed writing old-style ELF program Header. rc=%Rrc\n", rc));
1852
* Write new-style NOTE program header.
1854
pVBoxCore->offWrite += ProgHdr.p_filesz;
1855
ProgHdr.p_offset = pVBoxCore->offWrite;
1856
ProgHdr.p_filesz = ElfNoteSectionSize(pVBoxCore, enmNewEra);
1857
rc = pVBoxCore->pfnWriter(pVBoxCore->hCoreFile, &ProgHdr, sizeof(ProgHdr));
1860
CORELOGRELSYS((CORELOG_NAME "WriteCore: pfnWriter failed writing new-style ELF program header. rc=%Rrc\n", rc));
1865
* Write program headers per mapping.
1867
pVBoxCore->offWrite += ProgHdr.p_filesz;
1868
rc = ElfWriteMappingHeaders(pVBoxCore);
1871
CORELOGRELSYS((CORELOG_NAME "Write: ElfWriteMappings failed. rc=%Rrc\n", rc));
1876
* Write old-style note section.
1878
rc = ElfWriteNoteSection(pVBoxCore, enmOldEra);
1881
CORELOGRELSYS((CORELOG_NAME "WriteCore: ElfWriteNoteSection old-style failed. rc=%Rrc\n", rc));
1886
* Write new-style section.
1888
rc = ElfWriteNoteSection(pVBoxCore, enmNewEra);
1891
CORELOGRELSYS((CORELOG_NAME "WriteCore: ElfWriteNoteSection new-style failed. rc=%Rrc\n", rc));
1896
* Write all mappings.
1898
rc = ElfWriteMappings(pVBoxCore);
1901
CORELOGRELSYS((CORELOG_NAME "WriteCore: ElfWriteMappings failed. rc=%Rrc\n", rc));
1907
if (pVBoxCore->hCoreFile != NIL_RTFILE)
1909
RTFileClose(pVBoxCore->hCoreFile);
1910
pVBoxCore->hCoreFile = NIL_RTFILE;
1913
if (pVBoxProc->hAs != NIL_RTFILE)
1915
RTFileClose(pVBoxProc->hAs);
1916
pVBoxProc->hAs = NIL_RTFILE;
1919
rtCoreDumperResumeThreads(pVBoxCore);
1925
* Takes a process snapshot into a passed-in core object. It has the side-effect of halting
1926
* all threads which can lead to things like spurious wakeups of threads (if and when threads
1927
* are ultimately resumed en-masse) already suspended while calling this function.
1929
* @param pVBoxCore Pointer to a core object.
1930
* @param pContext Pointer to the caller context thread.
1931
* @param pszCoreFilePath Path to the core file. If NULL is passed, the global
1932
* path specified in RTCoreDumperSetup() would be used.
1934
* @remarks Halts all threads.
1935
* @return IPRT status code.
1937
static int rtCoreDumperCreateCore(PVBOXCORE pVBoxCore, ucontext_t *pContext, const char *pszCoreFilePath)
1939
AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
1940
AssertReturn(pContext, VERR_INVALID_POINTER);
1943
* Initialize core structures.
1945
memset(pVBoxCore, 0, sizeof(VBOXCORE));
1946
pVBoxCore->pfnReader = &ReadFileNoIntr;
1947
pVBoxCore->pfnWriter = &WriteFileNoIntr;
1948
pVBoxCore->fIsValid = false;
1949
pVBoxCore->hCoreFile = NIL_RTFILE;
1951
PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
1952
pVBoxProc->Process = RTProcSelf();
1953
pVBoxProc->hCurThread = _lwp_self(); /* thr_self() */
1954
pVBoxProc->hAs = NIL_RTFILE;
1955
pVBoxProc->pCurThreadCtx = pContext;
1956
pVBoxProc->CoreContent = CC_CONTENT_DEFAULT;
1958
RTProcGetExecutableName(pVBoxProc->szExecPath, sizeof(pVBoxProc->szExecPath)); /* this gets full path not just name */
1959
pVBoxProc->pszExecName = RTPathFilename(pVBoxProc->szExecPath);
1962
* If a path has been specified, use it. Otherwise use the global path.
1964
if (!pszCoreFilePath)
1967
* If no output directory is specified, use current directory.
1969
if (g_szCoreDumpDir[0] == '\0')
1970
g_szCoreDumpDir[0] = '.';
1972
if (g_szCoreDumpFile[0] == '\0')
1974
/* We cannot call RTPathAbs*() as they call getcwd() which calls malloc. */
1975
RTStrPrintf(pVBoxCore->szCorePath, sizeof(pVBoxCore->szCorePath), "%s/core.vb.%s.%d",
1976
g_szCoreDumpDir, pVBoxProc->pszExecName, (int)pVBoxProc->Process);
1979
RTStrPrintf(pVBoxCore->szCorePath, sizeof(pVBoxCore->szCorePath), "%s/core.vb.%s", g_szCoreDumpDir, g_szCoreDumpFile);
1982
RTStrCopy(pVBoxCore->szCorePath, sizeof(pVBoxCore->szCorePath), pszCoreFilePath);
1984
CORELOG((CORELOG_NAME "CreateCore: Taking Core %s from Thread %d\n", pVBoxCore->szCorePath, (int)pVBoxProc->hCurThread));
1987
* Quiesce the process.
1989
int rc = rtCoreDumperSuspendThreads(pVBoxCore);
1992
rc = ProcReadInfo(pVBoxCore);
1995
GetOldProcessInfo(pVBoxCore, &pVBoxProc->ProcInfoOld);
1996
if (IsProcessArchNative(pVBoxProc))
1999
* Read process status, information such as number of active LWPs will be invalid since we just quiesced the process.
2001
rc = ProcReadStatus(pVBoxCore);
2004
rc = AllocMemoryArea(pVBoxCore);
2007
struct COREACCUMULATOR
2009
const char *pszName;
2010
PFNCOREACCUMULATOR pfnAcc;
2014
{ "ProcReadLdt", &ProcReadLdt, false },
2015
{ "ProcReadCred", &ProcReadCred, false },
2016
{ "ProcReadPriv", &ProcReadPriv, false },
2017
{ "ProcReadAuxVecs", &ProcReadAuxVecs, false },
2018
{ "ProcReadMappings", &ProcReadMappings, false },
2019
{ "ProcReadThreads", &ProcReadThreads, false },
2020
{ "ProcReadMiscInfo", &ProcReadMiscInfo, false }
2023
for (unsigned i = 0; i < RT_ELEMENTS(aAccumulators); i++)
2025
rc = aAccumulators[i].pfnAcc(pVBoxCore);
2028
CORELOGRELSYS((CORELOG_NAME "CreateCore: %s failed. rc=%Rrc\n", aAccumulators[i].pszName, rc));
2029
if (!aAccumulators[i].fOptional)
2036
pVBoxCore->fIsValid = true;
2037
return VINF_SUCCESS;
2040
FreeMemoryArea(pVBoxCore);
2043
CORELOGRELSYS((CORELOG_NAME "CreateCore: AllocMemoryArea failed. rc=%Rrc\n", rc));
2046
CORELOGRELSYS((CORELOG_NAME "CreateCore: ProcReadStatus failed. rc=%Rrc\n", rc));
2050
CORELOGRELSYS((CORELOG_NAME "CreateCore: IsProcessArchNative failed.\n"));
2051
rc = VERR_BAD_EXE_FORMAT;
2055
CORELOGRELSYS((CORELOG_NAME "CreateCore: ProcReadInfo failed. rc=%Rrc\n", rc));
2058
* Resume threads on failure.
2060
rtCoreDumperResumeThreads(pVBoxCore);
2063
CORELOG((CORELOG_NAME "CreateCore: SuspendAllThreads failed. Thread bomb!?! rc=%Rrc\n", rc));
2070
* Destroy an existing core object.
2072
* @param pVBoxCore Pointer to the core object.
2074
* @return IPRT status code.
2076
static int rtCoreDumperDestroyCore(PVBOXCORE pVBoxCore)
2078
AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
2079
if (!pVBoxCore->fIsValid)
2080
return VERR_INVALID_STATE;
2082
FreeMemoryArea(pVBoxCore);
2083
pVBoxCore->fIsValid = false;
2084
return VINF_SUCCESS;
2089
* Takes a core dump. This function has no other parameters than the context
2090
* because it can be called from signal handlers.
2092
* @param pContext The context of the caller.
2093
* @param pszOutputFile Path of the core file. If NULL is passed, the
2094
* global path passed in RTCoreDumperSetup will
2096
* @returns IPRT status code.
2098
static int rtCoreDumperTakeDump(ucontext_t *pContext, const char *pszOutputFile)
2102
CORELOGRELSYS((CORELOG_NAME "TakeDump: Missing context.\n"));
2103
return VERR_INVALID_POINTER;
2107
* Take a snapshot, then dump core to disk, all threads except this one are halted
2108
* from before taking the snapshot until writing the core is completely finished.
2109
* Any errors would resume all threads if they were halted.
2113
int rc = rtCoreDumperCreateCore(&VBoxCore, pContext, pszOutputFile);
2116
rc = rtCoreDumperWriteCore(&VBoxCore, &WriteFileNoIntr);
2118
CORELOGRELSYS((CORELOG_NAME "Core dumped in %s\n", VBoxCore.szCorePath));
2120
CORELOGRELSYS((CORELOG_NAME "TakeDump: WriteCore failed. szCorePath=%s rc=%Rrc\n", VBoxCore.szCorePath, rc));
2122
rtCoreDumperDestroyCore(&VBoxCore);
2125
CORELOGRELSYS((CORELOG_NAME "TakeDump: CreateCore failed. rc=%Rrc\n", rc));
2132
* The signal handler that will be invoked to take core dumps.
2134
* @param Sig The signal that invoked us.
2135
* @param pSigInfo The signal information.
2136
* @param pvArg Opaque pointer to the caller context structure,
2137
* this cannot be NULL.
2139
static void rtCoreDumperSignalHandler(int Sig, siginfo_t *pSigInfo, void *pvArg)
2141
CORELOG((CORELOG_NAME "SignalHandler Sig=%d pvArg=%p\n", Sig, pvArg));
2143
RTNATIVETHREAD hCurNativeThread = RTThreadNativeSelf();
2144
int rc = VERR_GENERAL_FAILURE;
2145
bool fCallSystemDump = false;
2147
ASMAtomicCmpXchgHandle(&g_CoreDumpThread, hCurNativeThread, NIL_RTNATIVETHREAD, fRc);
2150
rc = rtCoreDumperTakeDump((ucontext_t *)pvArg, NULL /* Use Global Core filepath */);
2151
ASMAtomicWriteHandle(&g_CoreDumpThread, NIL_RTNATIVETHREAD);
2154
CORELOGRELSYS((CORELOG_NAME "TakeDump failed! rc=%Rrc\n", rc));
2156
else if (Sig == SIGSEGV || Sig == SIGBUS || Sig == SIGTRAP)
2159
* Core dumping is already in progress and we've somehow ended up being
2162
rc = VERR_INTERNAL_ERROR;
2165
* If our dumper has crashed. No point in waiting, trigger the system one.
2166
* Wait only when the dumping thread is not the one generating this signal.
2168
RTNATIVETHREAD hNativeDumperThread;
2169
ASMAtomicReadHandle(&g_CoreDumpThread, &hNativeDumperThread);
2170
if (hNativeDumperThread == RTThreadNativeSelf())
2172
CORELOGRELSYS((CORELOG_NAME "SignalHandler: Core dumper (thread %u) crashed Sig=%d. Triggering system dump\n",
2173
RTThreadSelf(), Sig));
2174
fCallSystemDump = true;
2179
* Some other thread in the process is triggering a crash, wait a while
2180
* to let our core dumper finish, on timeout trigger system dump.
2182
CORELOGRELSYS((CORELOG_NAME "SignalHandler: Core dump already in progress! Waiting a while for completion Sig=%d.\n", Sig));
2183
int64_t iTimeout = 16000; /* timeout (ms) */
2186
ASMAtomicReadHandle(&g_CoreDumpThread, &hNativeDumperThread);
2187
if (hNativeDumperThread == NIL_RTNATIVETHREAD)
2196
fCallSystemDump = true;
2197
CORELOGRELSYS((CORELOG_NAME "SignalHandler: Core dumper seems to be stuck. Signalling new signal %d\n", Sig));
2202
if (Sig == SIGSEGV || Sig == SIGBUS || Sig == SIGTRAP)
2205
* Reset signal handlers, we're not a live core we will be blown away
2206
* one way or another.
2208
signal(SIGSEGV, SIG_DFL);
2209
signal(SIGBUS, SIG_DFL);
2210
signal(SIGTRAP, SIG_DFL);
2213
* Hard terminate the process if this is not a live dump without invoking
2214
* the system core dumping behaviour.
2220
* Something went wrong, fall back to the system core dumper.
2222
if (fCallSystemDump)
2228
RTDECL(int) RTCoreDumperTakeDump(const char *pszOutputFile, bool fLiveCore)
2231
int rc = getcontext(&Context);
2235
* Block SIGSEGV and co. while we write the core.
2237
sigset_t SigSet, OldSigSet;
2238
sigemptyset(&SigSet);
2239
sigaddset(&SigSet, SIGSEGV);
2240
sigaddset(&SigSet, SIGBUS);
2241
sigaddset(&SigSet, SIGTRAP);
2242
sigaddset(&SigSet, SIGUSR2);
2243
pthread_sigmask(SIG_BLOCK, &SigSet, &OldSigSet);
2244
rc = rtCoreDumperTakeDump(&Context, pszOutputFile);
2246
CORELOGRELSYS(("RTCoreDumperTakeDump: rtCoreDumperTakeDump failed rc=%Rrc\n", rc));
2250
signal(SIGSEGV, SIG_DFL);
2251
signal(SIGBUS, SIG_DFL);
2252
signal(SIGTRAP, SIG_DFL);
2258
pthread_sigmask(SIG_SETMASK, &OldSigSet, NULL);
2262
CORELOGRELSYS(("RTCoreDumperTakeDump: getcontext failed rc=%d.\n", rc));
2263
rc = VERR_INVALID_CONTEXT;
2270
RTDECL(int) RTCoreDumperSetup(const char *pszOutputDir, uint32_t fFlags)
2275
AssertReturn(fFlags, VERR_INVALID_PARAMETER);
2276
AssertReturn(!(fFlags & ~( RTCOREDUMPER_FLAGS_REPLACE_SYSTEM_DUMP
2277
| RTCOREDUMPER_FLAGS_LIVE_CORE)),
2278
VERR_INVALID_PARAMETER);
2281
* Install core dump signal handler only if the flags changed or if it's the first time.
2283
if ( ASMAtomicReadBool(&g_fCoreDumpSignalSetup) == false
2284
|| ASMAtomicReadU32(&g_fCoreDumpFlags) != fFlags)
2286
struct sigaction sigAct;
2288
sigAct.sa_sigaction = &rtCoreDumperSignalHandler;
2290
if ( (fFlags & RTCOREDUMPER_FLAGS_REPLACE_SYSTEM_DUMP)
2291
&& !(g_fCoreDumpFlags & RTCOREDUMPER_FLAGS_REPLACE_SYSTEM_DUMP))
2293
sigemptyset(&sigAct.sa_mask);
2294
sigAct.sa_flags = SA_RESTART | SA_SIGINFO | SA_NODEFER;
2295
sigaction(SIGSEGV, &sigAct, NULL);
2296
sigaction(SIGBUS, &sigAct, NULL);
2297
sigaction(SIGTRAP, &sigAct, NULL);
2300
if ( fFlags & RTCOREDUMPER_FLAGS_LIVE_CORE
2301
&& !(g_fCoreDumpFlags & RTCOREDUMPER_FLAGS_LIVE_CORE))
2303
sigfillset(&sigAct.sa_mask); /* Block all signals while in it's signal handler */
2304
sigAct.sa_flags = SA_RESTART | SA_SIGINFO;
2305
sigaction(SIGUSR2, &sigAct, NULL);
2308
ASMAtomicWriteU32(&g_fCoreDumpFlags, fFlags);
2309
ASMAtomicWriteBool(&g_fCoreDumpSignalSetup, true);
2312
RT_ZERO(g_szCoreDumpDir);
2314
RTStrCopy(g_szCoreDumpDir, sizeof(g_szCoreDumpDir), pszOutputDir);
2316
return VINF_SUCCESS;
2320
RTDECL(int) RTCoreDumperDisable(void)
2323
* Remove core dump signal handler & reset variables.
2325
if (ASMAtomicReadBool(&g_fCoreDumpSignalSetup) == true)
2327
signal(SIGSEGV, SIG_DFL);
2328
signal(SIGBUS, SIG_DFL);
2329
signal(SIGTRAP, SIG_DFL);
2330
signal(SIGUSR2, SIG_DFL);
2331
ASMAtomicWriteBool(&g_fCoreDumpSignalSetup, false);
2334
RT_ZERO(g_szCoreDumpDir);
2335
RT_ZERO(g_szCoreDumpFile);
2336
ASMAtomicWriteU32(&g_fCoreDumpFlags, 0);
2337
return VINF_SUCCESS;