VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstRTCoreDump.cpp@ 31795

Last change on this file since 31795 was 31795, checked in by vboxsync, 15 years ago

tstRTCoreDump: don't break OSE, export it.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 75.1 KB
Line 
1/* $Id: tstRTCoreDump.cpp 31795 2010-08-19 14:37:28Z vboxsync $ */
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#include <iprt/types.h>
31#include <iprt/file.h>
32#include <iprt/err.h>
33#include <iprt/dir.h>
34#include <iprt/path.h>
35#include <iprt/string.h>
36#include <iprt/stream.h>
37#include <iprt/initterm.h>
38#include <iprt/thread.h>
39#include <iprt/param.h>
40#include <iprt/asm.h>
41#include "tstRTCoreDump.h"
42
43#ifdef RT_OS_SOLARIS
44# include <signal.h>
45# include <unistd.h>
46# include <errno.h>
47# include <zone.h>
48# include <sys/proc.h>
49# include <sys/sysmacros.h>
50# include <sys/systeminfo.h>
51# include <sys/mman.h>
52#endif /* RT_OS_SOLARIS */
53
54/*******************************************************************************
55* Defined Constants And Macros *
56*******************************************************************************/
57#define CORELOG(a) RTPrintf a
58#define CORELOGREL(a) RTPrintf a
59
60/**
61 * VBOXSOLCORETYPE: Whether this is an old or new style core.
62 */
63typedef enum VBOXSOLCORETYPE
64{
65 enmOldEra = 0x01d, /* old */
66 enmNewEra = 0x5c151 /* sci-fi */
67} VBOXSOLCORETYPE;
68
69static unsigned volatile g_cErrors = 0;
70
71volatile bool g_fCoreDumpInProgress = false;
72
73
74/**
75 * Reads a file in a given offset making sure an interruption doesn't cause a failure.
76 *
77 * @param hFile Handle to the file to read.
78 * @param pv Where to store the read data.
79 * @param cb Size of the data to read.
80 * @param off Offset to read from.
81 *
82 * @return Number of bytes actually read.
83 */
84static ssize_t ReadFileAt(RTFILE hFile, void *pv, size_t cb, RTFOFF off)
85{
86 while (1)
87 {
88 ssize_t cbRead = pread(hFile, pv, cb, off);
89 if ( cbRead < 0
90 && errno == EINTR)
91 {
92 continue;
93 }
94 return cbRead;
95 }
96}
97
98/**
99 * Determines endianness of the system. Just for completeness.
100 *
101 * @return Will return false if system is little endian, true otherwise.
102 */
103static bool IsBigEndian()
104{
105 const int i = 1;
106 char *p = (char *)&i;
107 if (p[0] == 1)
108 return false;
109 return true;
110}
111
112
113/**
114 * Reads from a file making sure an interruption doesn't cause a failure.
115 *
116 * @param hFile Handle to the file to read.
117 * @param pv Where to store the read data.
118 * @param cbToRead Size of data to read.
119 *
120 * @return VBox status code.
121 */
122static int ReadFileNoIntr(RTFILE hFile, void *pv, size_t cbToRead)
123{
124 int rc = VERR_READ_ERROR;
125 while (1)
126 {
127 rc = RTFileRead(hFile, pv, cbToRead, NULL /* Read all */);
128 if (rc == VERR_INTERRUPTED)
129 continue;
130 break;
131 }
132 return rc;
133}
134
135
136/**
137 * Writes to a file making sure an interruption doesn't cause a failure.
138 *
139 * @param hFile Handle to the file to write.
140 * @param pv Pointer to what to write.
141 * @param cbToRead Size of data to write.
142 *
143 * @return VBox status code.
144 */
145static int WriteFileNoIntr(RTFILE hFile, const void *pcv, size_t cbToRead)
146{
147 int rc = VERR_READ_ERROR;
148 while (1)
149 {
150 rc = RTFileWrite(hFile, pcv, cbToRead, NULL /* Write all */);
151 if (rc == VERR_INTERRUPTED)
152 continue;
153 break;
154 }
155 return rc;
156}
157
158
159/**
160 * Read from a given offet in the process' address space.
161 *
162 * @param pVBoxProc Pointer to the VBox process.
163 * @param pv Where to read the data into.
164 * @param cb Size of the read buffer.
165 * @param off Offset to read from.
166 *
167 * @return VINF_SUCCESS, if all the given bytes was read in, otherwise VERR_READ_ERROR.
168 */
169static ssize_t ReadProcAddrSpace(PVBOXPROCESS pVBoxProc, void *pv, size_t cb, RTFOFF off)
170{
171 ssize_t cbRead = ReadFileAt(pVBoxProc->hAs, pv, cb, off);
172 if (cbRead == (ssize_t)cb)
173 return VINF_SUCCESS;
174 else
175 return VERR_READ_ERROR;
176}
177
178
179/**
180 * Determines if the current process' architecture is suitable for dumping core.
181 *
182 * @param pVBoxProc Pointer to the VBox process.
183 *
184 * @return true if the architecture matches the current one.
185 */
186inline bool IsProcArchNative(PVBOXPROCESS pVBoxProc)
187{
188 return pVBoxProc->ProcInfo.pr_dmodel == PR_MODEL_NATIVE;
189}
190
191
192/**
193 * Helper function to get the size of a file given it's path.
194 *
195 * @param pszPath Pointer to the full path of the file.
196 *
197 * @return The size of the file in bytes.
198 */
199size_t GetFileSize(const char *pszPath)
200{
201 size_t cb = 0;
202 RTFILE hFile;
203 int rc = RTFileOpen(&hFile, pszPath, RTFILE_O_OPEN | RTFILE_O_READ);
204 if (RT_SUCCESS(rc))
205 {
206 RTFileGetSize(hFile, (uint64_t *)&cb);
207 RTFileClose(hFile);
208 }
209 else
210 CORELOGREL(("GetFileSize failed to open %s rc=%Rrc\n", pszPath, rc));
211 return cb;
212}
213
214
215/**
216 * Pre-compute and pre-allocate sufficient memory for dumping core.
217 * This is meant to be called once, as a single-large anonymously
218 * mapped memory area which will be used during the core dumping routines.
219 *
220 * @param pVBoxCore Pointer to the core object.
221 *
222 * @return VBox status code.
223 */
224int AllocMemoryArea(PVBOXCORE pVBoxCore)
225{
226 AssertReturn(pVBoxCore->pvCore == NULL, VERR_ALREADY_EXISTS);
227 AssertReturn(pVBoxCore->VBoxProc.Process != NIL_RTPROCESS, VERR_PROCESS_NOT_FOUND);
228
229 struct VBOXSOLPREALLOCTABLE
230 {
231 const char *pszFilePath; /* Proc based path */
232 size_t cbHeader; /* Size of header */
233 size_t cbEntry; /* Size of each entry in file */
234 size_t cbAccounting; /* Size of each accounting entry per entry */
235 } aPreAllocTable[] = {
236 { "/proc/%d/map", 0, sizeof(prmap_t), sizeof(VBOXSOLMAPINFO) },
237 { "/proc/%d/auxv", 0, 0, 0 },
238 { "/proc/%d/lpsinfo", sizeof(prheader_t), sizeof(lwpsinfo_t), sizeof(VBOXSOLTHREADINFO) },
239 { "/proc/%d/lstatus", 0, 0, 0 },
240 { "/proc/%d/ldt", 0, 0, 0 },
241 { "/proc/%d/cred", sizeof(prcred_t), sizeof(gid_t), 1 },
242 { "/proc/%d/priv", sizeof(prpriv_t), sizeof(priv_chunk_t), 1 },
243 };
244
245 size_t cb = 0;
246 for (int i = 0; i < (int)RT_ELEMENTS(aPreAllocTable); i++)
247 {
248 char szPath[PATH_MAX];
249 RTStrPrintf(szPath, sizeof(szPath), aPreAllocTable[i].pszFilePath, (int)pVBoxCore->VBoxProc.Process);
250 size_t cbFile = GetFileSize(szPath);
251 cb += cbFile;
252 if ( cbFile > 0
253 && aPreAllocTable[i].cbEntry > 0
254 && aPreAllocTable[i].cbAccounting > 0)
255 {
256 cb += ((cbFile - aPreAllocTable[i].cbHeader) / aPreAllocTable[i].cbEntry) * aPreAllocTable[i].cbAccounting;
257 cb += aPreAllocTable[i].cbHeader;
258 }
259 }
260
261 /*
262 * Make Room for our own mapping accountant entry which will also be included in the core.
263 */
264 cb += sizeof(VBOXSOLMAPINFO);
265
266 /*
267 * Allocate the required space, plus some extra room.
268 */
269 cb += _128K;
270 void *pv = mmap(NULL, cb, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1 /* fd */, 0 /* offset */);
271 if (pv)
272 {
273 CORELOG(("AllocMemoryArea: memory area of %u bytes allocated.\n", cb));
274 pVBoxCore->pvCore = pv;
275 pVBoxCore->pvFree = pv;
276 pVBoxCore->cbCore = cb;
277 return VINF_SUCCESS;
278 }
279 else
280 {
281 CORELOGREL(("AllocMemoryArea: failed cb=%u\n", cb));
282 return VERR_NO_MEMORY;
283 }
284}
285
286
287/**
288 * Free memory area used by the core object.
289 *
290 * @param pVBoxCore Pointer to the core object.
291 */
292void FreeMemoryArea(PVBOXCORE pVBoxCore)
293{
294 AssertReturnVoid(pVBoxCore);
295 AssertReturnVoid(pVBoxCore->pvCore);
296 AssertReturnVoid(pVBoxCore->cbCore > 0);
297
298 munmap(pVBoxCore->pvCore, pVBoxCore->cbCore);
299 CORELOG(("FreeMemoryArea: memory area of %u bytes freed.\n", pVBoxCore->cbCore));
300
301 pVBoxCore->pvCore = NULL;
302 pVBoxCore->pvFree= NULL;
303 pVBoxCore->cbCore = 0;
304}
305
306
307/**
308 * Get a chunk from the area of allocated memory.
309 *
310 * @param pVBoxCore Pointer to the core object.
311 * @param cb Size of requested chunk.
312 *
313 * @return Pointer to allocated memory, or NULL on failure.
314 */
315void *GetMemoryChunk(PVBOXCORE pVBoxCore, size_t cb)
316{
317 AssertReturn(pVBoxCore, NULL);
318 AssertReturn(pVBoxCore->pvCore, NULL);
319 AssertReturn(pVBoxCore->pvFree, NULL);
320
321 size_t cbAllocated = (char *)pVBoxCore->pvFree - (char *)pVBoxCore->pvCore;
322 if (cbAllocated < pVBoxCore->cbCore)
323 {
324 char *pb = (char *)pVBoxCore->pvFree;
325 pVBoxCore->pvFree = pb + cb;
326 return pb;
327 }
328
329 return NULL;
330}
331
332
333/**
334 * Reads the proc file's content into a newly allocated buffer.
335 *
336 * @param pVBoxCore Pointer to the core object.
337 * @param pszFileFmt Only the name of the file to read from (/proc/<pid> will be prepended)
338 * @param ppv Where to store the allocated buffer.
339 * @param pcb Where to store size of the buffer.
340 *
341 * @return VBox status code.
342 */
343int ProcReadFileInto(PVBOXCORE pVBoxCore, const char *pszProcFileName, void **ppv, size_t *pcb)
344{
345 AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
346
347 char szPath[PATH_MAX];
348 RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/%s", (int)pVBoxCore->VBoxProc.Process, pszProcFileName);
349 RTFILE hFile;
350 int rc = RTFileOpen(&hFile, szPath, RTFILE_O_OPEN | RTFILE_O_READ);
351 if (RT_SUCCESS(rc))
352 {
353 RTFileGetSize(hFile, (uint64_t *)pcb);
354 if (*pcb > 0)
355 {
356 *ppv = GetMemoryChunk(pVBoxCore, *pcb);
357 if (*ppv)
358 rc = ReadFileNoIntr(hFile, *ppv, *pcb);
359 else
360 rc = VERR_NO_MEMORY;
361 }
362 else
363 {
364 *pcb = 0;
365 *ppv = NULL;
366 }
367 RTFileClose(hFile);
368 }
369 else
370 CORELOGREL(("ProcReadFileInto: failed to open %s. rc=%Rrc\n", szPath, rc));
371 return rc;
372}
373
374
375/**
376 * Reads an ELF header from the given offset in a file.
377 *
378 * @param hFile The file to read.
379 * @param off The offset where ELF header resides.
380 * @param pHdr Where to store the read-in ELF header.
381 * @param pcSecHdrs Where to store the number of section headers.
382 * @param pSecHdrIndex Where to store the section header index.
383 * @param pcProgHdrs Where to store the number of program headers.
384 *
385 * @return VBox status code.
386 */
387int ElfReadHdr(RTFILE hFile, RTFOFF off, Ehdr *pHdr, uint32_t *pcSecHdrs, uint32_t *pSecHdrIndex, uint32_t *pcProgHdrs)
388{
389 /*
390 * Read ELF header from the given position.
391 */
392 int rc = ReadFileAt(hFile, pHdr, sizeof(Ehdr), off) != sizeof(Ehdr);
393 if (RT_FAILURE(rc))
394 {
395 CORELOGREL(("ElfReadHdr: pfnRead failed rc=%d\n", rc));
396 return VERR_READ_ERROR;
397 }
398
399 /*
400 * Validate ELF header.
401 */
402 if ( pHdr->e_ident[EI_MAG0] != ELFMAG0
403 || pHdr->e_ident[EI_MAG1] != ELFMAG1
404 || pHdr->e_ident[EI_MAG2] != ELFMAG2
405 || pHdr->e_ident[EI_MAG3] != ELFMAG3
406#ifdef BIG_ENDIAN
407 || pHdr->e_ident[EI_DATA] != ELFDATA2MSB
408#else
409 || pHdr->e_ident[EI_DATA] != ELFDATA2LSB
410#endif
411 || pHdr->e_ident[EI_VERSION] != EV_CURRENT)
412 {
413 CORELOGREL(("ElfReadHdr: Bad format(1)\n", rc));
414 return VERR_BAD_EXE_FORMAT;
415 }
416
417 if (
418#ifdef RT_ARCH_AMD64
419 pHdr->e_ident[EI_CLASS] != ELFCLASS64
420 || ( pHdr->e_machine != EM_AMD64
421 && pHdr->e_machine != EM_X86_64)
422#else
423 pHdr->e_ident[EI_CLASS] != ELFCLASS32
424 || ( pHdr->e_machine != EM_386
425 && pHdr->e_machine != EM_486)
426#endif
427 )
428 {
429 CORELOGREL(("ElfReadHdr: Bad format(2)\n", rc));
430 return VERR_BAD_EXE_FORMAT;
431 }
432
433 if ( pHdr->e_type != ET_EXEC
434 && pHdr->e_type != ET_DYN)
435 {
436 CORELOGREL(("ElfReadHdr: Bad format(3)\n", rc));
437 return VERR_BAD_EXE_FORMAT;
438 }
439
440 if ( pHdr->e_shoff < pHdr->e_ehsize
441 && !(pHdr->e_shoff && pHdr->e_shnum))
442 {
443 CORELOGREL(("ElfReadHdr: Section headers overlap ELF header!\n"));
444 return VERR_BAD_EXE_FORMAT;
445 }
446
447 uint64_t cbFileSize = 0;
448 rc = RTFileGetSize(hFile, &cbFileSize);
449 if ( RT_SUCCESS(rc)
450 && ( pHdr->e_shoff + pHdr->e_shnum * pHdr->e_shentsize > cbFileSize
451 || pHdr->e_shoff + pHdr->e_shnum * pHdr->e_shentsize < pHdr->e_shoff))
452 {
453 CORELOGREL(("ElfReadHdr: Section headers goes beyond file cbFileSize=%u shoff=%u\n", cbFileSize, pHdr->e_shoff));
454 return VERR_BAD_EXE_FORMAT;
455 }
456
457 *pcSecHdrs = pHdr->e_shnum;
458 *pSecHdrIndex = pHdr->e_shstrndx;
459 *pcProgHdrs = pHdr->e_phnum;
460
461 /*
462 * If pcSecHdrs, pSecHdrIndex or pcProgHdrs is at it's max value, we need to
463 * read the section header at index 0 for getting the real values.
464 */
465 if ( (*pcSecHdrs == 0 && pHdr->e_shoff != 0)
466 || *pSecHdrIndex == SHN_XINDEX
467 || *pcProgHdrs == PN_XNUM)
468 {
469 Shdr SecHdr;
470 if (pHdr->e_shoff == 0)
471 {
472 CORELOGREL(("ElfReadHdr: invalid section header offset %d\n", pHdr->e_shoff));
473 return VERR_ELF_EXE_NOT_SUPPORTED;
474 }
475
476 rc = ReadFileAt(hFile, &SecHdr, sizeof(SecHdr), pHdr->e_shoff);
477 if (RT_SUCCESS(rc))
478 {
479 if (*pcSecHdrs == 0)
480 *pcSecHdrs = SecHdr.sh_size;
481 if (*pSecHdrIndex == SHN_XINDEX)
482 *pSecHdrIndex = SecHdr.sh_link;
483 if (*pcProgHdrs == PN_XNUM && SecHdr.sh_info != 0)
484 *pcProgHdrs = SecHdr.sh_info;
485 }
486 else
487 return rc;
488 }
489
490 return VINF_SUCCESS;
491}
492
493
494/**
495 * Read a section header from an ELF file.
496 *
497 * @param hFile The file to read.
498 * @param offElfStart Offset that represents the start of the ELF header.
499 * @param pHdr Pointer to the ELF header.
500 * @param cSecHdrs Number of section headers.
501 * @param SecHdrIndex Index into the section header table.
502 * @param ppvSecHdr Where to store the pointer to the read-in section header.
503 * @param pcbSecHdr Where to store the size of the read-in section header.
504 * @param ppszSecHdrStr Where to store the section header string table.
505 * @param pcbSecHdrStr Where to store the size of the section header string table.
506 *
507 * @return VBox status code.
508 */
509int ElfReadSecHdr(PVBOXCORE pVBoxCore, RTFILE hFile, RTFOFF offElfStart, const Ehdr *pHdr, uint32_t cSecHdrs, uint32_t SecHdrIndex,
510 void **ppvSecHdr, size_t *pcbSecHdr, char **ppszSecHdrStr, size_t *pcbSecHdrStr)
511{
512 AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
513 PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
514
515 /*
516 * Since we use e_shentsize to index into the array of section headers, make sure it's 8-byte aligned.
517 * We use all the members through sh_entsize (on both 32, 64 bit) so e_shentsize must be large enough.
518 */
519 Shdr *pSecHdr;
520 ssize_t cSize = RT_OFFSETOF(Shdr, sh_entsize) + sizeof(pSecHdr->sh_entsize);
521 if ( pHdr->e_shentsize < cSize
522 || (pHdr->e_shentsize & 3) != 0
523 || SecHdrIndex > cSecHdrs)
524 {
525 CORELOGREL(("ElfReadSecHdr: invalid format\n"));
526 return VERR_BAD_EXE_FORMAT;
527 }
528
529 /*
530 * Allocate & read in the section header.
531 */
532 int rc = VINF_SUCCESS;
533 *pcbSecHdr = cSecHdrs * pHdr->e_shentsize;
534 *ppvSecHdr = GetMemoryChunk(pVBoxCore, *pcbSecHdr);
535 if (!*ppvSecHdr)
536 {
537 rc = ReadFileAt(hFile, *ppvSecHdr, *pcbSecHdr, pHdr->e_shoff);
538 if (RT_SUCCESS(rc))
539 {
540 /*
541 * Allocate & read in the section string table.
542 */
543 pSecHdr = (Shdr *)((char *)*ppvSecHdr + SecHdrIndex * pHdr->e_shentsize);
544 if (pSecHdr->sh_size > 0)
545 {
546 *pcbSecHdrStr = pSecHdr->sh_size;
547 *ppszSecHdrStr = (char *)GetMemoryChunk(pVBoxCore, *pcbSecHdrStr);
548 if (*ppszSecHdrStr)
549 {
550 rc = ReadFileAt(hFile, *ppszSecHdrStr, *pcbSecHdrStr, pSecHdr->sh_offset);
551 if (RT_SUCCESS(rc))
552 {
553 (*ppszSecHdrStr)[*pcbSecHdrStr - 1] = '\0';
554 return VINF_SUCCESS;
555 }
556 else
557 CORELOGREL(("ElfReadSecHdr: failed to read section header string table at %u\n", pSecHdr->sh_offset));
558 }
559 else
560 rc = VERR_NO_MEMORY;
561 }
562 else
563 {
564 CORELOGREL(("ElfReadSecHdr: invalid section header string table size\n"));
565 rc = VERR_BAD_EXE_FORMAT;
566 }
567 }
568 else
569 CORELOGREL(("ElfReadSecHdr: failed to read section header at %u\n", pHdr->e_shoff));
570
571 *ppvSecHdr = NULL;
572 *pcbSecHdr = 0;
573 }
574 else
575 rc = VERR_NO_MEMORY;
576
577 return rc;
578}
579
580
581/**
582 * Read process information (format psinfo_t) from /proc.
583 *
584 * @param pVBoxCore Pointer to the core object.
585 *
586 * @return VBox status code.
587 */
588int ReadProcInfo(PVBOXCORE pVBoxCore)
589{
590 AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
591
592 PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
593 char szPath[PATH_MAX];
594 RTFILE hFile;
595
596 RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/psinfo", (int)pVBoxProc->Process);
597 int rc = RTFileOpen(&hFile, szPath, RTFILE_O_OPEN | RTFILE_O_READ);
598 if (RT_SUCCESS(rc))
599 {
600 size_t cbProcInfo = sizeof(psinfo_t);
601 rc = ReadFileNoIntr(hFile, &pVBoxProc->ProcInfo, cbProcInfo);
602 }
603
604 RTFileClose(hFile);
605 return rc;
606}
607
608
609/**
610 * Read process status (format pstatus_t) from /proc.
611 *
612 * @param pVBoxCore Pointer to the core object.
613 *
614 * @return VBox status code.
615 */
616int ReadProcStatus(PVBOXCORE pVBoxCore)
617{
618 AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
619
620 PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
621
622 char szPath[PATH_MAX];
623 RTFILE hFile;
624
625 RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/status", (int)pVBoxProc->Process);
626 int rc = RTFileOpen(&hFile, szPath, RTFILE_O_OPEN | RTFILE_O_READ);
627 if (RT_SUCCESS(rc))
628 {
629 size_t cbRead;
630 size_t cbProcStatus = sizeof(pstatus_t);
631 AssertCompile(sizeof(pstatus_t) == sizeof(pVBoxProc->ProcStatus));
632 rc = ReadFileNoIntr(hFile, &pVBoxProc->ProcStatus, cbProcStatus);
633 }
634 RTFileClose(hFile);
635 return rc;
636}
637
638
639/**
640 * Read process credential information (format prcred_t + array of guid_t)
641 *
642 * @param pVBoxCore Pointer to the core object.
643 *
644 * @remarks Should not be called before successful call to @see AllocMemoryArea()
645 * @return VBox status code.
646 */
647int ReadProcCred(PVBOXCORE pVBoxCore)
648{
649 AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
650
651 PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
652 return ProcReadFileInto(pVBoxCore, "cred", &pVBoxProc->pvCred, &pVBoxProc->cbCred);
653}
654
655
656/**
657 * Read process privilege information (format prpriv_t + array of priv_chunk_t)
658 *
659 * @param pVBoxCore Pointer to the core object.
660 *
661 * @remarks Should not be called before successful call to @see AllocMemoryArea()
662 * @return VBox status code.
663 */
664int ReadProcPriv(PVBOXCORE pVBoxCore)
665{
666 AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
667
668 PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
669 int rc = ProcReadFileInto(pVBoxCore, "priv", (void **)&pVBoxProc->pPriv, &pVBoxProc->cbPriv);
670 if (RT_FAILURE(rc))
671 return rc;
672 pVBoxProc->pcPrivImpl = getprivimplinfo();
673 if (!pVBoxProc->pcPrivImpl)
674 {
675 CORELOGREL(("ReadProcPriv: getprivimplinfo returned NULL.\n"));
676 return VERR_INVALID_STATE;
677 }
678 return rc;
679}
680
681
682/**
683 * Read process LDT information (format array of struct ssd) from /proc.
684 *
685 * @param pVBoxProc Pointer to the core object.
686 *
687 * @remarks Should not be called before successful call to @see AllocMemoryArea()
688 * @return VBox status code.
689 */
690int ReadProcLdt(PVBOXCORE pVBoxCore)
691{
692 AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
693
694 PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
695 return ProcReadFileInto(pVBoxCore, "ldt", &pVBoxProc->pvLdt, &pVBoxProc->cbLdt);
696}
697
698
699/**
700 * Read process auxiliary vectors (format auxv_t) for the process.
701 *
702 * @param pVBoxCore Pointer to the core object.
703 *
704 * @remarks Should not be called before successful call to @see AllocMemoryArea()
705 * @return VBox status code.
706 */
707int ReadProcAuxVecs(PVBOXCORE pVBoxCore)
708{
709 AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
710
711 PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
712 char szPath[PATH_MAX];
713 RTFILE hFile = NIL_RTFILE;
714 RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/auxv", (int)pVBoxProc->Process);
715 int rc = RTFileOpen(&hFile, szPath, RTFILE_O_OPEN | RTFILE_O_READ);
716 if (RT_FAILURE(rc))
717 {
718 CORELOGREL(("ReadProcAuxVecs: RTFileOpen %s failed rc=%Rrc\n", szPath, rc));
719 return rc;
720 }
721
722 size_t cbAuxFile = 0;
723 RTFileGetSize(hFile, (uint64_t *)&cbAuxFile);
724 if (cbAuxFile >= sizeof(auxv_t))
725 {
726 pVBoxProc->pAuxVecs = (auxv_t*)GetMemoryChunk(pVBoxCore, cbAuxFile + sizeof(auxv_t));
727 if (pVBoxProc->pAuxVecs)
728 {
729 rc = ReadFileNoIntr(hFile, pVBoxProc->pAuxVecs, cbAuxFile);
730 if (RT_SUCCESS(rc))
731 {
732 /* Terminate list of vectors */
733 pVBoxProc->cAuxVecs = cbAuxFile / sizeof(auxv_t);
734 CORELOG(("ReadProcAuxVecs: cbAuxFile=%u auxv_t size %d cAuxVecs=%u\n", cbAuxFile, sizeof(auxv_t), pVBoxProc->cAuxVecs));
735 if (pVBoxProc->cAuxVecs > 0)
736 {
737 pVBoxProc->pAuxVecs[pVBoxProc->cAuxVecs].a_type = AT_NULL;
738 pVBoxProc->pAuxVecs[pVBoxProc->cAuxVecs].a_un.a_val = 0L;
739 RTFileClose(hFile);
740 return VINF_SUCCESS;
741 }
742 else
743 {
744 CORELOGREL(("ReadProcAuxVecs: Invalid vector count %u\n", pVBoxProc->cAuxVecs));
745 rc = VERR_READ_ERROR;
746 }
747 }
748 else
749 CORELOGREL(("ReadProcAuxVecs: ReadFileNoIntr failed. rc=%Rrc cbAuxFile=%u\n", rc, cbAuxFile));
750
751 pVBoxProc->pAuxVecs = NULL;
752 pVBoxProc->cAuxVecs = 0;
753 }
754 else
755 {
756 CORELOGREL(("ReadProcAuxVecs: no memory for %u bytes\n", cbAuxFile + sizeof(auxv_t)));
757 rc = VERR_NO_MEMORY;
758 }
759 }
760 else
761 CORELOGREL(("ReadProcAuxVecs: aux file too small %u, expecting %u or more\n", cbAuxFile, sizeof(auxv_t)));
762
763 RTFileClose(hFile);
764 return rc;
765}
766
767
768/*
769 * Find an element in the process' auxiliary vector.
770 */
771long GetAuxVal(PVBOXPROCESS pVBoxProc, int Type)
772{
773 AssertReturn(pVBoxProc, -1);
774 if (pVBoxProc->pAuxVecs)
775 {
776 auxv_t *pAuxVec = pVBoxProc->pAuxVecs;
777 for (; pAuxVec->a_type != AT_NULL; pAuxVec++)
778 {
779 if (pAuxVec->a_type == Type)
780 return pAuxVec->a_un.a_val;
781 }
782 }
783 return -1;
784}
785
786
787/**
788 * Read the process mappings (format prmap_t array).
789 *
790 * @param pVBoxCore Pointer to the core object.
791 *
792 * @remarks Should not be called before successful call to @see AllocMemoryArea()
793 * @return VBox status code.
794 */
795int ReadProcMappings(PVBOXCORE pVBoxCore)
796{
797 AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
798
799 PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
800 char szPath[PATH_MAX];
801 RTFILE hFile = NIL_RTFILE;
802 RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/map", (int)pVBoxProc->Process);
803 int rc = RTFileOpen(&hFile, szPath, RTFILE_O_OPEN | RTFILE_O_READ);
804 if (RT_FAILURE(rc))
805 return rc;
806
807 RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/as", (int)pVBoxProc->Process);
808 rc = RTFileOpen(&pVBoxProc->hAs, szPath, RTFILE_O_OPEN | RTFILE_O_READ);
809 if (RT_SUCCESS(rc))
810 {
811 /*
812 * Allocate and read all the prmap_t objects from proc.
813 */
814 size_t cbMapFile = 0;
815 RTFileGetSize(hFile, (uint64_t *)&cbMapFile);
816 if (cbMapFile >= sizeof(prmap_t))
817 {
818 prmap_t *pMap = (prmap_t*)GetMemoryChunk(pVBoxCore, cbMapFile);
819 if (pMap)
820 {
821 rc = ReadFileNoIntr(hFile, pMap, cbMapFile);
822 if (RT_SUCCESS(rc))
823 {
824 pVBoxProc->cMappings = cbMapFile / sizeof(prmap_t);
825 if (pVBoxProc->cMappings > 0)
826 {
827 /*
828 * Allocate for each prmap_t object, a corresponding VBOXSOLMAPINFO object.
829 */
830 pVBoxProc->pMapInfoHead = (PVBOXSOLMAPINFO)GetMemoryChunk(pVBoxCore, pVBoxProc->cMappings * sizeof(VBOXSOLMAPINFO));
831 if (pVBoxProc->pMapInfoHead)
832 {
833 /*
834 * Associate the prmap_t with the mapping info object.
835 */
836 Assert(pVBoxProc->pMapInfoHead == NULL);
837 PVBOXSOLMAPINFO pCur = pVBoxProc->pMapInfoHead;
838 PVBOXSOLMAPINFO pPrev = NULL;
839 for (uint64_t i = 0; i < pVBoxProc->cMappings; i++, pMap++, pCur++)
840 {
841 pCur->pMap = *pMap;
842 if (pPrev)
843 pPrev->pNext = pCur;
844
845 pCur->fError = 0;
846
847 /*
848 * Make sure we can read the mapping, otherwise mark them to be skipped.
849 */
850 char achBuf[PAGE_SIZE];
851 uint64_t k = 0;
852 while (k < pCur->pMap.pr_size)
853 {
854 size_t cb = RT_MIN(sizeof(achBuf), pCur->pMap.pr_size - k);
855 int rc2 = ReadProcAddrSpace(pVBoxProc, &achBuf, cb, pCur->pMap.pr_vaddr + k);
856 if (RT_FAILURE(rc2))
857 {
858 CORELOGREL(("ReadProcMappings: skipping mapping. vaddr=%#x rc=%Rrc\n", pCur->pMap.pr_vaddr, rc2));
859
860 /*
861 * Instead of storing the actual mapping data which we failed to read, the core
862 * will contain an errno in place. So we adjust the prmap_t's size field too
863 * so the program header offsets match.
864 */
865 pCur->pMap.pr_size = RT_ALIGN_Z(sizeof(int), 8);
866 pCur->fError = errno;
867 if (pCur->fError == 0) /* huh!? somehow errno got reset? fake one! EFAULT is nice. */
868 pCur->fError = EFAULT;
869 break;
870 }
871 k += cb;
872 }
873
874 pPrev = pCur;
875 }
876 if (pPrev)
877 pPrev->pNext = NULL;
878
879 RTFileClose(hFile);
880 RTFileClose(pVBoxProc->hAs);
881 pVBoxProc->hAs = NIL_RTFILE;
882 CORELOG(("ReadProcMappings: successfully read in %u mappings\n", pVBoxProc->cMappings));
883 return VINF_SUCCESS;
884 }
885 else
886 {
887 CORELOGREL(("ReadProcMappings: GetMemoryChunk failed %u\n", pVBoxProc->cMappings * sizeof(VBOXSOLMAPINFO)));
888 rc = VERR_NO_MEMORY;
889 }
890 }
891 else
892 {
893 CORELOGREL(("ReadProcMappings: Invalid mapping count %u\n", pVBoxProc->cMappings));
894 rc = VERR_READ_ERROR;
895 }
896 }
897 else
898 CORELOGREL(("ReadProcMappings: FileReadNoIntr failed. rc=%Rrc cbMapFile=%u\n", rc, cbMapFile));
899 }
900 else
901 {
902 CORELOGREL(("ReadProcMappings: GetMemoryChunk failed. cbMapFile=%u\n", cbMapFile));
903 rc = VERR_NO_MEMORY;
904 }
905 }
906
907 RTFileClose(pVBoxProc->hAs);
908 pVBoxProc->hAs = NIL_RTFILE;
909 }
910 else
911 CORELOGREL(("ReadProcMappings: failed to open %s. rc=%Rrc\n", szPath, rc));
912
913 RTFileClose(hFile);
914 return rc;
915}
916
917
918/**
919 * Reads the thread information for all threads in the process.
920 *
921 * @param pVBoxCore Pointer to the core object.
922 *
923 * @remarks Should not be called before successful call to @see AllocMemoryArea()
924 * @return VBox status code.
925 */
926int ReadProcThreads(PVBOXCORE pVBoxCore)
927{
928 AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
929
930 PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
931 AssertReturn(pVBoxProc->pCurThreadCtx, VERR_NO_DATA);
932
933 /*
934 * Read the information for threads.
935 * Format: prheader_t + array of lwpsinfo_t's.
936 */
937 size_t cbInfoHdrAndData;
938 void *pvInfoHdr = NULL;
939 int rc = ProcReadFileInto(pVBoxCore, "lpsinfo", &pvInfoHdr, &cbInfoHdrAndData);
940 if (RT_SUCCESS(rc))
941 {
942 /*
943 * Read the status of threads.
944 * Format: prheader_t + array of lwpstatus_t's.
945 */
946 void *pvStatusHdr = NULL;
947 size_t cbStatusHdrAndData;
948 rc = ProcReadFileInto(pVBoxCore, "lstatus", &pvStatusHdr, &cbStatusHdrAndData);
949 if (RT_SUCCESS(rc))
950 {
951 prheader_t *pInfoHdr = (prheader_t *)pvInfoHdr;
952 prheader_t *pStatusHdr = (prheader_t *)pvStatusHdr;
953 lwpstatus_t *pStatus = (lwpstatus_t *)((uintptr_t)pStatusHdr + sizeof(prheader_t));
954 lwpsinfo_t *pInfo = (lwpsinfo_t *)((uintptr_t)pInfoHdr + sizeof(prheader_t));
955 uint64_t cStatus = pStatusHdr->pr_nent;
956 uint64_t cInfo = pInfoHdr->pr_nent;
957
958 CORELOG(("ReadProcThreads: read info(%u) status(%u), threads:cInfo=%u cStatus=%u\n", cbInfoHdrAndData, cbStatusHdrAndData, cInfo, cStatus));
959
960 /*
961 * Minor sanity size check (remember sizeof lwpstatus_t & lwpsinfo_t is <= size in file per entry).
962 */
963 if ( (cbStatusHdrAndData - sizeof(prheader_t)) % pStatusHdr->pr_entsize == 0
964 && (cbInfoHdrAndData - sizeof(prheader_t)) % pInfoHdr->pr_entsize == 0)
965 {
966 /*
967 * Make sure we have a matching lstatus entry for an lpsinfo entry unless
968 * it is a zombie thread, in which case we will not have a matching lstatus entry.
969 */
970 for (; cInfo != 0; cInfo--)
971 {
972 if (pInfo->pr_sname != 'Z') /* zombie */
973 {
974 if ( cStatus == 0
975 || pStatus->pr_lwpid != pInfo->pr_lwpid)
976 {
977 CORELOGREL(("ReadProcThreads: cStatus = %u pStatuslwpid=%d infolwpid=%d\n", cStatus, pStatus->pr_lwpid, pInfo->pr_lwpid));
978 rc = VERR_INVALID_STATE;
979 break;
980 }
981 pStatus = (lwpstatus_t *)((uintptr_t)pStatus + pStatusHdr->pr_entsize);
982 cStatus--;
983 }
984 pInfo = (lwpsinfo_t *)((uintptr_t)pInfo + pInfoHdr->pr_entsize);
985 }
986
987 if (RT_SUCCESS(rc))
988 {
989 /*
990 * Threre can still be more lwpsinfo_t's than lwpstatus_t's, build the
991 * lists accordingly.
992 */
993 pStatus = (lwpstatus_t *)((uintptr_t)pStatusHdr + sizeof(prheader_t));
994 pInfo = (lwpsinfo_t *)((uintptr_t)pInfoHdr + sizeof(prheader_t));
995 cInfo = pInfoHdr->pr_nent;
996 cStatus = pInfoHdr->pr_nent;
997
998 size_t cbThreadInfo = RT_MAX(cStatus, cInfo) * sizeof(VBOXSOLTHREADINFO);
999 pVBoxProc->pThreadInfoHead = (PVBOXSOLTHREADINFO)GetMemoryChunk(pVBoxCore, cbThreadInfo);
1000 if (pVBoxProc->pThreadInfoHead)
1001 {
1002 PVBOXSOLTHREADINFO pCur = pVBoxProc->pThreadInfoHead;
1003 PVBOXSOLTHREADINFO pPrev = NULL;
1004 for (uint64_t i = 0; i < cInfo; i++, pCur++)
1005 {
1006 pCur->Info = *pInfo;
1007 if ( pInfo->pr_sname != 'Z'
1008 && pInfo->pr_lwpid == pStatus->pr_lwpid)
1009 {
1010 /*
1011 * Adjust the context of the dumping thread to reflect the context
1012 * when the core dump got initiated before whatever signal caused it.
1013 */
1014 if ( pStatus /* noid droid */
1015 && pStatus->pr_lwpid == (id_t)pVBoxProc->hCurThread)
1016 {
1017 AssertCompile(sizeof(pStatus->pr_reg) == sizeof(pVBoxProc->pCurThreadCtx->uc_mcontext.gregs));
1018 AssertCompile(sizeof(pStatus->pr_fpreg) == sizeof(pVBoxProc->pCurThreadCtx->uc_mcontext.fpregs));
1019 memcpy(&pStatus->pr_reg, &pVBoxProc->pCurThreadCtx->uc_mcontext.gregs, sizeof(pStatus->pr_reg));
1020 memcpy(&pStatus->pr_fpreg, &pVBoxProc->pCurThreadCtx->uc_mcontext.fpregs, sizeof(pStatus->pr_fpreg));
1021
1022 AssertCompile(sizeof(pStatus->pr_lwphold) == sizeof(pVBoxProc->pCurThreadCtx->uc_sigmask));
1023 memcpy(&pStatus->pr_lwphold, &pVBoxProc->pCurThreadCtx->uc_sigmask, sizeof(pStatus->pr_lwphold));
1024 pStatus->pr_ustack = (uintptr_t)&pVBoxProc->pCurThreadCtx->uc_stack;
1025
1026 CORELOG(("ReadProcThreads: patched dumper thread context with pre-dump time context.\n"));
1027 }
1028
1029 pCur->pStatus = pStatus;
1030 pStatus = (lwpstatus_t *)((uintptr_t)pStatus + pStatusHdr->pr_entsize);
1031 }
1032 else
1033 {
1034 CORELOGREL(("ReadProcThreads: missing status for lwp %d\n", pInfo->pr_lwpid));
1035 pCur->pStatus = NULL;
1036 }
1037
1038 if (pPrev)
1039 pPrev->pNext = pCur;
1040 pPrev = pCur;
1041 pInfo = (lwpsinfo_t *)((uintptr_t)pInfo + pInfoHdr->pr_entsize);
1042 }
1043 if (pPrev)
1044 pPrev->pNext = NULL;
1045
1046 CORELOG(("ReadProcThreads: successfully read %u threads.\n", cInfo));
1047 pVBoxProc->cThreads = cInfo;
1048 return VINF_SUCCESS;
1049 }
1050 else
1051 {
1052 CORELOGREL(("ReadProcThreads: GetMemoryChunk failed for %u bytes\n", cbThreadInfo));
1053 rc = VERR_NO_MEMORY;
1054 }
1055 }
1056 else
1057 CORELOGREL(("ReadProcThreads: Invalid state information for threads.\n", rc));
1058 }
1059 else
1060 {
1061 CORELOGREL(("ReadProcThreads: huh!? cbStatusHdrAndData=%u prheader_t=%u entsize=%u\n", cbStatusHdrAndData,
1062 sizeof(prheader_t), pStatusHdr->pr_entsize));
1063 CORELOGREL(("ReadProcThreads: huh!? cbInfoHdrAndData=%u entsize=%u\n", cbInfoHdrAndData, pStatusHdr->pr_entsize));
1064 rc = VERR_INVALID_STATE;
1065 }
1066 }
1067 else
1068 CORELOGREL(("ReadProcThreads: ReadFileNoIntr failed for \"lpsinfo\" rc=%Rrc\n", rc));
1069 }
1070 else
1071 CORELOGREL(("ReadProcThreads: ReadFileNoIntr failed for \"lstatus\" rc=%Rrc\n", rc));
1072 return rc;
1073}
1074
1075
1076/**
1077 * Reads miscellaneous information that is collected as part of a core file.
1078 * This may include platform name, zone name and other OS-specific information.
1079 *
1080 * @param pVBoxCore Pointer to the core object.
1081 *
1082 * @return VBox status code.
1083 */
1084int ReadProcMiscInfo(PVBOXCORE pVBoxCore)
1085{
1086 AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
1087
1088 PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
1089
1090#ifdef RT_OS_SOLARIS
1091 /*
1092 * Read the platform name, uname string and zone name.
1093 */
1094 int rc = sysinfo(SI_PLATFORM, pVBoxProc->szPlatform, sizeof(pVBoxProc->szPlatform));
1095 if (rc == -1)
1096 {
1097 CORELOGREL(("ReadProcMiscInfo: sysinfo failed. rc=%d errno=%d\n", rc, errno));
1098 return VERR_GENERAL_FAILURE;
1099 }
1100 pVBoxProc->szPlatform[sizeof(pVBoxProc->szPlatform) - 1] = '\0';
1101
1102 rc = uname(&pVBoxProc->UtsName);
1103 if (rc == -1)
1104 {
1105 CORELOGREL(("ReadProcMiscInfo: uname failed. rc=%d errno=%d\n", rc, errno));
1106 return VERR_GENERAL_FAILURE;
1107 }
1108
1109 rc = getzonenamebyid(pVBoxProc->ProcInfo.pr_zoneid, pVBoxProc->szZoneName, sizeof(pVBoxProc->szZoneName));
1110 if (rc < 0)
1111 {
1112 CORELOGREL(("ReadProcMiscInfo: getzonenamebyid failed. rc=%d errno=%d zoneid=%d\n", rc, errno, pVBoxProc->ProcInfo.pr_zoneid));
1113 return VERR_GENERAL_FAILURE;
1114 }
1115 pVBoxProc->szZoneName[sizeof(pVBoxProc->szZoneName) - 1] = '\0';
1116 rc = VINF_SUCCESS;
1117
1118#else
1119# error Port Me!
1120#endif
1121 return rc;
1122}
1123
1124
1125/**
1126 * On Solaris use the old-style procfs interfaces but the core file still should have this
1127 * info. for backward and GDB compatibility, hence the need for this ugly function.
1128 *
1129 * @param pVBoxCore Pointer to the core object.
1130 * @param pInfo Pointer to the old prpsinfo_t structure to update.
1131 */
1132void GetOldProcessInfo(PVBOXCORE pVBoxCore, prpsinfo_t *pInfo)
1133{
1134 AssertReturnVoid(pVBoxCore);
1135 AssertReturnVoid(pInfo);
1136
1137 PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
1138 psinfo_t *pSrc = &pVBoxProc->ProcInfo;
1139 memset(pInfo, 0, sizeof(prpsinfo_t));
1140 pInfo->pr_state = pSrc->pr_lwp.pr_state;
1141 pInfo->pr_zomb = (pInfo->pr_state == SZOMB);
1142 RTStrCopy(pInfo->pr_clname, sizeof(pInfo->pr_clname), pSrc->pr_lwp.pr_clname);
1143 RTStrCopy(pInfo->pr_fname, sizeof(pInfo->pr_fname), pSrc->pr_fname);
1144 memcpy(&pInfo->pr_psargs, &pSrc->pr_psargs, sizeof(pInfo->pr_psargs));
1145 pInfo->pr_nice = pSrc->pr_lwp.pr_nice;
1146 pInfo->pr_flag = pSrc->pr_lwp.pr_flag;
1147 pInfo->pr_uid = pSrc->pr_uid;
1148 pInfo->pr_gid = pSrc->pr_gid;
1149 pInfo->pr_pid = pSrc->pr_pid;
1150 pInfo->pr_ppid = pSrc->pr_ppid;
1151 pInfo->pr_pgrp = pSrc->pr_pgid;
1152 pInfo->pr_sid = pSrc->pr_sid;
1153 pInfo->pr_addr = (caddr_t)pSrc->pr_addr;
1154 pInfo->pr_size = pSrc->pr_size;
1155 pInfo->pr_rssize = pSrc->pr_rssize;
1156 pInfo->pr_wchan = (caddr_t)pSrc->pr_lwp.pr_wchan;
1157 pInfo->pr_start = pSrc->pr_start;
1158 pInfo->pr_time = pSrc->pr_time;
1159 pInfo->pr_pri = pSrc->pr_lwp.pr_pri;
1160 pInfo->pr_oldpri = pSrc->pr_lwp.pr_oldpri;
1161 pInfo->pr_cpu = pSrc->pr_lwp.pr_cpu;
1162 pInfo->pr_ottydev = cmpdev(pSrc->pr_ttydev);
1163 pInfo->pr_lttydev = pSrc->pr_ttydev;
1164 pInfo->pr_syscall = pSrc->pr_lwp.pr_syscall;
1165 pInfo->pr_ctime = pSrc->pr_ctime;
1166 pInfo->pr_bysize = pSrc->pr_size * PAGESIZE;
1167 pInfo->pr_byrssize = pSrc->pr_rssize * PAGESIZE;
1168 pInfo->pr_argc = pSrc->pr_argc;
1169 pInfo->pr_argv = (char **)pSrc->pr_argv;
1170 pInfo->pr_envp = (char **)pSrc->pr_envp;
1171 pInfo->pr_wstat = pSrc->pr_wstat;
1172 pInfo->pr_pctcpu = pSrc->pr_pctcpu;
1173 pInfo->pr_pctmem = pSrc->pr_pctmem;
1174 pInfo->pr_euid = pSrc->pr_euid;
1175 pInfo->pr_egid = pSrc->pr_egid;
1176 pInfo->pr_aslwpid = 0;
1177 pInfo->pr_dmodel = pSrc->pr_dmodel;
1178}
1179
1180
1181/**
1182 * On Solaris use the old-style procfs interfaces but the core file still should have this
1183 * info. for backward and GDB compatibility, hence the need for this ugly function.
1184 *
1185 * @param pVBoxCore Pointer to the core object.
1186 * @param pInfo Pointer to the thread info.
1187 * @param pStatus Pointer to the thread status.
1188 * @param pDst Pointer to the old-style status structure to update.
1189 *
1190 */
1191void GetOldProcessStatus(PVBOXCORE pVBoxCore, lwpsinfo_t *pInfo, lwpstatus_t *pStatus, prstatus_t *pDst)
1192{
1193 AssertReturnVoid(pVBoxCore);
1194 AssertReturnVoid(pInfo);
1195 AssertReturnVoid(pStatus);
1196 AssertReturnVoid(pDst);
1197
1198 PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
1199 memset(pDst, 0, sizeof(prstatus_t));
1200 if (pStatus->pr_flags & PR_STOPPED)
1201 pDst->pr_flags = 0x0001;
1202 if (pStatus->pr_flags & PR_ISTOP)
1203 pDst->pr_flags = 0x0002;
1204 if (pStatus->pr_flags & PR_DSTOP)
1205 pDst->pr_flags = 0x0004;
1206 if (pStatus->pr_flags & PR_ASLEEP)
1207 pDst->pr_flags = 0x0008;
1208 if (pStatus->pr_flags & PR_FORK)
1209 pDst->pr_flags = 0x0010;
1210 if (pStatus->pr_flags & PR_RLC)
1211 pDst->pr_flags = 0x0020;
1212 /* PR_PTRACE is never set */
1213 if (pStatus->pr_flags & PR_PCINVAL)
1214 pDst->pr_flags = 0x0080;
1215 if (pStatus->pr_flags & PR_ISSYS)
1216 pDst->pr_flags = 0x0100;
1217 if (pStatus->pr_flags & PR_STEP)
1218 pDst->pr_flags = 0x0200;
1219 if (pStatus->pr_flags & PR_KLC)
1220 pDst->pr_flags = 0x0400;
1221 if (pStatus->pr_flags & PR_ASYNC)
1222 pDst->pr_flags = 0x0800;
1223 if (pStatus->pr_flags & PR_PTRACE)
1224 pDst->pr_flags = 0x1000;
1225 if (pStatus->pr_flags & PR_MSACCT)
1226 pDst->pr_flags = 0x2000;
1227 if (pStatus->pr_flags & PR_BPTADJ)
1228 pDst->pr_flags = 0x4000;
1229 if (pStatus->pr_flags & PR_ASLWP)
1230 pDst->pr_flags = 0x8000;
1231
1232 pDst->pr_who = pStatus->pr_lwpid;
1233 pDst->pr_why = pStatus->pr_why;
1234 pDst->pr_what = pStatus->pr_what;
1235 pDst->pr_info = pStatus->pr_info;
1236 pDst->pr_cursig = pStatus->pr_cursig;
1237 pDst->pr_sighold = pStatus->pr_lwphold;
1238 pDst->pr_altstack = pStatus->pr_altstack;
1239 pDst->pr_action = pStatus->pr_action;
1240 pDst->pr_syscall = pStatus->pr_syscall;
1241 pDst->pr_nsysarg = pStatus->pr_nsysarg;
1242 pDst->pr_lwppend = pStatus->pr_lwppend;
1243 pDst->pr_oldcontext = (ucontext_t *)pStatus->pr_oldcontext;
1244 memcpy(pDst->pr_reg, pStatus->pr_reg, sizeof(pDst->pr_reg));
1245 memcpy(pDst->pr_sysarg, pStatus->pr_sysarg, sizeof(pDst->pr_sysarg));
1246 RTStrCopy(pDst->pr_clname, sizeof(pDst->pr_clname), pStatus->pr_clname);
1247
1248 pDst->pr_nlwp = pVBoxProc->ProcStatus.pr_nlwp;
1249 pDst->pr_sigpend = pVBoxProc->ProcStatus.pr_sigpend;
1250 pDst->pr_pid = pVBoxProc->ProcStatus.pr_pid;
1251 pDst->pr_ppid = pVBoxProc->ProcStatus.pr_ppid;
1252 pDst->pr_pgrp = pVBoxProc->ProcStatus.pr_pgid;
1253 pDst->pr_sid = pVBoxProc->ProcStatus.pr_sid;
1254 pDst->pr_utime = pVBoxProc->ProcStatus.pr_utime;
1255 pDst->pr_stime = pVBoxProc->ProcStatus.pr_stime;
1256 pDst->pr_cutime = pVBoxProc->ProcStatus.pr_cutime;
1257 pDst->pr_cstime = pVBoxProc->ProcStatus.pr_cstime;
1258 pDst->pr_brkbase = (caddr_t)pVBoxProc->ProcStatus.pr_brkbase;
1259 pDst->pr_brksize = pVBoxProc->ProcStatus.pr_brksize;
1260 pDst->pr_stkbase = (caddr_t)pVBoxProc->ProcStatus.pr_stkbase;
1261 pDst->pr_stksize = pVBoxProc->ProcStatus.pr_stksize;
1262
1263 pDst->pr_processor = (short)pInfo->pr_onpro;
1264 pDst->pr_bind = (short)pInfo->pr_bindpro;
1265 pDst->pr_instr = pStatus->pr_instr;
1266}
1267
1268
1269/**
1270 * Count the number of sections which will be dumped into the core file.
1271 *
1272 * @param pVBoxCore Pointer to the core object.
1273 *
1274 * @return Number of sections for the core file.
1275 */
1276uint32_t CountSections(PVBOXCORE pVBoxCore)
1277{
1278 /* @todo sections */
1279 NOREF(pVBoxCore);
1280 return 0;
1281}
1282
1283
1284/**
1285 * Resume all threads of this process.
1286 *
1287 * @param pVBoxProc Pointer to the VBox process.
1288 *
1289 * @return VBox error code.
1290 */
1291int ResumeAllThreads(PVBOXPROCESS pVBoxProc)
1292{
1293 AssertReturn(pVBoxProc, VERR_INVALID_POINTER);
1294
1295 char szCurThread[128];
1296 char szPath[PATH_MAX];
1297 PRTDIR pDir = NULL;
1298
1299 RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/lwp", (int)pVBoxProc->Process);
1300 RTStrPrintf(szCurThread, sizeof(szCurThread), "%d", (int)pVBoxProc->hCurThread);
1301
1302 int32_t cRunningThreads = 0;
1303 int rc = RTDirOpen(&pDir, szPath);
1304 if (RT_SUCCESS(rc))
1305 {
1306 /*
1307 * Loop through all our threads & resume them.
1308 */
1309 RTDIRENTRY DirEntry;
1310 while (RT_SUCCESS(RTDirRead(pDir, &DirEntry, NULL)))
1311 {
1312 if ( !strcmp(DirEntry.szName, ".")
1313 || !strcmp(DirEntry.szName, ".."))
1314 continue;
1315
1316 if ( !strcmp(DirEntry.szName, szCurThread))
1317 continue;
1318
1319 int32_t ThreadId = RTStrToInt32(DirEntry.szName);
1320 _lwp_continue((lwpid_t)ThreadId);
1321 ++cRunningThreads;
1322 }
1323
1324 CORELOG(("ResumeAllThreads: resumed %d threads\n", cRunningThreads));
1325 RTDirClose(pDir);
1326 }
1327 else
1328 {
1329 CORELOGREL(("ResumeAllThreads: Failed to open %s\n", szPath));
1330 rc = VERR_READ_ERROR;
1331 }
1332
1333 return rc;
1334}
1335
1336
1337/**
1338 * Stop all running threads of this process. Before dumping any
1339 * core we need to make sure the process is quiesced.
1340 *
1341 * @param pVBoxProc Pointer to the VBox process.
1342 *
1343 * @return VBox error code.
1344 */
1345int SuspendAllThreads(PVBOXPROCESS pVBoxProc)
1346{
1347 char szCurThread[128];
1348 char szPath[PATH_MAX];
1349 PRTDIR pDir = NULL;
1350
1351 RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/lwp", (int)pVBoxProc->Process);
1352 RTStrPrintf(szCurThread, sizeof(szCurThread), "%d", (int)pVBoxProc->hCurThread);
1353
1354 int rc = -1;
1355 uint32_t cThreads = 0;
1356 uint16_t cTries = 0;
1357 for (cTries = 0; cTries < 10; cTries++)
1358 {
1359 uint32_t cRunningThreads = 0;
1360 rc = RTDirOpen(&pDir, szPath);
1361 if (RT_SUCCESS(rc))
1362 {
1363 /*
1364 * Loop through all our threads & suspend them, multiple calls to _lwp_suspend() are okay.
1365 */
1366 RTDIRENTRY DirEntry;
1367 while (RT_SUCCESS(RTDirRead(pDir, &DirEntry, NULL)))
1368 {
1369 if ( !strcmp(DirEntry.szName, ".")
1370 || !strcmp(DirEntry.szName, ".."))
1371 continue;
1372
1373 if ( !strcmp(DirEntry.szName, szCurThread))
1374 continue;
1375
1376 int32_t ThreadId = RTStrToInt32(DirEntry.szName);
1377 _lwp_suspend((lwpid_t)ThreadId);
1378 ++cRunningThreads;
1379 }
1380
1381 if (cTries > 5 && cThreads == cRunningThreads)
1382 {
1383 rc = VINF_SUCCESS;
1384 break;
1385 }
1386 cThreads = cRunningThreads;
1387 RTDirClose(pDir);
1388 }
1389 else
1390 {
1391 CORELOGREL(("SuspendAllThreads: Failed to open %s cTries=%d\n", szPath, cTries));
1392 rc = VERR_READ_ERROR;
1393 break;
1394 }
1395 }
1396
1397 if (RT_SUCCESS(rc))
1398 CORELOG(("Stopped %u threads successfully with %u tries\n", cThreads, cTries));
1399
1400 return rc;
1401}
1402
1403
1404/**
1405 * Returns size of an ELF NOTE header given the size of data the NOTE section will contain.
1406 *
1407 * @param cb Size of the data.
1408 *
1409 * @return Size of data actually used for NOTE header and section.
1410 */
1411inline size_t ElfNoteHeaderSize(size_t cb)
1412{
1413 return sizeof(ELFNOTEHDR) + RT_ALIGN_Z(cb, 4);
1414}
1415
1416
1417/**
1418 * Write an ELF NOTE header into the core file.
1419 *
1420 * @param pVBoxCore Pointer to the core object.
1421 * @param Type Type of this NOTE section.
1422 * @param pcv Opaque pointer to the data, if NULL only computes size.
1423 * @param cb Size of the data.
1424 *
1425 * @return VBox status code.
1426 */
1427int ElfWriteNoteHeader(PVBOXCORE pVBoxCore, uint_t Type, const void *pcv, size_t cb)
1428{
1429 AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
1430 AssertReturn(pcv, VERR_INVALID_POINTER);
1431 AssertReturn(cb > 0, VERR_NO_DATA);
1432 AssertReturn(pVBoxCore->pfnWriter, VERR_WRITE_ERROR);
1433 AssertReturn(pVBoxCore->hCoreFile, VERR_INVALID_HANDLE);
1434
1435 int rc = VERR_GENERAL_FAILURE;
1436#ifdef RT_OS_SOLARIS
1437 ELFNOTEHDR ElfNoteHdr;
1438 RT_ZERO(ElfNoteHdr);
1439 ElfNoteHdr.achName[0] = 'C';
1440 ElfNoteHdr.achName[1] = 'O';
1441 ElfNoteHdr.achName[2] = 'R';
1442 ElfNoteHdr.achName[3] = 'E';
1443 ElfNoteHdr.Hdr.n_namesz = 5;
1444 ElfNoteHdr.Hdr.n_type = Type;
1445 ElfNoteHdr.Hdr.n_descsz = RT_ALIGN_Z(cb, 4);
1446
1447 /*
1448 * Write note header and description.
1449 */
1450 rc = pVBoxCore->pfnWriter(pVBoxCore->hCoreFile, &ElfNoteHdr, sizeof(ElfNoteHdr));
1451 if (RT_SUCCESS(rc))
1452 rc = pVBoxCore->pfnWriter(pVBoxCore->hCoreFile, pcv, ElfNoteHdr.Hdr.n_descsz);
1453
1454 if (RT_FAILURE(rc))
1455 CORELOGREL(("ElfWriteNote: pfnWriter failed. Type=%d rc=%Rrc\n", Type, rc));
1456#else
1457#error Port Me!
1458#endif
1459 return rc;
1460}
1461
1462
1463/**
1464 * Computes the size of NOTE section for the given core type.
1465 * Solaris has two types of program header information (new and old).
1466 *
1467 * @param pVBoxCore Pointer to the core object.
1468 * @param enmType Type of core file information required.
1469 *
1470 * @return Size of NOTE section.
1471 */
1472size_t ElfNoteSectionSize(PVBOXCORE pVBoxCore, VBOXSOLCORETYPE enmType)
1473{
1474 PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
1475 size_t cb = 0;
1476 switch (enmType)
1477 {
1478 case enmOldEra:
1479 {
1480 cb += ElfNoteHeaderSize(sizeof(prpsinfo_t));
1481 cb += ElfNoteHeaderSize(pVBoxProc->cAuxVecs * sizeof(auxv_t));
1482 cb += ElfNoteHeaderSize(strlen(pVBoxProc->szPlatform));
1483
1484 PVBOXSOLTHREADINFO pThreadInfo = pVBoxProc->pThreadInfoHead;
1485 while (pThreadInfo)
1486 {
1487 if (pThreadInfo->pStatus)
1488 {
1489 cb += ElfNoteHeaderSize(sizeof(prstatus_t));
1490 cb += ElfNoteHeaderSize(sizeof(prfpregset_t));
1491 }
1492 pThreadInfo = pThreadInfo->pNext;
1493 }
1494
1495 break;
1496 }
1497
1498 case enmNewEra:
1499 {
1500 cb += ElfNoteHeaderSize(sizeof(psinfo_t));
1501 cb += ElfNoteHeaderSize(sizeof(pstatus_t));
1502 cb += ElfNoteHeaderSize(pVBoxProc->cAuxVecs * sizeof(auxv_t));
1503 cb += ElfNoteHeaderSize(strlen(pVBoxProc->szPlatform) + 1);
1504 cb += ElfNoteHeaderSize(sizeof(struct utsname));
1505 cb += ElfNoteHeaderSize(sizeof(core_content_t));
1506 cb += ElfNoteHeaderSize(pVBoxProc->cbCred);
1507
1508 if (pVBoxProc->pPriv)
1509 cb += ElfNoteHeaderSize(PRIV_PRPRIV_SIZE(pVBoxProc->pPriv)); /* Ought to be same as cbPriv!? */
1510
1511 if (pVBoxProc->pcPrivImpl)
1512 cb += ElfNoteHeaderSize(PRIV_IMPL_INFO_SIZE(pVBoxProc->pcPrivImpl));
1513
1514 cb += ElfNoteHeaderSize(strlen(pVBoxProc->szZoneName) + 1);
1515 if (pVBoxProc->cbLdt > 0)
1516 cb += ElfNoteHeaderSize(pVBoxProc->cbLdt);
1517
1518 PVBOXSOLTHREADINFO pThreadInfo = pVBoxProc->pThreadInfoHead;
1519 while (pThreadInfo)
1520 {
1521 cb += ElfNoteHeaderSize(sizeof(lwpsinfo_t));
1522 if (pThreadInfo->pStatus)
1523 cb += ElfNoteHeaderSize(sizeof(lwpstatus_t));
1524
1525 pThreadInfo = pThreadInfo->pNext;
1526 }
1527
1528 break;
1529 }
1530
1531 default:
1532 {
1533 CORELOGREL(("ElfNoteSectionSize: Unknown segment era %d\n", enmType));
1534 break;
1535 }
1536 }
1537
1538 return cb;
1539}
1540
1541
1542/**
1543 * Write the note section for the given era into the core file.
1544 * Solaris has two types of program header information (new and old).
1545 *
1546 * @param pVBoxCore Pointer to the core object.
1547 * @param enmType Type of core file information required.
1548 *
1549 * @return VBox status code.
1550 */
1551int ElfWriteNoteSection(PVBOXCORE pVBoxCore, VBOXSOLCORETYPE enmType)
1552{
1553 AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
1554
1555 PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
1556 int rc = VERR_GENERAL_FAILURE;
1557
1558#ifdef RT_OS_SOLARIS
1559
1560 typedef int (*PFNELFWRITENOTEHDR)(PVBOXCORE pVBoxCore, uint_t, const void *pcv, size_t cb);
1561 typedef struct ELFWRITENOTE
1562 {
1563 const char *pszType;
1564 uint_t Type;
1565 const void *pcv;
1566 size_t cb;
1567 } ELFWRITENOTE;
1568
1569 switch (enmType)
1570 {
1571 case enmOldEra:
1572 {
1573 ELFWRITENOTE aElfNotes[] =
1574 {
1575 { "NT_PRPSINFO", NT_PRPSINFO, &pVBoxProc->ProcInfoOld, sizeof(prpsinfo_t) },
1576 { "NT_AUXV", NT_AUXV, pVBoxProc->pAuxVecs, pVBoxProc->cAuxVecs * sizeof(auxv_t) },
1577 { "NT_PLATFORM", NT_PLATFORM, pVBoxProc->szPlatform, strlen(pVBoxProc->szPlatform) + 1 }
1578 };
1579
1580 for (unsigned i = 0; i < RT_ELEMENTS(aElfNotes); i++)
1581 {
1582 rc = ElfWriteNoteHeader(pVBoxCore, aElfNotes[i].Type, aElfNotes[i].pcv, aElfNotes[i].cb);
1583 if (RT_FAILURE(rc))
1584 {
1585 CORELOGREL(("ElfWriteNoteSection: ElfWriteNoteHeader failed for %s. rc=%Rrc\n", aElfNotes[i].pszType, rc));
1586 break;
1587 }
1588 }
1589
1590 /*
1591 * Write old-style thread info., they contain nothing about zombies,
1592 * so we just skip if there is no status information for them.
1593 */
1594 PVBOXSOLTHREADINFO pThreadInfo = pVBoxProc->pThreadInfoHead;
1595 for (; pThreadInfo; pThreadInfo = pThreadInfo->pNext)
1596 {
1597 if (!pThreadInfo->pStatus)
1598 continue;
1599
1600 prstatus_t OldProcessStatus;
1601 GetOldProcessStatus(pVBoxCore, &pThreadInfo->Info, pThreadInfo->pStatus, &OldProcessStatus);
1602 rc = ElfWriteNoteHeader(pVBoxCore, NT_PRSTATUS, &OldProcessStatus, sizeof(prstatus_t));
1603 if (RT_SUCCESS(rc))
1604 {
1605 rc = ElfWriteNoteHeader(pVBoxCore, NT_PRFPREG, &pThreadInfo->pStatus->pr_fpreg, sizeof(prfpregset_t));
1606 if (RT_FAILURE(rc))
1607 {
1608 CORELOGREL(("ElfWriteSegment: ElfWriteNote failed for NT_PRFPREF. rc=%Rrc\n", rc));
1609 break;
1610 }
1611 }
1612 else
1613 {
1614 CORELOGREL(("ElfWriteSegment: ElfWriteNote failed for NT_PRSTATUS. rc=%Rrc\n", rc));
1615 break;
1616 }
1617 }
1618 break;
1619 }
1620
1621 case enmNewEra:
1622 {
1623 ELFWRITENOTE aElfNotes[] =
1624 {
1625 { "NT_PSINFO", NT_PSINFO, &pVBoxProc->ProcInfo, sizeof(psinfo_t) },
1626 { "NT_PSTATUS", NT_PSTATUS, &pVBoxProc->ProcStatus, sizeof(pstatus_t) },
1627 { "NT_AUXV", NT_AUXV, pVBoxProc->pAuxVecs, pVBoxProc->cAuxVecs * sizeof(auxv_t) },
1628 { "NT_PLATFORM", NT_PLATFORM, pVBoxProc->szPlatform, strlen(pVBoxProc->szPlatform) + 1 },
1629 { "NT_UTSNAME", NT_UTSNAME, &pVBoxProc->UtsName, sizeof(struct utsname) },
1630 { "NT_CONTENT", NT_CONTENT, &pVBoxProc->CoreContent, sizeof(core_content_t) },
1631 { "NT_PRCRED", NT_PRCRED, pVBoxProc->pvCred, pVBoxProc->cbCred },
1632 { "NT_PRPRIV", NT_PRPRIV, pVBoxProc->pPriv, PRIV_PRPRIV_SIZE(pVBoxProc->pPriv) },
1633 { "NT_PRPRIVINFO", NT_PRPRIVINFO, pVBoxProc->pcPrivImpl, PRIV_IMPL_INFO_SIZE(pVBoxProc->pcPrivImpl) },
1634 { "NT_ZONENAME", NT_ZONENAME, pVBoxProc->szZoneName, strlen(pVBoxProc->szZoneName) + 1 }
1635 };
1636
1637 for (unsigned i = 0; i < RT_ELEMENTS(aElfNotes); i++)
1638 {
1639 rc = ElfWriteNoteHeader(pVBoxCore, aElfNotes[i].Type, aElfNotes[i].pcv, aElfNotes[i].cb);
1640 if (RT_FAILURE(rc))
1641 {
1642 CORELOGREL(("ElfWriteNoteSection: ElfWriteNoteHeader failed for %s. rc=%Rrc\n", aElfNotes[i].pszType, rc));
1643 break;
1644 }
1645 }
1646
1647 /*
1648 * Write new-style thread info., missing lwpstatus_t indicates it's a zombie thread
1649 * we only dump the lwpsinfo_t in that case.
1650 */
1651 PVBOXSOLTHREADINFO pThreadInfo = pVBoxProc->pThreadInfoHead;
1652 for (; pThreadInfo; pThreadInfo = pThreadInfo->pNext)
1653 {
1654 rc = ElfWriteNoteHeader(pVBoxCore, NT_LWPSINFO, &pThreadInfo->Info, sizeof(lwpsinfo_t));
1655 if (RT_FAILURE(rc))
1656 {
1657 CORELOGREL(("ElfWriteNoteSection: ElfWriteNoteHeader for NT_LWPSINFO failed. rc=%Rrc\n", rc));
1658 break;
1659 }
1660
1661 if (pThreadInfo->pStatus)
1662 {
1663 rc = ElfWriteNoteHeader(pVBoxCore, NT_LWPSTATUS, pThreadInfo->pStatus, sizeof(lwpstatus_t));
1664 if (RT_FAILURE(rc))
1665 {
1666 CORELOGREL(("ElfWriteNoteSection: ElfWriteNoteHeader for NT_LWPSTATUS failed. rc=%Rrc\n", rc));
1667 break;
1668 }
1669 }
1670 }
1671 break;
1672 }
1673
1674 default:
1675 {
1676 CORELOGREL(("ElfWriteNoteSection: Invalid type %d\n", enmType));
1677 rc = VERR_GENERAL_FAILURE;
1678 break;
1679 }
1680 }
1681#else
1682# error Port Me!
1683#endif
1684 return rc;
1685}
1686
1687
1688/**
1689 * Write mappings into the core file.
1690 *
1691 * @param pVBoxCore Pointer to the core object.
1692 *
1693 * @return VBox status code.
1694 */
1695int ElfWriteMappings(PVBOXCORE pVBoxCore)
1696{
1697 PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
1698
1699 int rc = VERR_GENERAL_FAILURE;
1700 PVBOXSOLMAPINFO pMapInfo = pVBoxProc->pMapInfoHead;
1701 while (pMapInfo)
1702 {
1703 if (!pMapInfo->fError)
1704 {
1705 uint64_t k = 0;
1706 char achBuf[PAGE_SIZE];
1707 while (k < pMapInfo->pMap.pr_size)
1708 {
1709 size_t cb = RT_MIN(sizeof(achBuf), pMapInfo->pMap.pr_size - k);
1710 int rc2 = ReadProcAddrSpace(pVBoxProc, &achBuf, cb, pMapInfo->pMap.pr_vaddr + k);
1711 if (RT_FAILURE(rc2))
1712 {
1713 CORELOGREL(("ElfWriteMappings: Failed to read mapping, can't recover. Bye. rc=%Rrc\n", rc));
1714 return VERR_INVALID_STATE;
1715 }
1716
1717 rc = pVBoxCore->pfnWriter(pVBoxCore->hCoreFile, achBuf, sizeof(achBuf));
1718 if (RT_FAILURE(rc))
1719 {
1720 CORELOGREL(("ElfWriteMappings: pfnWriter failed. rc=%Rrc\n", rc));
1721 return rc;
1722 }
1723 k += cb;
1724 }
1725 }
1726 else
1727 {
1728 char achBuf[RT_ALIGN_Z(sizeof(int), 8)];
1729 RT_ZERO(achBuf);
1730 memcpy(achBuf, &pMapInfo->fError, sizeof(pMapInfo->fError));
1731 if (sizeof(achBuf) != pMapInfo->pMap.pr_size)
1732 CORELOGREL(("ElfWriteMappings: Huh!? something is wrong!\n"));
1733 rc = pVBoxCore->pfnWriter(pVBoxCore->hCoreFile, &achBuf, sizeof(achBuf));
1734 if (RT_FAILURE(rc))
1735 {
1736 CORELOGREL(("ElfWriteMappings: pfnWriter(2) failed. rc=%Rrc\n", rc));
1737 return rc;
1738 }
1739 }
1740
1741 pMapInfo = pMapInfo->pNext;
1742 }
1743
1744 return VINF_SUCCESS;
1745}
1746
1747/**
1748 * Write program headers for all mappings into the core file.
1749 *
1750 * @param pVBoxCore Pointer to the core object.
1751 *
1752 * @return VBox status code.
1753 */
1754int ElfWriteMappingHeaders(PVBOXCORE pVBoxCore)
1755{
1756 AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
1757
1758 PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
1759 Phdr ProgHdr;
1760 RT_ZERO(ProgHdr);
1761 ProgHdr.p_type = PT_LOAD;
1762
1763 int rc = VERR_GENERAL_FAILURE;
1764 PVBOXSOLMAPINFO pMapInfo = pVBoxProc->pMapInfoHead;
1765 while (pMapInfo)
1766 {
1767 ProgHdr.p_vaddr = pMapInfo->pMap.pr_vaddr; /* Virtual address of this mapping in the process address space */
1768 ProgHdr.p_offset = pVBoxCore->offWrite; /* Where this mapping is located in the core file */
1769 ProgHdr.p_memsz = pMapInfo->pMap.pr_size; /* Size of the memory image of the mapping */
1770 ProgHdr.p_filesz = pMapInfo->pMap.pr_size; /* Size of the file image of the mapping */
1771
1772 if (pMapInfo->pMap.pr_mflags & MA_READ)
1773 ProgHdr.p_flags |= PF_R;
1774 if (pMapInfo->pMap.pr_mflags & MA_WRITE)
1775 ProgHdr.p_flags |= PF_W;
1776 if (pMapInfo->pMap.pr_mflags & MA_EXEC)
1777 ProgHdr.p_flags |= PF_X;
1778
1779 if (pMapInfo->fError)
1780 ProgHdr.p_flags |= PF_SUNW_FAILURE;
1781
1782 rc = pVBoxCore->pfnWriter(pVBoxCore->hCoreFile, &ProgHdr, sizeof(ProgHdr));
1783 if (RT_FAILURE(rc))
1784 {
1785 CORELOGREL(("ElfWriteMappingHeaders: pfnWriter failed. rc=%Rrc\n", rc));
1786 return rc;
1787 }
1788
1789 pVBoxCore->offWrite += ProgHdr.p_filesz;
1790 pMapInfo = pMapInfo->pNext;
1791 }
1792 return rc;
1793}
1794
1795
1796/**
1797 * Write a prepared core file using a user-passed in writer function, requires all threads
1798 * to be in suspended state (i.e. called after CreateCore).
1799 *
1800 * @param pVBoxCore Pointer to the core object.
1801 * @param pfnWriter Pointer to the writer function to override default writer (NULL uses default).
1802 *
1803 * @remarks Resumes all suspended threads, unless it's an invalid core.
1804 * @return VBox status.
1805 */
1806int WriteCore(PVBOXCORE pVBoxCore, PFNCOREWRITER pfnWriter)
1807{
1808 AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
1809
1810 if (!pVBoxCore->fIsValid)
1811 return VERR_INVALID_STATE;
1812
1813 if (pfnWriter)
1814 pVBoxCore->pfnWriter = pfnWriter;
1815
1816 PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
1817 char szPath[PATH_MAX];
1818
1819 /*
1820 * Open the process address space file.
1821 */
1822 RTStrPrintf(szPath, sizeof(szPath), "/proc/%d/as", (int)pVBoxProc->Process);
1823 int rc = RTFileOpen(&pVBoxProc->hAs, szPath, RTFILE_O_OPEN | RTFILE_O_READ);
1824 if (RT_FAILURE(rc))
1825 {
1826 CORELOGREL(("WriteCore: Failed to open address space, %s. rc=%Rrc\n", szPath, rc));
1827 goto WriteCoreDone;
1828 }
1829
1830 /*
1831 * Create the core file.
1832 */
1833 RTStrPrintf(szPath, sizeof(szPath), "/export/home/ram/vbox/out/solaris.amd64/release/bin/%s", pVBoxCore->szCorePath, pVBoxCore->VBoxProc.Process); /* @todo fix this */
1834 rc = RTFileOpen(&pVBoxCore->hCoreFile, szPath, RTFILE_O_OPEN_CREATE | RTFILE_O_TRUNCATE | RTFILE_O_READWRITE | RTFILE_O_DENY_ALL);
1835 if (RT_FAILURE(rc))
1836 {
1837 CORELOGREL(("WriteCore: failed to open %s. rc=%Rrc\n", szPath, rc));
1838 goto WriteCoreDone;
1839 }
1840
1841 pVBoxCore->offWrite = 0;
1842 uint32_t cProgHdrs = pVBoxProc->cMappings + 2; /* two PT_NOTE program headers (old, new style) */
1843 uint32_t cSecHdrs = CountSections(pVBoxCore);
1844
1845 /*
1846 * Write the ELF header.
1847 */
1848 Ehdr ElfHdr;
1849 RT_ZERO(ElfHdr);
1850 ElfHdr.e_ident[EI_MAG0] = ELFMAG0;
1851 ElfHdr.e_ident[EI_MAG1] = ELFMAG1;
1852 ElfHdr.e_ident[EI_MAG2] = ELFMAG2;
1853 ElfHdr.e_ident[EI_MAG3] = ELFMAG3;
1854 ElfHdr.e_ident[EI_DATA] = IsBigEndian() ? ELFDATA2MSB : ELFDATA2LSB;
1855 ElfHdr.e_type = ET_CORE;
1856 ElfHdr.e_version = EV_CURRENT;
1857#ifdef RT_ARCH_AMD64
1858 ElfHdr.e_machine = EM_AMD64;
1859 ElfHdr.e_ident[EI_CLASS] = ELFCLASS64;
1860#else
1861 ElfHdr.e_machine = EM_386;
1862 ElfHdr.e_ident[EI_CLASS] = ELFCLASS32;
1863#endif
1864 if (cProgHdrs >= PN_XNUM)
1865 ElfHdr.e_phnum = PN_XNUM;
1866 else
1867 ElfHdr.e_phnum = cProgHdrs;
1868 ElfHdr.e_ehsize = sizeof(ElfHdr);
1869 ElfHdr.e_phoff = sizeof(ElfHdr);
1870 ElfHdr.e_phentsize = sizeof(Phdr);
1871 ElfHdr.e_shentsize = sizeof(Shdr);
1872 rc = pVBoxCore->pfnWriter(pVBoxCore->hCoreFile, &ElfHdr, sizeof(ElfHdr));
1873 if (RT_FAILURE(rc))
1874 {
1875 CORELOGREL(("WriteCore: pfnWriter failed writing ELF header. rc=%Rrc\n", rc));
1876 goto WriteCoreDone;
1877 }
1878
1879 /*
1880 * Setup program header.
1881 */
1882 Phdr ProgHdr;
1883 RT_ZERO(ProgHdr);
1884 ProgHdr.p_type = PT_NOTE;
1885 ProgHdr.p_flags = PF_R;
1886
1887 /*
1888 * Write old-style NOTE program header.
1889 */
1890 pVBoxCore->offWrite += sizeof(ElfHdr) + cProgHdrs * sizeof(ProgHdr);
1891 ProgHdr.p_offset = pVBoxCore->offWrite;
1892 ProgHdr.p_filesz = ElfNoteSectionSize(pVBoxCore, enmOldEra);
1893 rc = pVBoxCore->pfnWriter(pVBoxCore->hCoreFile, &ProgHdr, sizeof(ProgHdr));
1894 if (RT_FAILURE(rc))
1895 {
1896 CORELOGREL(("WriteCore: pfnWriter failed writing old-style ELF program Header. rc=%Rrc\n", rc));
1897 goto WriteCoreDone;
1898 }
1899
1900 /*
1901 * Write new-style NOTE program header.
1902 */
1903 pVBoxCore->offWrite += ProgHdr.p_filesz;
1904 ProgHdr.p_offset = pVBoxCore->offWrite;
1905 ProgHdr.p_filesz = ElfNoteSectionSize(pVBoxCore, enmNewEra);
1906 rc = pVBoxCore->pfnWriter(pVBoxCore->hCoreFile, &ProgHdr, sizeof(ProgHdr));
1907 if (RT_FAILURE(rc))
1908 {
1909 CORELOGREL(("WriteCore: pfnWriter failed writing new-style ELF program header. rc=%Rrc\n", rc));
1910 goto WriteCoreDone;
1911 }
1912
1913 /*
1914 * Write program headers per mapping.
1915 */
1916 pVBoxCore->offWrite += ProgHdr.p_filesz;
1917 rc = ElfWriteMappingHeaders(pVBoxCore);
1918 if (RT_FAILURE(rc))
1919 {
1920 CORELOGREL(("Write: ElfWriteMappings failed. rc=%Rrc\n", rc));
1921 goto WriteCoreDone;
1922 }
1923
1924 /*
1925 * Write old-style note section.
1926 */
1927 rc = ElfWriteNoteSection(pVBoxCore, enmOldEra);
1928 if (RT_FAILURE(rc))
1929 {
1930 CORELOGREL(("WriteCore: ElfWriteNoteSection old-style failed. rc=%Rrc\n", rc));
1931 goto WriteCoreDone;
1932 }
1933
1934 /*
1935 * Write new-style section.
1936 */
1937 rc = ElfWriteNoteSection(pVBoxCore, enmNewEra);
1938 if (RT_FAILURE(rc))
1939 {
1940 CORELOGREL(("WriteCore: ElfWriteNoteSection new-style failed. rc=%Rrc\n", rc));
1941 goto WriteCoreDone;
1942 }
1943
1944 /*
1945 * Write all mappings.
1946 */
1947 rc = ElfWriteMappings(pVBoxCore);
1948 if (RT_FAILURE(rc))
1949 {
1950 CORELOGREL(("WriteCore: ElfWriteMappings failed. rc=%Rrc\n", rc));
1951 goto WriteCoreDone;
1952 }
1953
1954
1955WriteCoreDone:
1956 if (pVBoxCore->hCoreFile != NIL_RTFILE)
1957 {
1958 RTFileClose(pVBoxCore->hCoreFile);
1959 pVBoxCore->hCoreFile = NIL_RTFILE;
1960 }
1961
1962 if (pVBoxProc->hAs != NIL_RTFILE)
1963 {
1964 RTFileClose(pVBoxProc->hAs);
1965 pVBoxProc->hAs = NIL_RTFILE;
1966 }
1967
1968 ResumeAllThreads(pVBoxProc);
1969 return rc;
1970}
1971
1972
1973/**
1974 * Takes a process snapshot into a passed-in core object. It has the side-effect of halting
1975 * all threads which can lead to things like spurious wakeups of threads (if and when threads
1976 * are ultimately resumed en-masse) already suspended while calling this function.
1977 *
1978 * @param pVBoxCore Pointer to a core object.
1979 * @param pContext Pointer to the caller context thread.
1980 *
1981 * @remarks Halts all threads.
1982 * @return VBox status code.
1983 */
1984int CreateCore(PVBOXCORE pVBoxCore, ucontext_t *pContext)
1985{
1986 AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
1987 AssertReturn(pContext, VERR_INVALID_POINTER);
1988
1989 /*
1990 * Initialize core structures.
1991 */
1992 memset(pVBoxCore, 0, sizeof(VBOXCORE));
1993 pVBoxCore->pfnReader = &ReadFileNoIntr;
1994 pVBoxCore->pfnWriter = &WriteFileNoIntr;
1995 pVBoxCore->fIsValid = false;
1996 pVBoxCore->hCoreFile = NIL_RTFILE;
1997
1998 PVBOXPROCESS pVBoxProc = &pVBoxCore->VBoxProc;
1999 pVBoxProc->Process = RTProcSelf();
2000 pVBoxProc->hCurThread = _lwp_self(); /* thr_self() */
2001 pVBoxProc->hAs = NIL_RTFILE;
2002 pVBoxProc->pCurThreadCtx = pContext;
2003 pVBoxProc->CoreContent = CC_CONTENT_DEFAULT;
2004
2005 RTProcGetExecutableName(pVBoxProc->szExecPath, sizeof(pVBoxProc->szExecPath)); /* this gets full path not just name */
2006 pVBoxProc->pszExecName = RTPathFilename(pVBoxProc->szExecPath);
2007 RTStrPrintf(pVBoxCore->szCorePath, sizeof(pVBoxCore->szCorePath), "core.vb.%s.%d", pVBoxProc->pszExecName, (int)pVBoxProc->Process);
2008
2009 CORELOG(("tstRTCoreDump: Taking Core %s from Thread %d\n", pVBoxCore->szCorePath, (int)pVBoxProc->hCurThread));
2010
2011 /*
2012 * Quiesce the process.
2013 */
2014 int rc = SuspendAllThreads(pVBoxProc);
2015 if (RT_SUCCESS(rc))
2016 {
2017 rc = ReadProcInfo(pVBoxCore);
2018 if (RT_SUCCESS(rc))
2019 {
2020 GetOldProcessInfo(pVBoxCore, &pVBoxProc->ProcInfoOld);
2021 if (IsProcArchNative(pVBoxProc))
2022 {
2023 /*
2024 * Read process status, information such as number of active LWPs will be invalid since we just quiesced the process.
2025 */
2026 rc = ReadProcStatus(pVBoxCore);
2027 if (RT_SUCCESS(rc))
2028 {
2029 rc = AllocMemoryArea(pVBoxCore);
2030 if (RT_SUCCESS(rc))
2031 {
2032 struct COREACCUMULATORS
2033 {
2034 const char *pszName;
2035 PFNCOREACCUMULATOR pfnAcc;
2036 bool fOptional;
2037 } aAccumulators[] =
2038 {
2039 { "ReadProcLdt", &ReadProcLdt, false },
2040 { "ReadProcCred", &ReadProcCred, false },
2041 { "ReadProcPriv", &ReadProcPriv, false },
2042 { "ReadProcAuxVecs", &ReadProcAuxVecs, false },
2043 { "ReadProcMappings", &ReadProcMappings, false },
2044 { "ReadProcThreads", &ReadProcThreads, false },
2045 { "ReadProcMiscInfo", &ReadProcMiscInfo, false }
2046 };
2047
2048 for (unsigned i = 0; i < RT_ELEMENTS(aAccumulators); i++)
2049 {
2050 rc = aAccumulators[i].pfnAcc(pVBoxCore);
2051 if (RT_FAILURE(rc))
2052 {
2053 CORELOGREL(("DumpCore: %s failed. rc=%Rrc\n", aAccumulators[i].pszName, rc));
2054 if (!aAccumulators[i].fOptional)
2055 break;
2056 }
2057 }
2058
2059 if (RT_SUCCESS(rc))
2060 {
2061 pVBoxCore->fIsValid = true;
2062 return VINF_SUCCESS;
2063 }
2064
2065 FreeMemoryArea(pVBoxCore);
2066 }
2067 else
2068 CORELOGREL(("DumpCore: AllocMemoryArea failed. rc=%Rrc\n", rc));
2069 }
2070 else
2071 CORELOGREL(("DumpCore: ReadProcStatus failed. rc=%Rrc\n", rc));
2072 }
2073 else
2074 {
2075 CORELOGREL(("DumpCore: IsProcArchNative failed.\n"));
2076 rc = VERR_BAD_EXE_FORMAT;
2077 }
2078 }
2079 else
2080 CORELOGREL(("DumpCore: ReadProcInfo failed. rc=%Rrc\n", rc));
2081
2082 /*
2083 * Resume threads on failure.
2084 */
2085 ResumeAllThreads(pVBoxProc);
2086 }
2087 else
2088 CORELOG(("DumpCore: SuspendAllThreads failed. Thread bomb!?! rc=%Rrc\n", rc));
2089
2090 return rc;
2091}
2092
2093
2094/**
2095 * Destroy an existing core object.
2096 *
2097 * @param pVBoxCore Pointer to the core object.
2098 *
2099 * @return VBox status code.
2100 */
2101int DestroyCore(PVBOXCORE pVBoxCore)
2102{
2103 AssertReturn(pVBoxCore, VERR_INVALID_POINTER);
2104 if (!pVBoxCore->fIsValid)
2105 return VERR_INVALID_STATE;
2106
2107 FreeMemoryArea(pVBoxCore);
2108 pVBoxCore->fIsValid = false;
2109 return VINF_SUCCESS;
2110}
2111
2112
2113void CoreSigHandler(int Sig, siginfo_t *pSigInfo, void *pvArg)
2114{
2115 CORELOG(("CoreSigHandler Sig=%d pvArg=%p\n", Sig, pvArg));
2116
2117 ucontext_t *pContext = (ucontext_t *)pvArg;
2118 if (!pContext)
2119 CORELOGREL(("CoreSigHandler: Missing context.\n"));
2120 else
2121 {
2122 if (!ASMAtomicUoReadBool(&g_fCoreDumpInProgress))
2123 {
2124 ASMAtomicWriteBool(&g_fCoreDumpInProgress, true);
2125
2126 /*
2127 * Take a snapshot, then dump core to disk, all threads except this one are halted
2128 * from before taking the snapshot until writing the core is completely finished.
2129 * Any errors would resume all threads if they were halted.
2130 */
2131 VBOXCORE VBoxCore;
2132 RT_ZERO(VBoxCore);
2133 int rc = CreateCore(&VBoxCore, pContext);
2134 if (RT_SUCCESS(rc))
2135 {
2136 rc = WriteCore(&VBoxCore, &WriteFileNoIntr);
2137 if (RT_SUCCESS(rc))
2138 CORELOG(("CoreSigHandler: Successfully wrote core file to disk.\n"));
2139 else
2140 CORELOGREL(("CoreSigHandler: WriteCore failed. rc=%Rrc\n", rc));
2141
2142 DestroyCore(&VBoxCore);
2143 }
2144 else
2145 CORELOGREL(("CoreSigHandler: CreateCore failed. rc=%Rrc\n", rc));
2146
2147 ASMAtomicWriteBool(&g_fCoreDumpInProgress, false);
2148 }
2149 else
2150 {
2151 CORELOGREL(("CoreSigHandler: Core dump already in progress! Waiting before signalling Sig=%d.\n", Sig));
2152 int64_t iTimeout = 10000; /* timeout (ms) */
2153 while (!ASMAtomicUoReadBool(&g_fCoreDumpInProgress))
2154 {
2155 RTThreadSleep(200);
2156 iTimeout -= 200;
2157 if (iTimeout <= 0)
2158 break;
2159 }
2160 if (iTimeout <= 0)
2161 CORELOGREL(("CoreSigHandler: Core dump seems to be stuck. Signalling new signal %d\n", Sig));
2162 }
2163 }
2164
2165 signal(Sig, SIG_DFL);
2166 kill((int)getpid(), Sig);
2167}
2168
2169
2170static DECLCALLBACK(int) SleepyThread(RTTHREAD Thread, void *pvUser)
2171{
2172 NOREF(pvUser);
2173 sleep(10000);
2174 return VINF_SUCCESS;
2175}
2176
2177
2178int main()
2179{
2180 RTR3Init();
2181 CORELOG(("tstRTCoreDump: TESTING pid=%d\n", getpid()));
2182
2183 /*
2184 * Install core dump signal handler.
2185 */
2186 struct sigaction sigAction;
2187 sigAction.sa_sigaction = CoreSigHandler;
2188 sigemptyset(&sigAction.sa_mask);
2189 sigAction.sa_flags = SA_RESTART | SA_SIGINFO;
2190 sigaction(SIGSEGV, &sigAction, NULL);
2191 sigaction(SIGBUS, &sigAction, NULL);
2192 sigaction(SIGUSR1, &sigAction, NULL);
2193
2194 /*
2195 * Spawn a few threads.
2196 */
2197 RTTHREAD ahThreads[5];
2198 for (unsigned i = 0; i < RT_ELEMENTS(ahThreads); i++)
2199 {
2200 int rc = RTThreadCreate(&ahThreads[i], SleepyThread, &ahThreads[i], 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "TEST1");
2201 if (RT_FAILURE(rc))
2202 {
2203 CORELOG(("tstRTCoreDump: FAILURE(%d) - %d RTThreadCreate failed, rc=%Rrc\n", __LINE__, i, rc));
2204 g_cErrors++;
2205 ahThreads[i] = NIL_RTTHREAD;
2206 break;
2207 }
2208 }
2209
2210 CORELOG(("Spawned %d threads\n", RT_ELEMENTS(ahThreads)));
2211
2212 /*
2213 * Send signal to dump core.
2214 */
2215 kill(getpid(), SIGUSR1);
2216 g_cErrors++;
2217
2218 sleep(10);
2219
2220 /*
2221 * Summary.
2222 */
2223 if (!g_cErrors)
2224 CORELOG(("tstRTCoreDump: SUCCESS\n"));
2225 else
2226 CORELOG(("tstRTCoreDump: FAILURE - %d errors\n", g_cErrors));
2227
2228 return !!g_cErrors;
2229}
2230
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette