VirtualBox

Changeset 32214 in vbox


Ignore:
Timestamp:
Sep 2, 2010 3:19:06 PM (14 years ago)
Author:
vboxsync
Message:

VMM/DBGFCoreWrite: bits.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/DBGFCoreWrite.cpp

    r32050 r32214  
    2626#include "DBGFInternal.h"
    2727#include <VBox/vm.h>
     28#include <VBox/pgm.h>
    2829#include <VBox/err.h>
    2930#include <VBox/log.h>
     31#include <VBox/mm.h>
    3032
    3133#include "../Runtime/include/internal/ldrELF64.h"
     34
     35/*******************************************************************************
     36*   Defined Constants And Macros                                               *
     37*******************************************************************************/
     38#ifdef DEBUG_ramshankar
     39# undef Log
     40# define Log LogRel
     41#endif
     42#define DBGFLOG_NAME           "DGBFCoreWrite"
     43
     44/**
     45 * DBGFCOREDATA: Core data.
     46 */
     47typedef struct
     48{
     49    const char *pszDumpPath;    /* File path to dump the core into. */
     50} DBGFCOREDATA, *PDBGFCOREDATA;
     51
    3252
    3353/*
     
    6686 * @return IPRT status code.
    6787 */
    68 static int Elf64WriteElfHdr(RTFILE hFile, uint16_t cProgHdrs, uint16_t cSecHdrs, size_t *pcbElfHdr)
    69 {
     88static int Elf64WriteElfHdr(RTFILE hFile, uint16_t cProgHdrs, uint16_t cSecHdrs, uint64_t *pcbElfHdr)
     89{
     90AssertCompile(sizeof(uint32_t) == 4);
     91
    7092    Elf64_Ehdr ElfHdr;
    7193    RT_ZERO(ElfHdr);
     
    103125 * @param hFile             The file to write to.
    104126 * @param Type              Type of program header (PT_*).
    105  * @param fFlags            Flags (access permissions).
     127 * @param fFlags            Flags (access permissions, PF_*).
    106128 * @param offFileData       File offset of contents.
    107129 * @param cbFileData        Size of contents in the file.
    108130 * @param cbMemData         Size of contents in memory.
     131 * @param Phys              Physical address, pass zero if not applicable.
    109132 * @param pcbProgHdr        Where to store the size of written header to file,
    110133 *                          can be NULL.
     
    112135 * @return IPRT status code.
    113136 */
    114 static int Elf64WriteProgHdr(RTFILE hFile, uint32_t Type, uint32_t fFlags, RTFOFF offFileData, size_t cbFileData, size_t cbMemData,
    115                                 size_t *pcbProgHdr)
     137static int Elf64WriteProgHdr(RTFILE hFile, uint32_t Type, uint32_t fFlags, uint64_t offFileData, uint64_t cbFileData, uint64_t cbMemData,
     138                             RTGCPHYS Phys, uint64_t *pcbProgHdr)
    116139{
    117140    Elf64_Phdr ProgHdr;
     
    122145    ProgHdr.p_filesz        = cbFileData;
    123146    ProgHdr.p_memsz         = cbMemData;
     147    ProgHdr.p_paddr         = Phys;
    124148
    125149    int rc = RTFileWrite(hFile, &ProgHdr, sizeof(ProgHdr), NULL /* full write */);
     
    131155
    132156/**
    133  * Count the number of memory blobs that go into the core file.
    134  *
    135  * We cannot do a page-by-page dump of the entire guest memory as there will be
    136  * way too many entries. Also we don't want to dump MMIO regions which means we
    137  * cannot have a 1:1 mapping between core file offset and memory offset. Instead
    138  * we dump the memory in blobs. A memory blob is a contiguous memory area
    139  * suitable for dumping to a core file.
    140  *
    141  * @param pVM               The VM handle.
    142  * @oaram idCpu             The target CPU ID.
    143  *
    144  * @return Number of memory blobs.
    145  */
    146 static int dbgfR3CountMemoryBlobs(PVM pVM, VMCPUID idCpu)
    147 {
    148     /* @todo */
    149     return 0;
    150 }
    151 
    152 
    153 /**
    154  * EMT worker function for DBGFR3CoreWrite.
    155  *
    156  * @param   pVM              The VM handle.
    157  * @param   idCpu            The target CPU ID.
    158  * @param   pszDumpPath      The full path of the file to dump into.
    159  *
    160  * @return VBox status code.
    161  */
    162 static DECLCALLBACK(int) dbgfR3CoreWrite(PVM pVM, VMCPUID idCpu, const char *pszDumpPath)
    163 {
    164     /*
    165      * Validate input.
    166      */
    167     Assert(idCpu == VMMGetCpuId(pVM));
    168     AssertReturn(pszDumpPath, VERR_INVALID_POINTER);
    169 
    170     /*
    171      * Halt the VM if it is not already halted.
    172      */
    173     int rc = VINF_SUCCESS;
    174     if (!DBGFR3IsHalted(pVM))
     157 * Elf function to write 64-bit note header.
     158 *
     159 * @param hFile             The file to write to.
     160 * @param Type              Type of this section.
     161 * @param pszName           Name of this section, will be limited to 8 bytes.
     162 * @param pcv               Opaque pointer to the data, if NULL only computes size.
     163 * @param cb                Size of the data.
     164 * @param pcbNoteHdr        Where to store the size of written header to file,
     165 *                          can be NULL.
     166 *
     167 * @return IPRT status code.
     168 */
     169static int Elf64WriteNoteHeader(RTFILE hFile, uint_t Type, const char *pszName, const void *pcv, uint64_t cb, uint64_t *pcbNoteHdr)
     170{
     171    AssertReturn(pcv, VERR_INVALID_POINTER);
     172    AssertReturn(cb > 0, VERR_NO_DATA);
     173
     174    typedef struct
    175175    {
    176         rc = DBGFR3Halt(pVM);
    177         if (RT_FAILURE(rc))
    178             return rc;
    179     }
    180 
    181     /*
    182      * Collect core information.
    183      */
    184     uint16_t cMemBlobs = dbgfR3CountMemoryBlobs(pVM, idCpu);
    185     uint16_t cProgHdrs = cMemBlobs + 1;   /* One PT_NOTE Program header */
    186 
    187     /*
    188      * Write the core file.
    189      */
    190     RTFILE hFile = NIL_RTFILE;
    191     rc = RTFileOpen(&hFile, pszDumpPath, RTFILE_O_CREATE | RTFILE_O_READWRITE);
     176        Elf64_Nhdr  Hdr;            /* 64-bit NOTE Header */
     177        char        achName[8];     /* Name of NOTE section */
     178    } ELFNOTEHDR;
     179
     180    ELFNOTEHDR ElfNoteHdr;
     181    RT_ZERO(ElfNoteHdr);
     182    RTStrCopy(ElfNoteHdr.achName, sizeof(ElfNoteHdr.achName) - 1, pszName);
     183    ElfNoteHdr.Hdr.n_namesz = strlen(ElfNoteHdr.achName) + 1;
     184    ElfNoteHdr.Hdr.n_type   = Type;
     185
     186    static const char s_achPad[3] = { 0, 0, 0 };
     187    uint64_t cbAlign = RT_ALIGN_64(cb, 4);
     188    ElfNoteHdr.Hdr.n_descsz = cbAlign;
     189
     190    /*
     191     * Write note header and description.
     192     */
     193    int rc = RTFileWrite(hFile, &ElfNoteHdr, sizeof(ElfNoteHdr), NULL /* full write */);
    192194    if (RT_SUCCESS(rc))
    193195    {
    194         size_t cbElfHdr = 0;
    195         rc = Elf64WriteElfHdr(hFile, 0, 0 /* cSecHdrs */, &cbElfHdr);
     196        rc = RTFileWrite(hFile, pcv, cb, NULL /* full write */);
    196197        if (RT_SUCCESS(rc))
    197198        {
     199            if (cbAlign > cb)
     200                rc = RTFileWrite(hFile, s_achPad, cbAlign - cb, NULL /* full write*/);
     201        }
     202    }
     203
     204    if (RT_FAILURE(rc))
     205        LogRel((DBGFLOG_NAME ":RTFileWrite failed. rc=%Rrc pszName=%s cb=%u cbAlign=%u\n", rc, pszName, cb, cbAlign));
     206
     207    return rc;
     208}
     209
     210
     211/**
     212 * Count the number of memory ranges that go into the core file.
     213 *
     214 * We cannot do a page-by-page dump of the entire guest memory as there will be
     215 * way too many program header entries. Also we don't want to dump MMIO regions
     216 * which means we cannot have a 1:1 mapping between core file offset and memory
     217 * offset. Instead we dump the memory in ranges. A memory range is a contiguous
     218 * memory area suitable for dumping to a core file.
     219 *
     220 * @param pVM               The VM handle.
     221 *
     222 * @return Number of memory ranges
     223 */
     224static uint32_t dbgfR3GetRamRangeCount(PVM pVM)
     225{
     226    return PGMR3PhysGetRamRangeCount(pVM);
     227}
     228
     229
     230/**
     231 * EMT Rendezvous worker function for DBGFR3CoreWrite.
     232 *
     233 * @param   pVM              The VM handle.
     234 * @param   pVCpu            The handle of the calling VCPU.
     235 * @param   pvData           Opaque data.
     236 *
     237 * @return VBox status code.
     238 * @remarks The VM must be suspended before calling this function.
     239 */
     240static DECLCALLBACK(int) dbgfR3CoreWrite(PVM pVM, PVMCPU pVCpu, void *pvData)
     241{
     242    /*
     243     * Validate input.
     244     */
     245    AssertReturn(pVM, VERR_INVALID_VM_HANDLE);
     246    AssertReturn(pVCpu, VERR_INVALID_VMCPU_HANDLE);
     247    AssertReturn(pvData, VERR_INVALID_POINTER);
     248
     249    PDBGFCOREDATA pDbgfData = (PDBGFCOREDATA)pvData;
     250
     251    /*
     252     * Collect core information.
     253     */
     254    uint32_t u32MemRanges = dbgfR3GetRamRangeCount(pVM);
     255    uint16_t cMemRanges   = u32MemRanges < UINT16_MAX - 1 ? u32MemRanges : UINT16_MAX - 1;    /* One PT_NOTE Program header */
     256    uint16_t cProgHdrs    = cMemRanges + 1;
     257
     258    /*
     259     * Compute size of the note section.
     260     */
     261    uint64_t cbNoteSection = pVM->cCpus * sizeof(CPUMCTX);
     262    uint64_t off = 0;
     263
     264    /*
     265     * Create the core file.
     266     */
     267    RTFILE hFile = NIL_RTFILE;
     268    int rc = RTFileOpen(&hFile, pDbgfData->pszDumpPath, RTFILE_O_CREATE_REPLACE | RTFILE_O_READWRITE);
     269    if (RT_SUCCESS(rc))
     270    {
     271        /*
     272         * Write ELF header.
     273         */
     274        uint64_t cbElfHdr = 0;
     275        rc = Elf64WriteElfHdr(hFile, cProgHdrs, 0 /* cSecHdrs */, &cbElfHdr);
     276        off += cbElfHdr;
     277        if (RT_SUCCESS(rc))
     278        {
     279            /*
     280             * Write PT_NOTE program header.
     281             */
     282            uint64_t cbProgHdr = 0;
     283            rc = Elf64WriteProgHdr(hFile, PT_NOTE, PF_R,
     284                                   cbElfHdr + cProgHdrs * sizeof(Elf64_Phdr),   /* file offset to contents */
     285                                   cbNoteSection,                               /* size in core file */
     286                                   cbNoteSection,                               /* size in memory */
     287                                   0,                                           /* physical address */
     288                                   &cbProgHdr);
     289            Assert(cbProgHdr == sizeof(Elf64_Phdr));
     290            off += cbProgHdr;
     291            if (RT_SUCCESS(rc))
     292            {
     293                /*
     294                 * Write PT_LOAD program header for each memory range.
     295                 */
     296                uint64_t offMemRange = off + cbNoteSection;
     297                for (uint16_t iRange = 0; iRange < cMemRanges; iRange++)
     298                {
     299                    RTGCPHYS GCPhysStart;
     300                    RTGCPHYS GCPhysEnd;
     301
     302                    bool fIsMmio;
     303                    rc = PGMR3PhysGetRange(pVM, iRange, &GCPhysStart, &GCPhysEnd, NULL /* pszDesc */, &fIsMmio);
     304                    if (RT_FAILURE(rc))
     305                    {
     306                        LogRel((DBGFLOG_NAME ": PGMR3PhysGetRange failed for iRange(%u) rc=%Rrc\n", iRange, rc));
     307                        break;
     308                    }
     309
     310                    uint64_t cbMemRange  = GCPhysEnd - GCPhysStart + 1;
     311                    uint64_t cbFileRange = fIsMmio ? 0 : cbMemRange;
     312
     313                    LogRel((DBGFLOG_NAME ": PGMR3PhysGetRange iRange=%u GCPhysStart=%#x GCPhysEnd=%#x cbMemRange=%u\n",
     314                            iRange, GCPhysStart, GCPhysEnd, cbMemRange));
     315
     316                    rc = Elf64WriteProgHdr(hFile, PT_LOAD, PF_R,
     317                                           offMemRange,                         /* file offset to contents */
     318                                           cbFileRange,                         /* size in core file */
     319                                           cbMemRange,                          /* size in memory */
     320                                           GCPhysStart,                         /* physical address */
     321                                           &cbProgHdr);
     322                    Assert(cbProgHdr == sizeof(Elf64_Phdr));
     323                    if (RT_FAILURE(rc))
     324                    {
     325                        LogRel((DBGFLOG_NAME ":Elf64WriteProgHdr failed for memory range(%u) cbFileRange=%u cbMemRange=%u rc=%Rrc\n", iRange,
     326                                cbFileRange, cbMemRange, rc));
     327                        break;
     328                    }
     329
     330                    offMemRange += cbFileRange;
     331                }
     332
     333                /*
     334                 * Write the CPU context note headers and data.
     335                 */
     336                if (RT_SUCCESS(rc))
     337                {
     338                    for (uint32_t iCpu = 0; iCpu < pVM->cCpus; iCpu++)
     339                    {
     340                        /** @todo -XXX- cpus */
     341                    }
     342                }
     343            }
    198344
    199345        }
     
    201347        RTFileClose(hFile);
    202348    }
    203 
    204     /*
    205      * Resume the VM.
    206      */
    207     DBGFR3Resume(pVM);
    208349
    209350    return rc;
     
    219360 * @param   pszDumpPath         The path of the file to dump into, cannot be
    220361 *                              NULL.
     362 *
     363 * @remarks The VM must be suspended before calling this function.
    221364 */
    222365VMMR3DECL(int) DBGFR3CoreWrite(PVM pVM, VMCPUID idCpu, const char *pszDumpPath)
     
    227370
    228371    /*
    229      * Pass the core write request down to EMT.
    230      */
    231     return VMR3ReqCallWaitU(pVM->pUVM, idCpu, (PFNRT)dbgfR3CoreWrite, 3, pVM, idCpu, pszDumpPath);
    232 }
    233 
     372     * Pass the core write request down to EMT rendezvous which makes sure
     373     * other EMTs, if any, are not running.
     374     */
     375    DBGFCOREDATA CoreData;
     376    RT_ZERO(CoreData);
     377    CoreData.pszDumpPath = pszDumpPath;
     378
     379    return VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, dbgfR3CoreWrite, &CoreData);
     380}
     381
Note: See TracChangeset for help on using the changeset viewer.

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