~ubuntu-branches/ubuntu/natty/virtualbox-ose/natty-updates

« back to all changes in this revision

Viewing changes to src/VBox/Runtime/r3/solaris/coredumper-solaris.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2010-10-15 02:12:28 UTC
  • mfrom: (0.3.10 upstream) (0.4.19 sid)
  • Revision ID: james.westby@ubuntu.com-20101015021228-5e6vbxgtes8mg189
Tags: 3.2.10-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - VirtualBox should go in Accessories, not in System tools.
    - debian/virtualbox-ose-qt.files/virtualbox-ose.desktop
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Add ubuntu-01-fix-build-gcc45.patch to fix FTBFS due to uninitalized
  variables. Thanks to Lubomir Rintel <lkundrak@v3.sk> for the patch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: coredumper-solaris.cpp $ */
 
2
/** @file
 
3
 * IPRT Testcase - Core Dumper.
 
4
 */
 
5
 
 
6
/*
 
7
 * Copyright (C) 2010 Oracle Corporation
 
8
 *
 
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.
 
16
 *
 
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.
 
22
 *
 
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.
 
25
 */
 
26
 
 
27
/*******************************************************************************
 
28
*   Header Files                                                               *
 
29
*******************************************************************************/
 
30
#define LOG_GROUP LOG_GROUP_CORE_DUMPER
 
31
#include <VBox/log.h>
 
32
#include <iprt/coredumper.h>
 
33
#include <iprt/types.h>
 
34
#include <iprt/file.h>
 
35
#include <iprt/err.h>
 
36
#include <iprt/dir.h>
 
37
#include <iprt/path.h>
 
38
#include <iprt/string.h>
 
39
#include <iprt/thread.h>
 
40
#include <iprt/param.h>
 
41
#include <iprt/asm.h>
 
42
#include "coredumper-solaris.h"
 
43
 
 
44
#ifdef RT_OS_SOLARIS
 
45
# include <syslog.h>
 
46
# include <signal.h>
 
47
# include <stdlib.h>
 
48
# include <unistd.h>
 
49
# include <errno.h>
 
50
# include <zone.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 */
 
57
 
 
58
#include "internal/ldrELF.h"
 
59
#include "internal/ldrELF64.h"
 
60
 
 
61
/*******************************************************************************
 
62
*   Globals                                                                    *
 
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 };
 
69
 
 
70
 
 
71
/*******************************************************************************
 
72
*   Defined Constants And Macros                                               *
 
73
*******************************************************************************/
 
74
#define CORELOG_NAME        "CoreDumper: "
 
75
#define CORELOG(a)          Log(a)
 
76
#define CORELOGRELSYS(a)       \
 
77
    do { \
 
78
        LogRel(a); \
 
79
        rtCoreDumperSysLogWrapper a; \
 
80
    } while (0)
 
81
 
 
82
 
 
83
/**
 
84
 * ELFNOTEHDR: ELF NOTE header.
 
85
 */
 
86
typedef struct ELFNOTEHDR
 
87
{
 
88
    Elf64_Nhdr                      Hdr;                        /* Header of NOTE section */
 
89
    char                            achName[8];                 /* Name of NOTE section */
 
90
} ELFNOTEHDR;
 
91
typedef ELFNOTEHDR *PELFNOTEHDR;
 
92
 
 
93
/**
 
94
 * Wrapper function to write IPRT format style string to the syslog.
 
95
 *
 
96
 * @param pszFormat         Format string
 
97
 */
 
98
static void rtCoreDumperSysLogWrapper(const char *pszFormat, ...)
 
99
{
 
100
    va_list va;
 
101
    va_start(va, pszFormat);
 
102
    char szBuf[1024];
 
103
    RTStrPrintfV(szBuf, sizeof(szBuf), pszFormat, va);
 
104
    va_end(va);
 
105
    syslog(LOG_ERR, "%s", szBuf);
 
106
}
 
107
 
 
108
 
 
109
/**
 
110
 * Determines endianness of the system. Just for completeness.
 
111
 *
 
112
 * @return Will return false if system is little endian, true otherwise.
 
113
 */
 
114
static bool IsBigEndian()
 
115
{
 
116
    const int i = 1;
 
117
    char *p = (char *)&i;
 
118
    if (p[0] == 1)
 
119
        return false;
 
120
    return true;
 
121
}
 
122
 
 
123
 
 
124
/**
 
125
 * Reads from a file making sure an interruption doesn't cause a failure.
 
126
 *
 
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.
 
130
 *
 
131
 * @return IPRT status code.
 
132
 */
 
133
static int ReadFileNoIntr(RTFILE hFile, void *pv, size_t cbToRead)
 
134
{
 
135
    int rc = VERR_READ_ERROR;
 
136
    while (1)
 
137
    {
 
138
        rc = RTFileRead(hFile, pv, cbToRead, NULL /* Read all */);
 
139
        if (rc == VERR_INTERRUPTED)
 
140
            continue;
 
141
        break;
 
142
    }
 
143
    return rc;
 
144
}
 
145
 
 
146
 
 
147
/**
 
148
 * Writes to a file making sure an interruption doesn't cause a failure.
 
149
 *
 
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.
 
153
 *
 
154
 * @return IPRT status code.
 
155
 */
 
156
static int WriteFileNoIntr(RTFILE hFile, const void *pcv, size_t cbToRead)
 
157
{
 
158
    int rc = VERR_READ_ERROR;
 
159
    while (1)
 
160
    {
 
161
        rc = RTFileWrite(hFile, pcv, cbToRead, NULL /* Write all */);
 
162
        if (rc == VERR_INTERRUPTED)
 
163
            continue;
 
164
        break;
 
165
    }
 
166
    return rc;
 
167
}
 
168
 
 
169
 
 
170
/**
 
171
 * Read from a given offet in the process' address space.
 
172
 *
 
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.
 
177
 *
 
178
 * @return VINF_SUCCESS, if all the given bytes was read in, otherwise VERR_READ_ERROR.
 
179
 */
 
180
static ssize_t ProcReadAddrSpace(PVBOXPROCESS pVBoxProc, RTFOFF off, void *pvBuf, size_t cbToRead)
 
181
{
 
182
    while (1)
 
183
    {
 
184
        int rc = RTFileReadAt(pVBoxProc->hAs, off, pvBuf, cbToRead, NULL);
 
185
        if (rc == VERR_INTERRUPTED)
 
186
            continue;
 
187
        return rc;
 
188
    }
 
189
}
 
190
 
 
191
 
 
192
/**
 
193
 * Determines if the current process' architecture is suitable for dumping core.
 
194
 *
 
195
 * @param pVBoxProc         Pointer to the VBox process.
 
196
 *
 
197
 * @return true if the architecture matches the current one.
 
198
 */
 
199
static inline bool IsProcessArchNative(PVBOXPROCESS pVBoxProc)
 
200
{
 
201
    return pVBoxProc->ProcInfo.pr_dmodel == PR_MODEL_NATIVE;
 
202
}
 
203
 
 
204
 
 
205
/**
 
206
 * Helper function to get the size of a file given it's path.
 
207
 *
 
208
 * @param pszPath           Pointer to the full path of the file.
 
209
 *
 
210
 * @return The size of the file in bytes.
 
211
 */
 
212
static size_t GetFileSize(const char *pszPath)
 
213
{
 
214
    uint64_t cb = 0;
 
215
    RTFILE hFile;
 
216
    int rc = RTFileOpen(&hFile, pszPath, RTFILE_O_OPEN | RTFILE_O_READ);
 
217
    if (RT_SUCCESS(rc))
 
218
    {
 
219
        RTFileGetSize(hFile, &cb);
 
220
        RTFileClose(hFile);
 
221
    }
 
222
    else
 
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;
 
225
}
 
226
 
 
227
 
 
228
/**
 
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.
 
232
 *
 
233
 * @param pVBoxCore         Pointer to the core object.
 
234
 *
 
235
 * @return IPRT status code.
 
236
 */
 
237
static int AllocMemoryArea(PVBOXCORE pVBoxCore)
 
238
{
 
239
    AssertReturn(pVBoxCore->pvCore == NULL, VERR_ALREADY_EXISTS);
 
240
 
 
241
    struct VBOXSOLPREALLOCTABLE
 
242
    {
 
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 },
 
255
    };
 
256
 
 
257
    size_t cb = 0;
 
258
    for (int i = 0; i < (int)RT_ELEMENTS(aPreAllocTable); i++)
 
259
    {
 
260
        char szPath[PATH_MAX];
 
261
        RTStrPrintf(szPath, sizeof(szPath), aPreAllocTable[i].pszFilePath, (int)pVBoxCore->VBoxProc.Process);
 
262
        size_t cbFile = GetFileSize(szPath);
 
263
        cb += cbFile;
 
264
        if (   cbFile > 0
 
265
            && aPreAllocTable[i].cbEntry > 0)
 
266
        {
 
267
            cb += ((cbFile - aPreAllocTable[i].cbHeader) / aPreAllocTable[i].cbEntry) * (aPreAllocTable[i].cbAccounting > 0 ?
 
268
                                                                                         aPreAllocTable[i].cbAccounting : 1);
 
269
            cb += aPreAllocTable[i].cbHeader;
 
270
        }
 
271
    }
 
272
 
 
273
    /*
 
274
     * Make room for our own mapping accountant entry which will also be included in the core.
 
275
     */
 
276
    cb += sizeof(VBOXSOLMAPINFO);
 
277
 
 
278
    /*
 
279
     * Allocate the required space, plus some extra room.
 
280
     */
 
281
    cb += _128K;
 
282
    void *pv = mmap(NULL, cb, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1 /* fd */, 0 /* offset */);
 
283
    if (pv != MAP_FAILED)
 
284
    {
 
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;
 
289
        return VINF_SUCCESS;
 
290
    }
 
291
    else
 
292
    {
 
293
        CORELOGRELSYS((CORELOG_NAME "AllocMemoryArea: failed cb=%u\n", cb));
 
294
        return VERR_NO_MEMORY;
 
295
    }
 
296
}
 
297
 
 
298
 
 
299
/**
 
300
 * Free memory area used by the core object.
 
301
 *
 
302
 * @param pVBoxCore         Pointer to the core object.
 
303
 */
 
304
static void FreeMemoryArea(PVBOXCORE pVBoxCore)
 
305
{
 
306
    AssertReturnVoid(pVBoxCore);
 
307
    AssertReturnVoid(pVBoxCore->pvCore);
 
308
    AssertReturnVoid(pVBoxCore->cbCore > 0);
 
309
 
 
310
    munmap(pVBoxCore->pvCore, pVBoxCore->cbCore);
 
311
    CORELOG((CORELOG_NAME "FreeMemoryArea: memory area of %u bytes freed.\n", pVBoxCore->cbCore));
 
312
 
 
313
    pVBoxCore->pvCore = NULL;
 
314
    pVBoxCore->pvFree= NULL;
 
315
    pVBoxCore->cbCore = 0;
 
316
}
 
317
 
 
318
 
 
319
/**
 
320
 * Get a chunk from the area of allocated memory.
 
321
 *
 
322
 * @param pVBoxCore         Pointer to the core object.
 
323
 * @param cb                Size of requested chunk.
 
324
 *
 
325
 * @return Pointer to allocated memory, or NULL on failure.
 
326
 */
 
327
static void *GetMemoryChunk(PVBOXCORE pVBoxCore, size_t cb)
 
328
{
 
329
    AssertReturn(pVBoxCore, NULL);
 
330
    AssertReturn(pVBoxCore->pvCore, NULL);
 
331
    AssertReturn(pVBoxCore->pvFree, NULL);
 
332
 
 
333
    size_t cbAllocated = (char *)pVBoxCore->pvFree - (char *)pVBoxCore->pvCore;
 
334
    if (cbAllocated < pVBoxCore->cbCore)
 
335
    {
 
336
        char *pb = (char *)pVBoxCore->pvFree;
 
337
        pVBoxCore->pvFree = pb + cb;
 
338
        return pb;
 
339
    }
 
340
 
 
341
    return NULL;
 
342
}
 
343
 
 
344
 
 
345
/**
 
346
 * Reads the proc file's content into a newly allocated buffer.
 
347
 *
 
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.
 
352
 *
 
353
 * @return IPRT status code.
 
354
 */
 
355
static int ProcReadFileInto(PVBOXCORE pVBoxCore, const char *pszProcFileName, void **ppv, size_t *pcb)
 
356
{
 
357
    AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
 
358
 
 
359
    char szPath[PATH_MAX];
 
360
    RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/%s", (int)pVBoxCore->VBoxProc.Process, pszProcFileName);
 
361
    RTFILE hFile;
 
362
    int rc = RTFileOpen(&hFile, szPath, RTFILE_O_OPEN | RTFILE_O_READ);
 
363
    if (RT_SUCCESS(rc))
 
364
    {
 
365
        uint64_t u64Size;
 
366
        RTFileGetSize(hFile, &u64Size);
 
367
        *pcb = u64Size < ~(size_t)0 ? u64Size : ~(size_t)0;
 
368
        if (*pcb > 0)
 
369
        {
 
370
            *ppv = GetMemoryChunk(pVBoxCore, *pcb);
 
371
            if (*ppv)
 
372
                rc = ReadFileNoIntr(hFile, *ppv, *pcb);
 
373
            else
 
374
                rc = VERR_NO_MEMORY;
 
375
        }
 
376
        else
 
377
        {
 
378
            *pcb =  0;
 
379
            *ppv = NULL;
 
380
        }
 
381
        RTFileClose(hFile);
 
382
    }
 
383
    else
 
384
        CORELOGRELSYS((CORELOG_NAME "ProcReadFileInto: failed to open %s. rc=%Rrc\n", szPath, rc));
 
385
    return rc;
 
386
}
 
387
 
 
388
 
 
389
/**
 
390
 * Read process information (format psinfo_t) from /proc.
 
391
 *
 
392
 * @param pVBoxCore         Pointer to the core object.
 
393
 *
 
394
 * @return IPRT status code.
 
395
 */
 
396
static int ProcReadInfo(PVBOXCORE pVBoxCore)
 
397
{
 
398
    AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
 
399
 
 
400
    PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
 
401
    char szPath[PATH_MAX];
 
402
    RTFILE hFile;
 
403
 
 
404
    RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/psinfo", (int)pVBoxProc->Process);
 
405
    int rc = RTFileOpen(&hFile, szPath, RTFILE_O_OPEN | RTFILE_O_READ);
 
406
    if (RT_SUCCESS(rc))
 
407
    {
 
408
        size_t cbProcInfo = sizeof(psinfo_t);
 
409
        rc = ReadFileNoIntr(hFile, &pVBoxProc->ProcInfo, cbProcInfo);
 
410
    }
 
411
 
 
412
    RTFileClose(hFile);
 
413
    return rc;
 
414
}
 
415
 
 
416
 
 
417
/**
 
418
 * Read process status (format pstatus_t) from /proc.
 
419
 *
 
420
 * @param pVBoxCore         Pointer to the core object.
 
421
 *
 
422
 * @return IPRT status code.
 
423
 */
 
424
static int ProcReadStatus(PVBOXCORE pVBoxCore)
 
425
{
 
426
    AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
 
427
 
 
428
    PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
 
429
 
 
430
    char szPath[PATH_MAX];
 
431
    RTFILE hFile;
 
432
 
 
433
    RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/status", (int)pVBoxProc->Process);
 
434
    int rc = RTFileOpen(&hFile, szPath, RTFILE_O_OPEN | RTFILE_O_READ);
 
435
    if (RT_SUCCESS(rc))
 
436
    {
 
437
        size_t cbRead;
 
438
        size_t cbProcStatus = sizeof(pstatus_t);
 
439
        AssertCompile(sizeof(pstatus_t) == sizeof(pVBoxProc->ProcStatus));
 
440
        rc = ReadFileNoIntr(hFile, &pVBoxProc->ProcStatus, cbProcStatus);
 
441
    }
 
442
    RTFileClose(hFile);
 
443
    return rc;
 
444
}
 
445
 
 
446
 
 
447
/**
 
448
 * Read process credential information (format prcred_t + array of guid_t)
 
449
 *
 
450
 * @param pVBoxCore         Pointer to the core object.
 
451
 *
 
452
 * @remarks Should not be called before successful call to @see AllocMemoryArea()
 
453
 * @return IPRT status code.
 
454
 */
 
455
static int ProcReadCred(PVBOXCORE pVBoxCore)
 
456
{
 
457
    AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
 
458
 
 
459
    PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
 
460
    return ProcReadFileInto(pVBoxCore, "cred", &pVBoxProc->pvCred, &pVBoxProc->cbCred);
 
461
}
 
462
 
 
463
 
 
464
/**
 
465
 * Read process privilege information (format prpriv_t + array of priv_chunk_t)
 
466
 *
 
467
 * @param pVBoxCore         Pointer to the core object.
 
468
 *
 
469
 * @remarks Should not be called before successful call to @see AllocMemoryArea()
 
470
 * @return IPRT status code.
 
471
 */
 
472
static int ProcReadPriv(PVBOXCORE pVBoxCore)
 
473
{
 
474
    AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
 
475
 
 
476
    PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
 
477
    int rc = ProcReadFileInto(pVBoxCore, "priv", (void **)&pVBoxProc->pPriv, &pVBoxProc->cbPriv);
 
478
    if (RT_FAILURE(rc))
 
479
        return rc;
 
480
    pVBoxProc->pcPrivImpl = getprivimplinfo();
 
481
    if (!pVBoxProc->pcPrivImpl)
 
482
    {
 
483
        CORELOGRELSYS((CORELOG_NAME "ProcReadPriv: getprivimplinfo returned NULL.\n"));
 
484
        return VERR_INVALID_STATE;
 
485
    }
 
486
    return rc;
 
487
}
 
488
 
 
489
 
 
490
/**
 
491
 * Read process LDT information (format array of struct ssd) from /proc.
 
492
 *
 
493
 * @param pVBoxProc         Pointer to the core object.
 
494
 *
 
495
 * @remarks Should not be called before successful call to @see AllocMemoryArea()
 
496
 * @return IPRT status code.
 
497
 */
 
498
static int ProcReadLdt(PVBOXCORE pVBoxCore)
 
499
{
 
500
    AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
 
501
 
 
502
    PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
 
503
    return ProcReadFileInto(pVBoxCore, "ldt", &pVBoxProc->pvLdt, &pVBoxProc->cbLdt);
 
504
}
 
505
 
 
506
 
 
507
/**
 
508
 * Read process auxiliary vectors (format auxv_t) for the process.
 
509
 *
 
510
 * @param pVBoxCore         Pointer to the core object.
 
511
 *
 
512
 * @remarks Should not be called before successful call to @see AllocMemoryArea()
 
513
 * @return IPRT status code.
 
514
 */
 
515
static int ProcReadAuxVecs(PVBOXCORE pVBoxCore)
 
516
{
 
517
    AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
 
518
 
 
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);
 
524
    if (RT_FAILURE(rc))
 
525
    {
 
526
        CORELOGRELSYS((CORELOG_NAME "ProcReadAuxVecs: RTFileOpen %s failed rc=%Rrc\n", szPath, rc));
 
527
        return rc;
 
528
    }
 
529
 
 
530
    uint64_t u64Size;
 
531
    RTFileGetSize(hFile, &u64Size);
 
532
    size_t cbAuxFile = u64Size < ~(size_t)0 ? u64Size : ~(size_t)0;
 
533
    if (cbAuxFile >= sizeof(auxv_t))
 
534
    {
 
535
        pVBoxProc->pAuxVecs = (auxv_t*)GetMemoryChunk(pVBoxCore, cbAuxFile + sizeof(auxv_t));
 
536
        if (pVBoxProc->pAuxVecs)
 
537
        {
 
538
            rc = ReadFileNoIntr(hFile, pVBoxProc->pAuxVecs, cbAuxFile);
 
539
            if (RT_SUCCESS(rc))
 
540
            {
 
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)
 
546
                {
 
547
                    pVBoxProc->pAuxVecs[pVBoxProc->cAuxVecs].a_type = AT_NULL;
 
548
                    pVBoxProc->pAuxVecs[pVBoxProc->cAuxVecs].a_un.a_val = 0L;
 
549
                    RTFileClose(hFile);
 
550
                    return VINF_SUCCESS;
 
551
                }
 
552
                else
 
553
                {
 
554
                    CORELOGRELSYS((CORELOG_NAME "ProcReadAuxVecs: Invalid vector count %u\n", pVBoxProc->cAuxVecs));
 
555
                    rc = VERR_READ_ERROR;
 
556
                }
 
557
            }
 
558
            else
 
559
                CORELOGRELSYS((CORELOG_NAME "ProcReadAuxVecs: ReadFileNoIntr failed. rc=%Rrc cbAuxFile=%u\n", rc, cbAuxFile));
 
560
 
 
561
            pVBoxProc->pAuxVecs = NULL;
 
562
            pVBoxProc->cAuxVecs = 0;
 
563
        }
 
564
        else
 
565
        {
 
566
            CORELOGRELSYS((CORELOG_NAME "ProcReadAuxVecs: no memory for %u bytes\n", cbAuxFile + sizeof(auxv_t)));
 
567
            rc = VERR_NO_MEMORY;
 
568
        }
 
569
    }
 
570
    else
 
571
        CORELOGRELSYS((CORELOG_NAME "ProcReadAuxVecs: aux file too small %u, expecting %u or more\n", cbAuxFile, sizeof(auxv_t)));
 
572
 
 
573
    RTFileClose(hFile);
 
574
    return rc;
 
575
}
 
576
 
 
577
 
 
578
/*
 
579
 * Find an element in the process' auxiliary vector.
 
580
 */
 
581
static long GetAuxVal(PVBOXPROCESS pVBoxProc, int Type)
 
582
{
 
583
    AssertReturn(pVBoxProc, -1);
 
584
    if (pVBoxProc->pAuxVecs)
 
585
    {
 
586
        auxv_t *pAuxVec = pVBoxProc->pAuxVecs;
 
587
        for (; pAuxVec->a_type != AT_NULL; pAuxVec++)
 
588
        {
 
589
            if (pAuxVec->a_type == Type)
 
590
                return pAuxVec->a_un.a_val;
 
591
        }
 
592
    }
 
593
    return -1;
 
594
}
 
595
 
 
596
 
 
597
/**
 
598
 * Read the process mappings (format prmap_t array).
 
599
 *
 
600
 * @param   pVBoxCore           Pointer to the core object.
 
601
 *
 
602
 * @remarks Should not be called before successful call to @see AllocMemoryArea()
 
603
 * @return IPRT status code.
 
604
 */
 
605
static int ProcReadMappings(PVBOXCORE pVBoxCore)
 
606
{
 
607
    AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
 
608
 
 
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);
 
614
    if (RT_FAILURE(rc))
 
615
        return rc;
 
616
 
 
617
    RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/as", (int)pVBoxProc->Process);
 
618
    rc = RTFileOpen(&pVBoxProc->hAs, szPath, RTFILE_O_OPEN | RTFILE_O_READ);
 
619
    if (RT_SUCCESS(rc))
 
620
    {
 
621
        /*
 
622
         * Allocate and read all the prmap_t objects from proc.
 
623
         */
 
624
        uint64_t u64Size;
 
625
        RTFileGetSize(hFile, &u64Size);
 
626
        size_t cbMapFile = u64Size < ~(size_t)0 ? u64Size : ~(size_t)0;
 
627
        if (cbMapFile >= sizeof(prmap_t))
 
628
        {
 
629
            prmap_t *pMap = (prmap_t*)GetMemoryChunk(pVBoxCore, cbMapFile);
 
630
            if (pMap)
 
631
            {
 
632
                rc = ReadFileNoIntr(hFile, pMap, cbMapFile);
 
633
                if (RT_SUCCESS(rc))
 
634
                {
 
635
                    pVBoxProc->cMappings = cbMapFile / sizeof(prmap_t);
 
636
                    if (pVBoxProc->cMappings > 0)
 
637
                    {
 
638
                        /*
 
639
                         * Allocate for each prmap_t object, a corresponding VBOXSOLMAPINFO object.
 
640
                         */
 
641
                        pVBoxProc->pMapInfoHead = (PVBOXSOLMAPINFO)GetMemoryChunk(pVBoxCore, pVBoxProc->cMappings * sizeof(VBOXSOLMAPINFO));
 
642
                        if (pVBoxProc->pMapInfoHead)
 
643
                        {
 
644
                            /*
 
645
                             * Associate the prmap_t with the mapping info object.
 
646
                             */
 
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++)
 
651
                            {
 
652
                                memcpy(&pCur->pMap, pMap, sizeof(pCur->pMap));
 
653
                                if (pPrev)
 
654
                                    pPrev->pNext = pCur;
 
655
 
 
656
                                pCur->fError = 0;
 
657
 
 
658
                                /*
 
659
                                 * Make sure we can read the mapping, otherwise mark them to be skipped.
 
660
                                 */
 
661
                                char achBuf[PAGE_SIZE];
 
662
                                uint64_t k = 0;
 
663
                                while (k < pCur->pMap.pr_size)
 
664
                                {
 
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);
 
667
                                    if (RT_FAILURE(rc2))
 
668
                                    {
 
669
                                        CORELOGRELSYS((CORELOG_NAME "ProcReadMappings: skipping mapping. vaddr=%#x rc=%Rrc\n",
 
670
                                                       pCur->pMap.pr_vaddr, rc2));
 
671
 
 
672
                                        /*
 
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.
 
676
                                         */
 
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;
 
681
                                        break;
 
682
                                    }
 
683
                                    k += cb;
 
684
                                }
 
685
 
 
686
                                pPrev = pCur;
 
687
                            }
 
688
                            if (pPrev)
 
689
                                pPrev->pNext = NULL;
 
690
 
 
691
                            RTFileClose(hFile);
 
692
                            RTFileClose(pVBoxProc->hAs);
 
693
                            pVBoxProc->hAs = NIL_RTFILE;
 
694
                            CORELOG((CORELOG_NAME "ProcReadMappings: successfully read in %u mappings\n", pVBoxProc->cMappings));
 
695
                            return VINF_SUCCESS;
 
696
                        }
 
697
                        else
 
698
                        {
 
699
                            CORELOGRELSYS((CORELOG_NAME "ProcReadMappings: GetMemoryChunk failed %u\n",
 
700
                                           pVBoxProc->cMappings * sizeof(VBOXSOLMAPINFO)));
 
701
                            rc = VERR_NO_MEMORY;
 
702
                        }
 
703
                    }
 
704
                    else
 
705
                    {
 
706
                        CORELOGRELSYS((CORELOG_NAME "ProcReadMappings: Invalid mapping count %u\n", pVBoxProc->cMappings));
 
707
                        rc = VERR_READ_ERROR;
 
708
                    }
 
709
                }
 
710
                else
 
711
                    CORELOGRELSYS((CORELOG_NAME "ProcReadMappings: FileReadNoIntr failed. rc=%Rrc cbMapFile=%u\n", rc, cbMapFile));
 
712
            }
 
713
            else
 
714
            {
 
715
                CORELOGRELSYS((CORELOG_NAME "ProcReadMappings: GetMemoryChunk failed. cbMapFile=%u\n", cbMapFile));
 
716
                rc = VERR_NO_MEMORY;
 
717
            }
 
718
        }
 
719
 
 
720
        RTFileClose(pVBoxProc->hAs);
 
721
        pVBoxProc->hAs = NIL_RTFILE;
 
722
    }
 
723
    else
 
724
        CORELOGRELSYS((CORELOG_NAME "ProcReadMappings: failed to open %s. rc=%Rrc\n", szPath, rc));
 
725
 
 
726
    RTFileClose(hFile);
 
727
    return rc;
 
728
}
 
729
 
 
730
 
 
731
/**
 
732
 * Reads the thread information for all threads in the process.
 
733
 *
 
734
 * @param pVBoxCore         Pointer to the core object.
 
735
 *
 
736
 * @remarks Should not be called before successful call to @see AllocMemoryArea()
 
737
 * @return IPRT status code.
 
738
 */
 
739
static int ProcReadThreads(PVBOXCORE pVBoxCore)
 
740
{
 
741
    AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
 
742
 
 
743
    PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
 
744
    AssertReturn(pVBoxProc->pCurThreadCtx, VERR_NO_DATA);
 
745
 
 
746
    /*
 
747
     * Read the information for threads.
 
748
     * Format: prheader_t + array of lwpsinfo_t's.
 
749
     */
 
750
    size_t cbInfoHdrAndData;
 
751
    void *pvInfoHdr = NULL;
 
752
    int rc = ProcReadFileInto(pVBoxCore, "lpsinfo", &pvInfoHdr, &cbInfoHdrAndData);
 
753
    if (RT_SUCCESS(rc))
 
754
    {
 
755
        /*
 
756
         * Read the status of threads.
 
757
         * Format: prheader_t + array of lwpstatus_t's.
 
758
         */
 
759
        void *pvStatusHdr = NULL;
 
760
        size_t cbStatusHdrAndData;
 
761
        rc = ProcReadFileInto(pVBoxCore, "lstatus", &pvStatusHdr, &cbStatusHdrAndData);
 
762
        if (RT_SUCCESS(rc))
 
763
        {
 
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;
 
770
 
 
771
            CORELOG((CORELOG_NAME "ProcReadThreads: read info(%u) status(%u), threads:cInfo=%u cStatus=%u\n", cbInfoHdrAndData,
 
772
                        cbStatusHdrAndData, cInfo, cStatus));
 
773
 
 
774
            /*
 
775
             * Minor sanity size check (remember sizeof lwpstatus_t & lwpsinfo_t is <= size in file per entry).
 
776
             */
 
777
            if (   (cbStatusHdrAndData - sizeof(prheader_t)) % pStatusHdr->pr_entsize == 0
 
778
                && (cbInfoHdrAndData - sizeof(prheader_t)) % pInfoHdr->pr_entsize == 0)
 
779
            {
 
780
                /*
 
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.
 
783
                 */
 
784
                for (; cInfo != 0; cInfo--)
 
785
                {
 
786
                    if (pInfo->pr_sname != 'Z') /* zombie */
 
787
                    {
 
788
                        if (   cStatus == 0
 
789
                            || pStatus->pr_lwpid != pInfo->pr_lwpid)
 
790
                        {
 
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;
 
794
                            break;
 
795
                        }
 
796
                        pStatus = (lwpstatus_t *)((uintptr_t)pStatus + pStatusHdr->pr_entsize);
 
797
                        cStatus--;
 
798
                    }
 
799
                    pInfo = (lwpsinfo_t *)((uintptr_t)pInfo + pInfoHdr->pr_entsize);
 
800
                }
 
801
 
 
802
                if (RT_SUCCESS(rc))
 
803
                {
 
804
                    /*
 
805
                     * Threre can still be more lwpsinfo_t's than lwpstatus_t's, build the
 
806
                     * lists accordingly.
 
807
                     */
 
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;
 
812
 
 
813
                    size_t cbThreadInfo = RT_MAX(cStatus, cInfo) * sizeof(VBOXSOLTHREADINFO);
 
814
                    pVBoxProc->pThreadInfoHead = (PVBOXSOLTHREADINFO)GetMemoryChunk(pVBoxCore, cbThreadInfo);
 
815
                    if (pVBoxProc->pThreadInfoHead)
 
816
                    {
 
817
                        PVBOXSOLTHREADINFO pCur = pVBoxProc->pThreadInfoHead;
 
818
                        PVBOXSOLTHREADINFO pPrev = NULL;
 
819
                        for (uint64_t i = 0; i < cInfo; i++, pCur++)
 
820
                        {
 
821
                            pCur->Info = *pInfo;
 
822
                            if (   pInfo->pr_sname != 'Z'
 
823
                                && pInfo->pr_lwpid == pStatus->pr_lwpid)
 
824
                            {
 
825
                                /*
 
826
                                 * Adjust the context of the dumping thread to reflect the context
 
827
                                 * when the core dump got initiated before whatever signal caused it.
 
828
                                 */
 
829
                                if (   pStatus          /* noid droid */
 
830
                                    && pStatus->pr_lwpid == (id_t)pVBoxProc->hCurThread)
 
831
                                {
 
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));
 
836
 
 
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;
 
840
 
 
841
                                    CORELOG((CORELOG_NAME "ProcReadThreads: patched dumper thread context with pre-dump time context.\n"));
 
842
                                }
 
843
 
 
844
                                pCur->pStatus = pStatus;
 
845
                                pStatus = (lwpstatus_t *)((uintptr_t)pStatus + pStatusHdr->pr_entsize);
 
846
                            }
 
847
                            else
 
848
                            {
 
849
                                CORELOGRELSYS((CORELOG_NAME "ProcReadThreads: missing status for lwp %d\n", pInfo->pr_lwpid));
 
850
                                pCur->pStatus = NULL;
 
851
                            }
 
852
 
 
853
                            if (pPrev)
 
854
                                pPrev->pNext = pCur;
 
855
                            pPrev = pCur;
 
856
                            pInfo = (lwpsinfo_t *)((uintptr_t)pInfo + pInfoHdr->pr_entsize);
 
857
                        }
 
858
                        if (pPrev)
 
859
                            pPrev->pNext = NULL;
 
860
 
 
861
                        CORELOG((CORELOG_NAME "ProcReadThreads: successfully read %u threads.\n", cInfo));
 
862
                        pVBoxProc->cThreads = cInfo;
 
863
                        return VINF_SUCCESS;
 
864
                    }
 
865
                    else
 
866
                    {
 
867
                        CORELOGRELSYS((CORELOG_NAME "ProcReadThreads: GetMemoryChunk failed for %u bytes\n", cbThreadInfo));
 
868
                        rc = VERR_NO_MEMORY;
 
869
                    }
 
870
                }
 
871
                else
 
872
                    CORELOGRELSYS((CORELOG_NAME "ProcReadThreads: Invalid state information for threads.\n", rc));
 
873
            }
 
874
            else
 
875
            {
 
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;
 
881
            }
 
882
        }
 
883
        else
 
884
            CORELOGRELSYS((CORELOG_NAME "ProcReadThreads: ReadFileNoIntr failed for \"lpsinfo\" rc=%Rrc\n", rc));
 
885
    }
 
886
    else
 
887
        CORELOGRELSYS((CORELOG_NAME "ProcReadThreads: ReadFileNoIntr failed for \"lstatus\" rc=%Rrc\n", rc));
 
888
    return rc;
 
889
}
 
890
 
 
891
 
 
892
/**
 
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.
 
895
 *
 
896
 * @param pVBoxCore         Pointer to the core object.
 
897
 *
 
898
 * @return IPRT status code.
 
899
 */
 
900
static int ProcReadMiscInfo(PVBOXCORE pVBoxCore)
 
901
{
 
902
    AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
 
903
 
 
904
    PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
 
905
 
 
906
#ifdef RT_OS_SOLARIS
 
907
    /*
 
908
     * Read the platform name, uname string and zone name.
 
909
     */
 
910
    int rc = sysinfo(SI_PLATFORM, pVBoxProc->szPlatform, sizeof(pVBoxProc->szPlatform));
 
911
    if (rc == -1)
 
912
    {
 
913
        CORELOGRELSYS((CORELOG_NAME "ProcReadMiscInfo: sysinfo failed. rc=%d errno=%d\n", rc, errno));
 
914
        return VERR_GENERAL_FAILURE;
 
915
    }
 
916
    pVBoxProc->szPlatform[sizeof(pVBoxProc->szPlatform) - 1] = '\0';
 
917
 
 
918
    rc = uname(&pVBoxProc->UtsName);
 
919
    if (rc == -1)
 
920
    {
 
921
        CORELOGRELSYS((CORELOG_NAME "ProcReadMiscInfo: uname failed. rc=%d errno=%d\n", rc, errno));
 
922
        return VERR_GENERAL_FAILURE;
 
923
    }
 
924
 
 
925
    rc = getzonenamebyid(pVBoxProc->ProcInfo.pr_zoneid, pVBoxProc->szZoneName, sizeof(pVBoxProc->szZoneName));
 
926
    if (rc < 0)
 
927
    {
 
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;
 
931
    }
 
932
    pVBoxProc->szZoneName[sizeof(pVBoxProc->szZoneName) - 1] = '\0';
 
933
    rc = VINF_SUCCESS;
 
934
 
 
935
#else
 
936
# error Port Me!
 
937
#endif
 
938
    return rc;
 
939
}
 
940
 
 
941
 
 
942
/**
 
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.
 
945
 *
 
946
 * @param pVBoxCore         Pointer to the core object.
 
947
 * @param pInfo             Pointer to the old prpsinfo_t structure to update.
 
948
 */
 
949
static void GetOldProcessInfo(PVBOXCORE pVBoxCore, prpsinfo_t *pInfo)
 
950
{
 
951
    AssertReturnVoid(pVBoxCore);
 
952
    AssertReturnVoid(pInfo);
 
953
 
 
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;
 
995
}
 
996
 
 
997
 
 
998
/**
 
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.
 
1001
 *
 
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.
 
1006
 *
 
1007
 */
 
1008
static void GetOldProcessStatus(PVBOXCORE pVBoxCore, lwpsinfo_t *pInfo, lwpstatus_t *pStatus, prstatus_t *pDst)
 
1009
{
 
1010
    AssertReturnVoid(pVBoxCore);
 
1011
    AssertReturnVoid(pInfo);
 
1012
    AssertReturnVoid(pStatus);
 
1013
    AssertReturnVoid(pDst);
 
1014
 
 
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;
 
1048
 
 
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);
 
1064
 
 
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;
 
1079
 
 
1080
    pDst->pr_processor  = (short)pInfo->pr_onpro;
 
1081
    pDst->pr_bind       = (short)pInfo->pr_bindpro;
 
1082
    pDst->pr_instr      = pStatus->pr_instr;
 
1083
}
 
1084
 
 
1085
 
 
1086
/**
 
1087
 * Callback for rtCoreDumperForEachThread to suspend a thread.
 
1088
 *
 
1089
 * @param pVBoxCore             Pointer to the core object.
 
1090
 * @param pvThreadInfo          Opaque pointer to thread information.
 
1091
 *
 
1092
 * @return IPRT status code.
 
1093
 */
 
1094
static int suspendThread(PVBOXCORE pVBoxCore, void *pvThreadInfo)
 
1095
{
 
1096
    AssertPtrReturn(pvThreadInfo, VERR_INVALID_POINTER);
 
1097
    NOREF(pVBoxCore);
 
1098
 
 
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;
 
1104
}
 
1105
 
 
1106
 
 
1107
/**
 
1108
 * Callback for rtCoreDumperForEachThread to resume a thread.
 
1109
 *
 
1110
 * @param pVBoxCore             Pointer to the core object.
 
1111
 * @param pvThreadInfo          Opaque pointer to thread information.
 
1112
 *
 
1113
 * @return IPRT status code.
 
1114
 */
 
1115
static int resumeThread(PVBOXCORE pVBoxCore, void *pvThreadInfo)
 
1116
{
 
1117
    AssertPtrReturn(pvThreadInfo, VERR_INVALID_POINTER);
 
1118
    NOREF(pVBoxCore);
 
1119
 
 
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;
 
1125
}
 
1126
 
 
1127
 
 
1128
/**
 
1129
 * Calls a thread worker function for all threads in the process as described by /proc
 
1130
 *
 
1131
 * @param pVBoxCore             Pointer to the core object.
 
1132
 * @param pcThreads             Number of threads read.
 
1133
 * @param pfnWorker             Callback function for each thread.
 
1134
 *
 
1135
 * @return IPRT status code.
 
1136
 */
 
1137
static int rtCoreDumperForEachThread(PVBOXCORE pVBoxCore,  uint64_t *pcThreads, PFNCORETHREADWORKER pfnWorker)
 
1138
{
 
1139
    AssertPtrReturn(pVBoxCore, VERR_INVALID_POINTER);
 
1140
 
 
1141
    PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
 
1142
 
 
1143
    /*
 
1144
     * Read the information for threads.
 
1145
     * Format: prheader_t + array of lwpsinfo_t's.
 
1146
     */
 
1147
    char szLpsInfoPath[PATH_MAX];
 
1148
    RTStrPrintf(szLpsInfoPath, sizeof(szLpsInfoPath), "/proc/%d/lpsinfo", (int)pVBoxProc->Process);
 
1149
 
 
1150
    RTFILE hFile = NIL_RTFILE;
 
1151
    int rc = RTFileOpen(&hFile, szLpsInfoPath, RTFILE_O_READ);
 
1152
    if (RT_SUCCESS(rc))
 
1153
    {
 
1154
        uint64_t u64Size;
 
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)
 
1159
        {
 
1160
            rc = RTFileRead(hFile, pvInfoHdr, cbInfoHdrAndData, NULL);
 
1161
            if (RT_SUCCESS(rc))
 
1162
            {
 
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++)
 
1166
                {
 
1167
                    pfnWorker(pVBoxCore, pThreadInfo);
 
1168
                    pThreadInfo = (lwpsinfo_t *)((uintptr_t)pThreadInfo + pHeader->pr_entsize);
 
1169
                }
 
1170
                if (pcThreads)
 
1171
                    *pcThreads = pHeader->pr_nent;
 
1172
            }
 
1173
 
 
1174
            munmap(pvInfoHdr, cbInfoHdrAndData);
 
1175
        }
 
1176
        else
 
1177
            rc = VERR_NO_MEMORY;
 
1178
        RTFileClose(hFile);
 
1179
    }
 
1180
 
 
1181
    return rc;
 
1182
}
 
1183
 
 
1184
 
 
1185
/**
 
1186
 * Resume all threads of this process.
 
1187
 *
 
1188
 * @param pVBoxCore             Pointer to the core object.
 
1189
 *
 
1190
 * @return IPRT status code..
 
1191
 */
 
1192
static int rtCoreDumperResumeThreads(PVBOXCORE pVBoxCore)
 
1193
{
 
1194
    AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
 
1195
 
 
1196
#if 1
 
1197
    uint64_t cThreads;
 
1198
    return rtCoreDumperForEachThread(pVBoxCore, &cThreads, resumeThread);
 
1199
#else
 
1200
    PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
 
1201
 
 
1202
    char szCurThread[128];
 
1203
    char szPath[PATH_MAX];
 
1204
    PRTDIR pDir = NULL;
 
1205
 
 
1206
    RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/lwp", (int)pVBoxProc->Process);
 
1207
    RTStrPrintf(szCurThread, sizeof(szCurThread), "%d", (int)pVBoxProc->hCurThread);
 
1208
 
 
1209
    int32_t cRunningThreads = 0;
 
1210
    int rc = RTDirOpen(&pDir, szPath);
 
1211
    if (RT_SUCCESS(rc))
 
1212
    {
 
1213
        /*
 
1214
         * Loop through all our threads & resume them.
 
1215
         */
 
1216
        RTDIRENTRY DirEntry;
 
1217
        while (RT_SUCCESS(RTDirRead(pDir, &DirEntry, NULL)))
 
1218
        {
 
1219
            if (   !strcmp(DirEntry.szName, ".")
 
1220
                || !strcmp(DirEntry.szName, ".."))
 
1221
                continue;
 
1222
 
 
1223
            if ( !strcmp(DirEntry.szName, szCurThread))
 
1224
                continue;
 
1225
 
 
1226
            int32_t ThreadId = RTStrToInt32(DirEntry.szName);
 
1227
            _lwp_continue((lwpid_t)ThreadId);
 
1228
            ++cRunningThreads;
 
1229
        }
 
1230
 
 
1231
        CORELOG((CORELOG_NAME "ResumeAllThreads: resumed %d threads\n", cRunningThreads));
 
1232
        RTDirClose(pDir);
 
1233
    }
 
1234
    else
 
1235
    {
 
1236
        CORELOGRELSYS((CORELOG_NAME "ResumeAllThreads: Failed to open %s\n", szPath));
 
1237
        rc = VERR_READ_ERROR;
 
1238
    }
 
1239
    return rc;
 
1240
#endif
 
1241
}
 
1242
 
 
1243
 
 
1244
/**
 
1245
 * Stop all running threads of this process except the current one.
 
1246
 *
 
1247
 * @param pVBoxCore         Pointer to the core object.
 
1248
 *
 
1249
 * @return IPRT status code.
 
1250
 */
 
1251
static int rtCoreDumperSuspendThreads(PVBOXCORE pVBoxCore)
 
1252
{
 
1253
    AssertPtrReturn(pVBoxCore, VERR_INVALID_POINTER);
 
1254
 
 
1255
    /*
 
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.
 
1259
     */
 
1260
#if 1
 
1261
    uint16_t cTries = 0;
 
1262
    uint64_t aThreads[4];
 
1263
    RT_ZERO(aThreads);
 
1264
    int rc = VERR_GENERAL_FAILURE;
 
1265
    void *pv = NULL;
 
1266
    size_t cb = 0;
 
1267
    for (cTries = 0; cTries < RT_ELEMENTS(aThreads); cTries++)
 
1268
    {
 
1269
        rc = rtCoreDumperForEachThread(pVBoxCore, &aThreads[cTries], suspendThread);
 
1270
        if (RT_FAILURE(rc))
 
1271
            break;
 
1272
    }
 
1273
    if (   RT_SUCCESS(rc)
 
1274
        && aThreads[cTries - 1] != aThreads[cTries - 2])
 
1275
    {
 
1276
        CORELOGRELSYS((CORELOG_NAME "rtCoreDumperSuspendThreads: possible thread bomb!?\n"));
 
1277
        rc = VERR_TIMEOUT;
 
1278
    }
 
1279
    return rc;
 
1280
#else
 
1281
    PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
 
1282
 
 
1283
    char szCurThread[128];
 
1284
    char szPath[PATH_MAX];
 
1285
    PRTDIR pDir = NULL;
 
1286
 
 
1287
    RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/lwp", (int)pVBoxProc->Process);
 
1288
    RTStrPrintf(szCurThread, sizeof(szCurThread), "%d", (int)pVBoxProc->hCurThread);
 
1289
 
 
1290
    int rc = -1;
 
1291
    uint32_t cThreads = 0;
 
1292
    uint16_t cTries = 0;
 
1293
    for (cTries = 0; cTries < 10; cTries++)
 
1294
    {
 
1295
        uint32_t cRunningThreads = 0;
 
1296
        rc = RTDirOpen(&pDir, szPath);
 
1297
        if (RT_SUCCESS(rc))
 
1298
        {
 
1299
            /*
 
1300
             * Loop through all our threads & suspend them, multiple calls to _lwp_suspend() are okay.
 
1301
             */
 
1302
            RTDIRENTRY DirEntry;
 
1303
            while (RT_SUCCESS(RTDirRead(pDir, &DirEntry, NULL)))
 
1304
            {
 
1305
                if (   !strcmp(DirEntry.szName, ".")
 
1306
                    || !strcmp(DirEntry.szName, ".."))
 
1307
                    continue;
 
1308
 
 
1309
                if ( !strcmp(DirEntry.szName, szCurThread))
 
1310
                    continue;
 
1311
 
 
1312
                int32_t ThreadId = RTStrToInt32(DirEntry.szName);
 
1313
                _lwp_suspend((lwpid_t)ThreadId);
 
1314
                ++cRunningThreads;
 
1315
            }
 
1316
 
 
1317
            if (cTries > 5 && cThreads == cRunningThreads)
 
1318
            {
 
1319
                rc = VINF_SUCCESS;
 
1320
                break;
 
1321
            }
 
1322
            cThreads = cRunningThreads;
 
1323
            RTDirClose(pDir);
 
1324
        }
 
1325
        else
 
1326
        {
 
1327
            CORELOGRELSYS((CORELOG_NAME "SuspendThreads: Failed to open %s cTries=%d\n", szPath, cTries));
 
1328
            rc = VERR_READ_ERROR;
 
1329
            break;
 
1330
        }
 
1331
    }
 
1332
 
 
1333
    if (RT_SUCCESS(rc))
 
1334
        CORELOG((CORELOG_NAME "SuspendThreads: Stopped %u threads successfully with %u tries\n", cThreads, cTries));
 
1335
 
 
1336
    return rc;
 
1337
#endif
 
1338
}
 
1339
 
 
1340
 
 
1341
/**
 
1342
 * Returns size of an ELF NOTE header given the size of data the NOTE section will contain.
 
1343
 *
 
1344
 * @param cb                Size of the data.
 
1345
 *
 
1346
 * @return Size of data actually used for NOTE header and section.
 
1347
 */
 
1348
static inline size_t ElfNoteHeaderSize(size_t cb)
 
1349
{
 
1350
    return sizeof(ELFNOTEHDR) + RT_ALIGN_Z(cb, 4);
 
1351
}
 
1352
 
 
1353
 
 
1354
/**
 
1355
 * Write an ELF NOTE header into the core file.
 
1356
 *
 
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.
 
1361
 *
 
1362
 * @return IPRT status code.
 
1363
 */
 
1364
static int ElfWriteNoteHeader(PVBOXCORE pVBoxCore, uint_t Type, const void *pcv, size_t cb)
 
1365
{
 
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);
 
1371
 
 
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';
 
1380
 
 
1381
    /*
 
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.
 
1384
     */
 
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;
 
1390
 
 
1391
    /*
 
1392
     * Write note header and description.
 
1393
     */
 
1394
    rc = pVBoxCore->pfnWriter(pVBoxCore->hCoreFile, &ElfNoteHdr, sizeof(ElfNoteHdr));
 
1395
    if (RT_SUCCESS(rc))
 
1396
    {
 
1397
       rc = pVBoxCore->pfnWriter(pVBoxCore->hCoreFile, pcv, cb);
 
1398
       if (RT_SUCCESS(rc))
 
1399
       {
 
1400
           if (cbAlign > cb)
 
1401
               rc = pVBoxCore->pfnWriter(pVBoxCore->hCoreFile, s_achPad, cbAlign - cb);
 
1402
       }
 
1403
    }
 
1404
 
 
1405
    if (RT_FAILURE(rc))
 
1406
        CORELOGRELSYS((CORELOG_NAME "ElfWriteNote: pfnWriter failed. Type=%d rc=%Rrc\n", Type, rc));
 
1407
#else
 
1408
#error Port Me!
 
1409
#endif
 
1410
    return rc;
 
1411
}
 
1412
 
 
1413
 
 
1414
/**
 
1415
 * Computes the size of NOTE section for the given core type.
 
1416
 * Solaris has two types of program header information (new and old).
 
1417
 *
 
1418
 * @param pVBoxCore         Pointer to the core object.
 
1419
 * @param enmType           Type of core file information required.
 
1420
 *
 
1421
 * @return Size of NOTE section.
 
1422
 */
 
1423
static size_t ElfNoteSectionSize(PVBOXCORE pVBoxCore, VBOXSOLCORETYPE enmType)
 
1424
{
 
1425
    PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
 
1426
    size_t cb = 0;
 
1427
    switch (enmType)
 
1428
    {
 
1429
        case enmOldEra:
 
1430
        {
 
1431
            cb += ElfNoteHeaderSize(sizeof(prpsinfo_t));
 
1432
            cb += ElfNoteHeaderSize(pVBoxProc->cAuxVecs * sizeof(auxv_t));
 
1433
            cb += ElfNoteHeaderSize(strlen(pVBoxProc->szPlatform));
 
1434
 
 
1435
            PVBOXSOLTHREADINFO pThreadInfo = pVBoxProc->pThreadInfoHead;
 
1436
            while (pThreadInfo)
 
1437
            {
 
1438
                if (pThreadInfo->pStatus)
 
1439
                {
 
1440
                    cb += ElfNoteHeaderSize(sizeof(prstatus_t));
 
1441
                    cb += ElfNoteHeaderSize(sizeof(prfpregset_t));
 
1442
                }
 
1443
                pThreadInfo = pThreadInfo->pNext;
 
1444
            }
 
1445
 
 
1446
            break;
 
1447
        }
 
1448
 
 
1449
        case enmNewEra:
 
1450
        {
 
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);
 
1458
 
 
1459
            if (pVBoxProc->pPriv)
 
1460
                cb += ElfNoteHeaderSize(PRIV_PRPRIV_SIZE(pVBoxProc->pPriv));   /* Ought to be same as cbPriv!? */
 
1461
 
 
1462
            if (pVBoxProc->pcPrivImpl)
 
1463
                cb += ElfNoteHeaderSize(PRIV_IMPL_INFO_SIZE(pVBoxProc->pcPrivImpl));
 
1464
 
 
1465
            cb += ElfNoteHeaderSize(strlen(pVBoxProc->szZoneName) + 1);
 
1466
            if (pVBoxProc->cbLdt > 0)
 
1467
                cb += ElfNoteHeaderSize(pVBoxProc->cbLdt);
 
1468
 
 
1469
            PVBOXSOLTHREADINFO pThreadInfo = pVBoxProc->pThreadInfoHead;
 
1470
            while (pThreadInfo)
 
1471
            {
 
1472
                cb += ElfNoteHeaderSize(sizeof(lwpsinfo_t));
 
1473
                if (pThreadInfo->pStatus)
 
1474
                    cb += ElfNoteHeaderSize(sizeof(lwpstatus_t));
 
1475
 
 
1476
                pThreadInfo = pThreadInfo->pNext;
 
1477
            }
 
1478
 
 
1479
            break;
 
1480
        }
 
1481
 
 
1482
        default:
 
1483
        {
 
1484
            CORELOGRELSYS((CORELOG_NAME "ElfNoteSectionSize: Unknown segment era %d\n", enmType));
 
1485
            break;
 
1486
        }
 
1487
    }
 
1488
 
 
1489
    return cb;
 
1490
}
 
1491
 
 
1492
 
 
1493
/**
 
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).
 
1496
 *
 
1497
 * @param pVBoxCore         Pointer to the core object.
 
1498
 * @param enmType           Type of core file information required.
 
1499
 *
 
1500
 * @return IPRT status code.
 
1501
 */
 
1502
static int ElfWriteNoteSection(PVBOXCORE pVBoxCore, VBOXSOLCORETYPE enmType)
 
1503
{
 
1504
    AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
 
1505
 
 
1506
    PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
 
1507
    int rc = VERR_GENERAL_FAILURE;
 
1508
 
 
1509
#ifdef RT_OS_SOLARIS
 
1510
    typedef int (*PFNELFWRITENOTEHDR)(PVBOXCORE pVBoxCore, uint_t, const void *pcv, size_t cb);
 
1511
    typedef struct ELFWRITENOTE
 
1512
    {
 
1513
        const char        *pszType;
 
1514
        uint_t             Type;
 
1515
        const void        *pcv;
 
1516
        size_t             cb;
 
1517
    } ELFWRITENOTE;
 
1518
 
 
1519
    switch (enmType)
 
1520
    {
 
1521
        case enmOldEra:
 
1522
        {
 
1523
            ELFWRITENOTE aElfNotes[] =
 
1524
            {
 
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 }
 
1528
            };
 
1529
 
 
1530
            for (unsigned i = 0; i < RT_ELEMENTS(aElfNotes); i++)
 
1531
            {
 
1532
                rc = ElfWriteNoteHeader(pVBoxCore, aElfNotes[i].Type, aElfNotes[i].pcv, aElfNotes[i].cb);
 
1533
                if (RT_FAILURE(rc))
 
1534
                {
 
1535
                    CORELOGRELSYS((CORELOG_NAME "ElfWriteNoteSection: ElfWriteNoteHeader failed for %s. rc=%Rrc\n", aElfNotes[i].pszType, rc));
 
1536
                    break;
 
1537
                }
 
1538
            }
 
1539
 
 
1540
            /*
 
1541
             * Write old-style thread info., they contain nothing about zombies,
 
1542
             * so we just skip if there is no status information for them.
 
1543
             */
 
1544
            PVBOXSOLTHREADINFO pThreadInfo = pVBoxProc->pThreadInfoHead;
 
1545
            for (; pThreadInfo; pThreadInfo = pThreadInfo->pNext)
 
1546
            {
 
1547
                if (!pThreadInfo->pStatus)
 
1548
                    continue;
 
1549
 
 
1550
                prstatus_t OldProcessStatus;
 
1551
                GetOldProcessStatus(pVBoxCore, &pThreadInfo->Info, pThreadInfo->pStatus, &OldProcessStatus);
 
1552
                rc = ElfWriteNoteHeader(pVBoxCore, NT_PRSTATUS, &OldProcessStatus, sizeof(prstatus_t));
 
1553
                if (RT_SUCCESS(rc))
 
1554
                {
 
1555
                    rc = ElfWriteNoteHeader(pVBoxCore, NT_PRFPREG, &pThreadInfo->pStatus->pr_fpreg, sizeof(prfpregset_t));
 
1556
                    if (RT_FAILURE(rc))
 
1557
                    {
 
1558
                        CORELOGRELSYS((CORELOG_NAME "ElfWriteSegment: ElfWriteNote failed for NT_PRFPREF. rc=%Rrc\n", rc));
 
1559
                        break;
 
1560
                    }
 
1561
                }
 
1562
                else
 
1563
                {
 
1564
                    CORELOGRELSYS((CORELOG_NAME "ElfWriteSegment: ElfWriteNote failed for NT_PRSTATUS. rc=%Rrc\n", rc));
 
1565
                    break;
 
1566
                }
 
1567
            }
 
1568
            break;
 
1569
        }
 
1570
 
 
1571
        case enmNewEra:
 
1572
        {
 
1573
            ELFWRITENOTE aElfNotes[] =
 
1574
            {
 
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 }
 
1585
            };
 
1586
 
 
1587
            for (unsigned i = 0; i < RT_ELEMENTS(aElfNotes); i++)
 
1588
            {
 
1589
                rc = ElfWriteNoteHeader(pVBoxCore, aElfNotes[i].Type, aElfNotes[i].pcv, aElfNotes[i].cb);
 
1590
                if (RT_FAILURE(rc))
 
1591
                {
 
1592
                    CORELOGRELSYS((CORELOG_NAME "ElfWriteNoteSection: ElfWriteNoteHeader failed for %s. rc=%Rrc\n", aElfNotes[i].pszType, rc));
 
1593
                    break;
 
1594
                }
 
1595
            }
 
1596
 
 
1597
            /*
 
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.
 
1600
             */
 
1601
            PVBOXSOLTHREADINFO pThreadInfo = pVBoxProc->pThreadInfoHead;
 
1602
            for (; pThreadInfo; pThreadInfo = pThreadInfo->pNext)
 
1603
            {
 
1604
                rc = ElfWriteNoteHeader(pVBoxCore, NT_LWPSINFO, &pThreadInfo->Info, sizeof(lwpsinfo_t));
 
1605
                if (RT_FAILURE(rc))
 
1606
                {
 
1607
                    CORELOGRELSYS((CORELOG_NAME "ElfWriteNoteSection: ElfWriteNoteHeader for NT_LWPSINFO failed. rc=%Rrc\n", rc));
 
1608
                    break;
 
1609
                }
 
1610
 
 
1611
                if (pThreadInfo->pStatus)
 
1612
                {
 
1613
                    rc = ElfWriteNoteHeader(pVBoxCore, NT_LWPSTATUS, pThreadInfo->pStatus, sizeof(lwpstatus_t));
 
1614
                    if (RT_FAILURE(rc))
 
1615
                    {
 
1616
                        CORELOGRELSYS((CORELOG_NAME "ElfWriteNoteSection: ElfWriteNoteHeader for NT_LWPSTATUS failed. rc=%Rrc\n", rc));
 
1617
                        break;
 
1618
                    }
 
1619
                }
 
1620
            }
 
1621
            break;
 
1622
        }
 
1623
 
 
1624
        default:
 
1625
        {
 
1626
            CORELOGRELSYS((CORELOG_NAME "ElfWriteNoteSection: Invalid type %d\n", enmType));
 
1627
            rc = VERR_GENERAL_FAILURE;
 
1628
            break;
 
1629
        }
 
1630
    }
 
1631
#else
 
1632
# error Port Me!
 
1633
#endif
 
1634
    return rc;
 
1635
}
 
1636
 
 
1637
 
 
1638
/**
 
1639
 * Write mappings into the core file.
 
1640
 *
 
1641
 * @param pVBoxCore         Pointer to the core object.
 
1642
 *
 
1643
 * @return IPRT status code.
 
1644
 */
 
1645
static int ElfWriteMappings(PVBOXCORE pVBoxCore)
 
1646
{
 
1647
    PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
 
1648
 
 
1649
    int rc = VERR_GENERAL_FAILURE;
 
1650
    PVBOXSOLMAPINFO pMapInfo = pVBoxProc->pMapInfoHead;
 
1651
    while (pMapInfo)
 
1652
    {
 
1653
        if (!pMapInfo->fError)
 
1654
        {
 
1655
            uint64_t k = 0;
 
1656
            char achBuf[PAGE_SIZE];
 
1657
            while (k < pMapInfo->pMap.pr_size)
 
1658
            {
 
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))
 
1662
                {
 
1663
                    CORELOGRELSYS((CORELOG_NAME "ElfWriteMappings: Failed to read mapping, can't recover. Bye. rc=%Rrc\n", rc));
 
1664
                    return VERR_INVALID_STATE;
 
1665
                }
 
1666
 
 
1667
                rc = pVBoxCore->pfnWriter(pVBoxCore->hCoreFile, achBuf, sizeof(achBuf));
 
1668
                if (RT_FAILURE(rc))
 
1669
                {
 
1670
                    CORELOGRELSYS((CORELOG_NAME "ElfWriteMappings: pfnWriter failed. rc=%Rrc\n", rc));
 
1671
                    return rc;
 
1672
                }
 
1673
                k += cb;
 
1674
            }
 
1675
        }
 
1676
        else
 
1677
        {
 
1678
            char achBuf[RT_ALIGN_Z(sizeof(int), 8)];
 
1679
            RT_ZERO(achBuf);
 
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));
 
1684
            if (RT_FAILURE(rc))
 
1685
            {
 
1686
                CORELOGRELSYS((CORELOG_NAME "ElfWriteMappings: pfnWriter(2) failed. rc=%Rrc\n", rc));
 
1687
                return rc;
 
1688
            }
 
1689
        }
 
1690
 
 
1691
        pMapInfo = pMapInfo->pNext;
 
1692
    }
 
1693
 
 
1694
    return VINF_SUCCESS;
 
1695
}
 
1696
 
 
1697
 
 
1698
/**
 
1699
 * Write program headers for all mappings into the core file.
 
1700
 *
 
1701
 * @param pVBoxCore         Pointer to the core object.
 
1702
 *
 
1703
 * @return IPRT status code.
 
1704
 */
 
1705
static int ElfWriteMappingHeaders(PVBOXCORE pVBoxCore)
 
1706
{
 
1707
    AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
 
1708
 
 
1709
    PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
 
1710
    Elf_Phdr ProgHdr;
 
1711
    RT_ZERO(ProgHdr);
 
1712
    ProgHdr.p_type = PT_LOAD;
 
1713
 
 
1714
    int rc = VERR_GENERAL_FAILURE;
 
1715
    PVBOXSOLMAPINFO pMapInfo = pVBoxProc->pMapInfoHead;
 
1716
    while (pMapInfo)
 
1717
    {
 
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 */
 
1722
 
 
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;
 
1730
 
 
1731
        if (pMapInfo->fError)
 
1732
            ProgHdr.p_flags |= PF_SUNW_FAILURE;
 
1733
 
 
1734
        rc = pVBoxCore->pfnWriter(pVBoxCore->hCoreFile, &ProgHdr, sizeof(ProgHdr));
 
1735
        if (RT_FAILURE(rc))
 
1736
        {
 
1737
            CORELOGRELSYS((CORELOG_NAME "ElfWriteMappingHeaders: pfnWriter failed. rc=%Rrc\n", rc));
 
1738
            return rc;
 
1739
        }
 
1740
 
 
1741
        pVBoxCore->offWrite += ProgHdr.p_filesz;
 
1742
        pMapInfo = pMapInfo->pNext;
 
1743
    }
 
1744
    return rc;
 
1745
}
 
1746
 
 
1747
 
 
1748
/**
 
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).
 
1751
 *
 
1752
 * @param pVBoxCore         Pointer to the core object.
 
1753
 * @param pfnWriter         Pointer to the writer function to override default writer (NULL uses default).
 
1754
 *
 
1755
 * @remarks Resumes all suspended threads, unless it's an invalid core.
 
1756
 * @return VBox status.
 
1757
 */
 
1758
static int rtCoreDumperWriteCore(PVBOXCORE pVBoxCore, PFNCOREWRITER pfnWriter)
 
1759
{
 
1760
    AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
 
1761
 
 
1762
    if (!pVBoxCore->fIsValid)
 
1763
        return VERR_INVALID_STATE;
 
1764
 
 
1765
    if (pfnWriter)
 
1766
        pVBoxCore->pfnWriter = pfnWriter;
 
1767
 
 
1768
    PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
 
1769
    char szPath[PATH_MAX];
 
1770
 
 
1771
    /*
 
1772
     * Open the process address space file.
 
1773
     */
 
1774
    RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/as", (int)pVBoxProc->Process);
 
1775
    int rc = RTFileOpen(&pVBoxProc->hAs, szPath, RTFILE_O_OPEN | RTFILE_O_READ);
 
1776
    if (RT_FAILURE(rc))
 
1777
    {
 
1778
        CORELOGRELSYS((CORELOG_NAME "WriteCore: Failed to open address space, %s. rc=%Rrc\n", szPath, rc));
 
1779
        goto WriteCoreDone;
 
1780
    }
 
1781
 
 
1782
    /*
 
1783
     * Create the core file.
 
1784
     */
 
1785
    rc = RTFileOpen(&pVBoxCore->hCoreFile, pVBoxCore->szCorePath,
 
1786
                    RTFILE_O_OPEN_CREATE | RTFILE_O_TRUNCATE | RTFILE_O_READWRITE | RTFILE_O_DENY_ALL);
 
1787
    if (RT_FAILURE(rc))
 
1788
    {
 
1789
        CORELOGRELSYS((CORELOG_NAME "WriteCore: failed to open %s. rc=%Rrc\n", pVBoxCore->szCorePath, rc));
 
1790
        goto WriteCoreDone;
 
1791
    }
 
1792
 
 
1793
    pVBoxCore->offWrite = 0;
 
1794
    uint32_t cProgHdrs  = pVBoxProc->cMappings + 2; /* two PT_NOTE program headers (old, new style) */
 
1795
 
 
1796
    /*
 
1797
     * Write the ELF header.
 
1798
     */
 
1799
    Elf_Ehdr ElfHdr;
 
1800
    RT_ZERO(ElfHdr);
 
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;
 
1811
#else
 
1812
    ElfHdr.e_machine         = EM_386;
 
1813
    ElfHdr.e_ident[EI_CLASS] = ELFCLASS32;
 
1814
#endif
 
1815
    if (cProgHdrs >= PN_XNUM)
 
1816
        ElfHdr.e_phnum       = PN_XNUM;
 
1817
    else
 
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));
 
1824
    if (RT_FAILURE(rc))
 
1825
    {
 
1826
        CORELOGRELSYS((CORELOG_NAME "WriteCore: pfnWriter failed writing ELF header. rc=%Rrc\n", rc));
 
1827
        goto WriteCoreDone;
 
1828
    }
 
1829
 
 
1830
    /*
 
1831
     * Setup program header.
 
1832
     */
 
1833
    Elf_Phdr ProgHdr;
 
1834
    RT_ZERO(ProgHdr);
 
1835
    ProgHdr.p_type = PT_NOTE;
 
1836
    ProgHdr.p_flags = PF_R;
 
1837
 
 
1838
    /*
 
1839
     * Write old-style NOTE program header.
 
1840
     */
 
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));
 
1845
    if (RT_FAILURE(rc))
 
1846
    {
 
1847
        CORELOGRELSYS((CORELOG_NAME "WriteCore: pfnWriter failed writing old-style ELF program Header. rc=%Rrc\n", rc));
 
1848
        goto WriteCoreDone;
 
1849
    }
 
1850
 
 
1851
    /*
 
1852
     * Write new-style NOTE program header.
 
1853
     */
 
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));
 
1858
    if (RT_FAILURE(rc))
 
1859
    {
 
1860
        CORELOGRELSYS((CORELOG_NAME "WriteCore: pfnWriter failed writing new-style ELF program header. rc=%Rrc\n", rc));
 
1861
        goto WriteCoreDone;
 
1862
    }
 
1863
 
 
1864
    /*
 
1865
     * Write program headers per mapping.
 
1866
     */
 
1867
    pVBoxCore->offWrite += ProgHdr.p_filesz;
 
1868
    rc = ElfWriteMappingHeaders(pVBoxCore);
 
1869
    if (RT_FAILURE(rc))
 
1870
    {
 
1871
        CORELOGRELSYS((CORELOG_NAME "Write: ElfWriteMappings failed. rc=%Rrc\n", rc));
 
1872
        goto WriteCoreDone;
 
1873
    }
 
1874
 
 
1875
    /*
 
1876
     * Write old-style note section.
 
1877
     */
 
1878
    rc = ElfWriteNoteSection(pVBoxCore, enmOldEra);
 
1879
    if (RT_FAILURE(rc))
 
1880
    {
 
1881
        CORELOGRELSYS((CORELOG_NAME "WriteCore: ElfWriteNoteSection old-style failed. rc=%Rrc\n", rc));
 
1882
        goto WriteCoreDone;
 
1883
    }
 
1884
 
 
1885
    /*
 
1886
     * Write new-style section.
 
1887
     */
 
1888
    rc = ElfWriteNoteSection(pVBoxCore, enmNewEra);
 
1889
    if (RT_FAILURE(rc))
 
1890
    {
 
1891
        CORELOGRELSYS((CORELOG_NAME "WriteCore: ElfWriteNoteSection new-style failed. rc=%Rrc\n", rc));
 
1892
        goto WriteCoreDone;
 
1893
    }
 
1894
 
 
1895
    /*
 
1896
     * Write all mappings.
 
1897
     */
 
1898
    rc = ElfWriteMappings(pVBoxCore);
 
1899
    if (RT_FAILURE(rc))
 
1900
    {
 
1901
        CORELOGRELSYS((CORELOG_NAME "WriteCore: ElfWriteMappings failed. rc=%Rrc\n", rc));
 
1902
        goto WriteCoreDone;
 
1903
    }
 
1904
 
 
1905
 
 
1906
WriteCoreDone:
 
1907
    if (pVBoxCore->hCoreFile != NIL_RTFILE)
 
1908
    {
 
1909
        RTFileClose(pVBoxCore->hCoreFile);
 
1910
        pVBoxCore->hCoreFile = NIL_RTFILE;
 
1911
    }
 
1912
 
 
1913
    if (pVBoxProc->hAs != NIL_RTFILE)
 
1914
    {
 
1915
        RTFileClose(pVBoxProc->hAs);
 
1916
        pVBoxProc->hAs = NIL_RTFILE;
 
1917
    }
 
1918
 
 
1919
    rtCoreDumperResumeThreads(pVBoxCore);
 
1920
    return rc;
 
1921
}
 
1922
 
 
1923
 
 
1924
/**
 
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.
 
1928
 *
 
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.
 
1933
 *
 
1934
 * @remarks Halts all threads.
 
1935
 * @return IPRT status code.
 
1936
 */
 
1937
static int rtCoreDumperCreateCore(PVBOXCORE pVBoxCore, ucontext_t *pContext, const char *pszCoreFilePath)
 
1938
{
 
1939
    AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
 
1940
    AssertReturn(pContext, VERR_INVALID_POINTER);
 
1941
 
 
1942
    /*
 
1943
     * Initialize core structures.
 
1944
     */
 
1945
    memset(pVBoxCore, 0, sizeof(VBOXCORE));
 
1946
    pVBoxCore->pfnReader = &ReadFileNoIntr;
 
1947
    pVBoxCore->pfnWriter = &WriteFileNoIntr;
 
1948
    pVBoxCore->fIsValid  = false;
 
1949
    pVBoxCore->hCoreFile = NIL_RTFILE;
 
1950
 
 
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;
 
1957
 
 
1958
    RTProcGetExecutableName(pVBoxProc->szExecPath, sizeof(pVBoxProc->szExecPath));  /* this gets full path not just name */
 
1959
    pVBoxProc->pszExecName = RTPathFilename(pVBoxProc->szExecPath);
 
1960
 
 
1961
    /*
 
1962
     * If a path has been specified, use it. Otherwise use the global path.
 
1963
     */
 
1964
    if (!pszCoreFilePath)
 
1965
    {
 
1966
        /*
 
1967
         * If no output directory is specified, use current directory.
 
1968
         */
 
1969
        if (g_szCoreDumpDir[0] == '\0')
 
1970
            g_szCoreDumpDir[0] = '.';
 
1971
 
 
1972
        if (g_szCoreDumpFile[0] == '\0')
 
1973
        {
 
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);
 
1977
        }
 
1978
        else
 
1979
            RTStrPrintf(pVBoxCore->szCorePath, sizeof(pVBoxCore->szCorePath), "%s/core.vb.%s", g_szCoreDumpDir, g_szCoreDumpFile);
 
1980
    }
 
1981
    else
 
1982
        RTStrCopy(pVBoxCore->szCorePath, sizeof(pVBoxCore->szCorePath), pszCoreFilePath);
 
1983
 
 
1984
    CORELOG((CORELOG_NAME  "CreateCore: Taking Core %s from Thread %d\n", pVBoxCore->szCorePath, (int)pVBoxProc->hCurThread));
 
1985
 
 
1986
    /*
 
1987
     * Quiesce the process.
 
1988
     */
 
1989
    int rc = rtCoreDumperSuspendThreads(pVBoxCore);
 
1990
    if (RT_SUCCESS(rc))
 
1991
    {
 
1992
        rc = ProcReadInfo(pVBoxCore);
 
1993
        if (RT_SUCCESS(rc))
 
1994
        {
 
1995
            GetOldProcessInfo(pVBoxCore, &pVBoxProc->ProcInfoOld);
 
1996
            if (IsProcessArchNative(pVBoxProc))
 
1997
            {
 
1998
                /*
 
1999
                 * Read process status, information such as number of active LWPs will be invalid since we just quiesced the process.
 
2000
                 */
 
2001
                rc = ProcReadStatus(pVBoxCore);
 
2002
                if (RT_SUCCESS(rc))
 
2003
                {
 
2004
                    rc = AllocMemoryArea(pVBoxCore);
 
2005
                    if (RT_SUCCESS(rc))
 
2006
                    {
 
2007
                        struct COREACCUMULATOR
 
2008
                        {
 
2009
                            const char        *pszName;
 
2010
                            PFNCOREACCUMULATOR pfnAcc;
 
2011
                            bool               fOptional;
 
2012
                        } aAccumulators[] =
 
2013
                        {
 
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 }
 
2021
                        };
 
2022
 
 
2023
                        for (unsigned i = 0; i < RT_ELEMENTS(aAccumulators); i++)
 
2024
                        {
 
2025
                            rc = aAccumulators[i].pfnAcc(pVBoxCore);
 
2026
                            if (RT_FAILURE(rc))
 
2027
                            {
 
2028
                                CORELOGRELSYS((CORELOG_NAME "CreateCore: %s failed. rc=%Rrc\n", aAccumulators[i].pszName, rc));
 
2029
                                if (!aAccumulators[i].fOptional)
 
2030
                                    break;
 
2031
                            }
 
2032
                        }
 
2033
 
 
2034
                        if (RT_SUCCESS(rc))
 
2035
                        {
 
2036
                            pVBoxCore->fIsValid = true;
 
2037
                            return VINF_SUCCESS;
 
2038
                        }
 
2039
 
 
2040
                        FreeMemoryArea(pVBoxCore);
 
2041
                    }
 
2042
                    else
 
2043
                        CORELOGRELSYS((CORELOG_NAME "CreateCore: AllocMemoryArea failed. rc=%Rrc\n", rc));
 
2044
                }
 
2045
                else
 
2046
                    CORELOGRELSYS((CORELOG_NAME "CreateCore: ProcReadStatus failed. rc=%Rrc\n", rc));
 
2047
            }
 
2048
            else
 
2049
            {
 
2050
                CORELOGRELSYS((CORELOG_NAME "CreateCore: IsProcessArchNative failed.\n"));
 
2051
                rc = VERR_BAD_EXE_FORMAT;
 
2052
            }
 
2053
        }
 
2054
        else
 
2055
            CORELOGRELSYS((CORELOG_NAME "CreateCore: ProcReadInfo failed. rc=%Rrc\n", rc));
 
2056
 
 
2057
        /*
 
2058
         * Resume threads on failure.
 
2059
         */
 
2060
        rtCoreDumperResumeThreads(pVBoxCore);
 
2061
    }
 
2062
    else
 
2063
        CORELOG((CORELOG_NAME "CreateCore: SuspendAllThreads failed. Thread bomb!?! rc=%Rrc\n", rc));
 
2064
 
 
2065
    return rc;
 
2066
}
 
2067
 
 
2068
 
 
2069
/**
 
2070
 * Destroy an existing core object.
 
2071
 *
 
2072
 * @param pVBoxCore         Pointer to the core object.
 
2073
 *
 
2074
 * @return IPRT status code.
 
2075
 */
 
2076
static int rtCoreDumperDestroyCore(PVBOXCORE pVBoxCore)
 
2077
{
 
2078
    AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
 
2079
    if (!pVBoxCore->fIsValid)
 
2080
        return VERR_INVALID_STATE;
 
2081
 
 
2082
    FreeMemoryArea(pVBoxCore);
 
2083
    pVBoxCore->fIsValid = false;
 
2084
    return VINF_SUCCESS;
 
2085
}
 
2086
 
 
2087
 
 
2088
/**
 
2089
 * Takes a core dump. This function has no other parameters than the context
 
2090
 * because it can be called from signal handlers.
 
2091
 *
 
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
 
2095
 *                              be used.
 
2096
 * @returns IPRT status code.
 
2097
 */
 
2098
static int rtCoreDumperTakeDump(ucontext_t *pContext, const char *pszOutputFile)
 
2099
{
 
2100
    if (!pContext)
 
2101
    {
 
2102
        CORELOGRELSYS((CORELOG_NAME "TakeDump: Missing context.\n"));
 
2103
        return VERR_INVALID_POINTER;
 
2104
    }
 
2105
 
 
2106
    /*
 
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.
 
2110
     */
 
2111
    VBOXCORE VBoxCore;
 
2112
    RT_ZERO(VBoxCore);
 
2113
    int rc = rtCoreDumperCreateCore(&VBoxCore, pContext, pszOutputFile);
 
2114
    if (RT_SUCCESS(rc))
 
2115
    {
 
2116
        rc = rtCoreDumperWriteCore(&VBoxCore, &WriteFileNoIntr);
 
2117
        if (RT_SUCCESS(rc))
 
2118
            CORELOGRELSYS((CORELOG_NAME "Core dumped in %s\n", VBoxCore.szCorePath));
 
2119
        else
 
2120
            CORELOGRELSYS((CORELOG_NAME "TakeDump: WriteCore failed. szCorePath=%s rc=%Rrc\n", VBoxCore.szCorePath, rc));
 
2121
 
 
2122
        rtCoreDumperDestroyCore(&VBoxCore);
 
2123
    }
 
2124
    else
 
2125
        CORELOGRELSYS((CORELOG_NAME "TakeDump: CreateCore failed. rc=%Rrc\n", rc));
 
2126
 
 
2127
    return rc;
 
2128
}
 
2129
 
 
2130
 
 
2131
/**
 
2132
 * The signal handler that will be invoked to take core dumps.
 
2133
 *
 
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.
 
2138
 */
 
2139
static void rtCoreDumperSignalHandler(int Sig, siginfo_t *pSigInfo, void *pvArg)
 
2140
{
 
2141
    CORELOG((CORELOG_NAME "SignalHandler Sig=%d pvArg=%p\n", Sig, pvArg));
 
2142
 
 
2143
    RTNATIVETHREAD  hCurNativeThread = RTThreadNativeSelf();
 
2144
    int             rc               = VERR_GENERAL_FAILURE;
 
2145
    bool            fCallSystemDump  = false;
 
2146
    bool            fRc;
 
2147
    ASMAtomicCmpXchgHandle(&g_CoreDumpThread, hCurNativeThread, NIL_RTNATIVETHREAD, fRc);
 
2148
    if (fRc)
 
2149
    {
 
2150
        rc = rtCoreDumperTakeDump((ucontext_t *)pvArg, NULL /* Use Global Core filepath */);
 
2151
        ASMAtomicWriteHandle(&g_CoreDumpThread, NIL_RTNATIVETHREAD);
 
2152
 
 
2153
        if (RT_FAILURE(rc))
 
2154
            CORELOGRELSYS((CORELOG_NAME "TakeDump failed! rc=%Rrc\n", rc));
 
2155
    }
 
2156
    else if (Sig == SIGSEGV || Sig == SIGBUS || Sig == SIGTRAP)
 
2157
    {
 
2158
        /*
 
2159
         * Core dumping is already in progress and we've somehow ended up being
 
2160
         * signalled again.
 
2161
         */
 
2162
        rc = VERR_INTERNAL_ERROR;
 
2163
 
 
2164
        /*
 
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.
 
2167
         */
 
2168
        RTNATIVETHREAD hNativeDumperThread;
 
2169
        ASMAtomicReadHandle(&g_CoreDumpThread, &hNativeDumperThread);
 
2170
        if (hNativeDumperThread == RTThreadNativeSelf())
 
2171
        {
 
2172
            CORELOGRELSYS((CORELOG_NAME "SignalHandler: Core dumper (thread %u) crashed Sig=%d. Triggering system dump\n",
 
2173
                           RTThreadSelf(), Sig));
 
2174
            fCallSystemDump = true;
 
2175
        }
 
2176
        else
 
2177
        {
 
2178
            /*
 
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.
 
2181
             */
 
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) */
 
2184
            for (;;)
 
2185
            {
 
2186
                ASMAtomicReadHandle(&g_CoreDumpThread, &hNativeDumperThread);
 
2187
                if (hNativeDumperThread == NIL_RTNATIVETHREAD)
 
2188
                    break;
 
2189
                RTThreadSleep(200);
 
2190
                iTimeout -= 200;
 
2191
                if (iTimeout <= 0)
 
2192
                    break;
 
2193
            }
 
2194
            if (iTimeout <= 0)
 
2195
            {
 
2196
                fCallSystemDump = true;
 
2197
                CORELOGRELSYS((CORELOG_NAME "SignalHandler: Core dumper seems to be stuck. Signalling new signal %d\n", Sig));
 
2198
            }
 
2199
        }
 
2200
    }
 
2201
 
 
2202
    if (Sig == SIGSEGV || Sig == SIGBUS || Sig == SIGTRAP)
 
2203
    {
 
2204
        /*
 
2205
         * Reset signal handlers, we're not a live core we will be blown away
 
2206
         * one way or another.
 
2207
         */
 
2208
        signal(SIGSEGV, SIG_DFL);
 
2209
        signal(SIGBUS, SIG_DFL);
 
2210
        signal(SIGTRAP, SIG_DFL);
 
2211
 
 
2212
        /*
 
2213
         * Hard terminate the process if this is not a live dump without invoking
 
2214
         * the system core dumping behaviour.
 
2215
         */
 
2216
        if (RT_SUCCESS(rc))
 
2217
            raise(SIGKILL);
 
2218
 
 
2219
        /*
 
2220
         * Something went wrong, fall back to the system core dumper.
 
2221
         */
 
2222
        if (fCallSystemDump)
 
2223
            abort();
 
2224
    }
 
2225
}
 
2226
 
 
2227
 
 
2228
RTDECL(int) RTCoreDumperTakeDump(const char *pszOutputFile, bool fLiveCore)
 
2229
{
 
2230
    ucontext_t Context;
 
2231
    int rc = getcontext(&Context);
 
2232
    if (!rc)
 
2233
    {
 
2234
        /*
 
2235
         * Block SIGSEGV and co. while we write the core.
 
2236
         */
 
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);
 
2245
        if (RT_FAILURE(rc))
 
2246
            CORELOGRELSYS(("RTCoreDumperTakeDump: rtCoreDumperTakeDump failed rc=%Rrc\n", rc));
 
2247
 
 
2248
        if (!fLiveCore)
 
2249
        {
 
2250
            signal(SIGSEGV, SIG_DFL);
 
2251
            signal(SIGBUS, SIG_DFL);
 
2252
            signal(SIGTRAP, SIG_DFL);
 
2253
            if (RT_SUCCESS(rc))
 
2254
                raise(SIGKILL);
 
2255
            else
 
2256
                abort();
 
2257
        }
 
2258
        pthread_sigmask(SIG_SETMASK, &OldSigSet, NULL);
 
2259
    }
 
2260
    else
 
2261
    {
 
2262
        CORELOGRELSYS(("RTCoreDumperTakeDump: getcontext failed rc=%d.\n", rc));
 
2263
        rc = VERR_INVALID_CONTEXT;
 
2264
    }
 
2265
 
 
2266
    return rc;
 
2267
}
 
2268
 
 
2269
 
 
2270
RTDECL(int) RTCoreDumperSetup(const char *pszOutputDir, uint32_t fFlags)
 
2271
{
 
2272
    /*
 
2273
     * Validate flags.
 
2274
     */
 
2275
    AssertReturn(fFlags, VERR_INVALID_PARAMETER);
 
2276
    AssertReturn(!(fFlags & ~(  RTCOREDUMPER_FLAGS_REPLACE_SYSTEM_DUMP
 
2277
                              | RTCOREDUMPER_FLAGS_LIVE_CORE)),
 
2278
                 VERR_INVALID_PARAMETER);
 
2279
 
 
2280
    /*
 
2281
     * Install core dump signal handler only if the flags changed or if it's the first time.
 
2282
     */
 
2283
    if (   ASMAtomicReadBool(&g_fCoreDumpSignalSetup) == false
 
2284
        || ASMAtomicReadU32(&g_fCoreDumpFlags) != fFlags)
 
2285
    {
 
2286
        struct sigaction sigAct;
 
2287
        RT_ZERO(sigAct);
 
2288
        sigAct.sa_sigaction = &rtCoreDumperSignalHandler;
 
2289
 
 
2290
        if (   (fFlags & RTCOREDUMPER_FLAGS_REPLACE_SYSTEM_DUMP)
 
2291
            && !(g_fCoreDumpFlags & RTCOREDUMPER_FLAGS_REPLACE_SYSTEM_DUMP))
 
2292
        {
 
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);
 
2298
        }
 
2299
 
 
2300
        if (   fFlags & RTCOREDUMPER_FLAGS_LIVE_CORE
 
2301
            && !(g_fCoreDumpFlags & RTCOREDUMPER_FLAGS_LIVE_CORE))
 
2302
        {
 
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);
 
2306
        }
 
2307
 
 
2308
        ASMAtomicWriteU32(&g_fCoreDumpFlags, fFlags);
 
2309
        ASMAtomicWriteBool(&g_fCoreDumpSignalSetup, true);
 
2310
    }
 
2311
 
 
2312
    RT_ZERO(g_szCoreDumpDir);
 
2313
    if (pszOutputDir)
 
2314
        RTStrCopy(g_szCoreDumpDir, sizeof(g_szCoreDumpDir), pszOutputDir);
 
2315
 
 
2316
    return VINF_SUCCESS;
 
2317
}
 
2318
 
 
2319
 
 
2320
RTDECL(int) RTCoreDumperDisable(void)
 
2321
{
 
2322
    /*
 
2323
     * Remove core dump signal handler & reset variables.
 
2324
     */
 
2325
    if (ASMAtomicReadBool(&g_fCoreDumpSignalSetup) == true)
 
2326
    {
 
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);
 
2332
    }
 
2333
 
 
2334
    RT_ZERO(g_szCoreDumpDir);
 
2335
    RT_ZERO(g_szCoreDumpFile);
 
2336
    ASMAtomicWriteU32(&g_fCoreDumpFlags, 0);
 
2337
    return VINF_SUCCESS;
 
2338
}
 
2339