a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/* $Id$ */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/** @file
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * DBGPlugInLinux - Debugger and Guest OS Digger Plugin For Linux.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/*
c58f1213e628a545081c70e26c6b67a841cff880vboxsync * Copyright (C) 2008-2013 Oracle Corporation
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * available from http://www.virtualbox.org. This file is free software;
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * you can redistribute it and/or modify it under the terms of the GNU
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * General Public License (GPL) as published by the Free Software
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/*******************************************************************************
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync* Header Files *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync*******************************************************************************/
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#define LOG_GROUP LOG_GROUP_DBGF ///@todo add new log group.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#include "DBGPlugIns.h"
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#include "DBGPlugInCommonELF.h"
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync#include <VBox/vmm/dbgf.h>
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#include <iprt/string.h>
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#include <iprt/mem.h>
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#include <iprt/stream.h>
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#include <iprt/ctype.h>
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/*******************************************************************************
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync* Structures and Typedefs *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync*******************************************************************************/
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/** @name InternalLinux structures
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @{ */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/** @} */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/**
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Linux guest OS digger instance data.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsynctypedef struct DBGDIGGERLINUX
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync{
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /** Whether the information is valid or not.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * (For fending off illegal interface method calls.) */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync bool fValid;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /** Set if 64-bit, clear if 32-bit. */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync bool f64Bit;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /** The address of the linux banner.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * This is set during probing. */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync DBGFADDRESS AddrLinuxBanner;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /** Kernel base address.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * This is set during probing, refined during kallsyms parsing. */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync DBGFADDRESS AddrKernelBase;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /** The kernel size. */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint32_t cbKernel;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /** The number of kernel symbols (kallsyms_num_syms).
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * This is set during init. */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint32_t cKernelSymbols;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /** The size of the kernel name table (sizeof(kallsyms_names)). */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint32_t cbKernelNames;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /** Number of entries in the kernel_markers table. */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint32_t cKernelNameMarkers;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /** The size of the kernel symbol token table. */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint32_t cbKernelTokenTable;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /** The address of the encoded kernel symbol names (kallsyms_names). */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync DBGFADDRESS AddrKernelNames;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /** The address of the kernel symbol addresses (kallsyms_addresses). */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync DBGFADDRESS AddrKernelAddresses;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /** The address of the kernel symbol name markers (kallsyms_markers). */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync DBGFADDRESS AddrKernelNameMarkers;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /** The address of the kernel symbol token table (kallsyms_token_table). */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync DBGFADDRESS AddrKernelTokenTable;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /** The address of the kernel symbol token index table (kallsyms_token_index). */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync DBGFADDRESS AddrKernelTokenIndex;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync /** The kernel message log interface. */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync DBGFOSIDMESG IDmesg;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync} DBGDIGGERLINUX;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/** Pointer to the linux guest OS digger instance data. */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsynctypedef DBGDIGGERLINUX *PDBGDIGGERLINUX;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync/**
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync * The current printk_log structure.
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsynctypedef struct LNXPRINTKHDR
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync{
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync /** Monotonic timestamp. */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync uint64_t nsTimestamp;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync /** The total size of this message record. */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync uint16_t cbTotal;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync /** The size of the text part (immediately follows the header). */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync uint16_t cbText;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync /** The size of the optional dictionary part (follows the text). */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync uint16_t cbDict;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync /** The syslog facility number. */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync uint8_t bFacility;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync /** First 5 bits are internal flags, next 3 bits are log level. */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync uint8_t fFlagsAndLevel;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync} LNXPRINTKHDR;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsyncAssertCompileSize(LNXPRINTKHDR, 2*sizeof(uint64_t));
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync/** Pointer to linux printk_log header. */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsynctypedef LNXPRINTKHDR *PLNXPRINTKHDR;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync/** Pointer to linux const printk_log header. */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsynctypedef LNXPRINTKHDR const *PCLNXPRINTKHDR;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/*******************************************************************************
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync* Defined Constants And Macros *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync*******************************************************************************/
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/** Validates a 32-bit linux kernel address */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#define LNX32_VALID_ADDRESS(Addr) ((Addr) > UINT32_C(0x80000000) && (Addr) < UINT32_C(0xfffff000))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync/** Validates a 64-bit linux kernel address */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync#define LNX64_VALID_ADDRESS(Addr) ((Addr) > UINT64_C(0xffff800000000000) && (Addr) < UINT64_C(0xfffffffffffff000))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/** The max kernel size. */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync#define LNX_MAX_KERNEL_SIZE UINT32_C(0x0f000000)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync/** The maximum size we expect for kallsyms_names. */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync#define LNX_MAX_KALLSYMS_NAMES_SIZE UINT32_C(0x200000)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync/** The maximum size we expect for kallsyms_token_table. */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync#define LNX_MAX_KALLSYMS_TOKEN_TABLE_SIZE UINT32_C(0x10000)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync/** The minimum number of symbols we expect in kallsyms_num_syms. */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync#define LNX_MIN_KALLSYMS_SYMBOLS UINT32_C(2048)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync/** The maximum number of symbols we expect in kallsyms_num_syms. */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync#define LNX_MAX_KALLSYMS_SYMBOLS UINT32_C(1048576)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync/** The min length an encoded symbol in kallsyms_names is expected to have. */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync#define LNX_MIN_KALLSYMS_ENC_LENGTH UINT8_C(1)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync/** The max length an encoded symbol in kallsyms_names is expected to have.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @todo check real life here. */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync#define LNX_MAX_KALLSYMS_ENC_LENGTH UINT8_C(28)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync/** The approximate maximum length of a string token. */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync#define LNX_MAX_KALLSYMS_TOKEN_LEN UINT16_C(32)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync/** Module tag for linux ('linuxmod' on little endian ASCII systems). */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync#define DIG_LNX_MOD_TAG UINT64_C(0x545f5d78758e898c)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/*******************************************************************************
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync* Internal Functions *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync*******************************************************************************/
98427c0ab08697e468c26dc33ee9571308577867vboxsyncstatic DECLCALLBACK(int) dbgDiggerLinuxInit(PUVM pUVM, void *pvData);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/*******************************************************************************
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync* Global Variables *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync*******************************************************************************/
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/** Table of common linux kernel addresses. */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncstatic uint64_t g_au64LnxKernelAddresses[] =
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync{
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync UINT64_C(0xc0100000),
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync UINT64_C(0x90100000),
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync UINT64_C(0xffffffff80200000)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync};
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync/**
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync * @interface_method_impl{DBGFOSIDMESG,pfnQueryKernelLog}
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsyncstatic DECLCALLBACK(int) dbgDiggerLinuxIDmsg_QueryKernelLog(PDBGFOSIDMESG pThis, PUVM pUVM, uint32_t fFlags, uint32_t cMessages,
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync char *pszBuf, size_t cbBuf, size_t *pcbActual)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync{
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync PDBGDIGGERLINUX pData = RT_FROM_MEMBER(pThis, DBGDIGGERLINUX, IDmesg);
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync if (cMessages < 1)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync return VERR_INVALID_PARAMETER;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync /*
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync * Resolve the symbols we need and read their values.
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync RTDBGAS hAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL);
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync RTDBGMOD hMod;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync int rc = RTDbgAsModuleByName(hAs, "vmlinux", 0, &hMod);
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync if (RT_FAILURE(rc))
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync return VERR_NOT_FOUND;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync RTDbgAsRelease(hAs);
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync RTGCPTR GCPtrLogBuf;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync uint32_t cbLogBuf;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync uint32_t idxFirst;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync uint32_t idxNext;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync struct { void *pvVar; uint32_t cbHost, cbGuest; const char *pszSymbol; } aSymbols[] =
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync {
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync { &GCPtrLogBuf, sizeof(GCPtrLogBuf), pData->f64Bit ? sizeof(uint64_t) : sizeof(uint32_t), "log_buf" },
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync { &cbLogBuf, sizeof(cbLogBuf), sizeof(cbLogBuf), "log_buf_len" },
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync { &idxFirst, sizeof(idxFirst), sizeof(idxFirst), "log_first_idx" },
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync { &idxNext, sizeof(idxNext), sizeof(idxNext), "log_next_idx" },
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync };
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(aSymbols); i++)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync {
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync RTDBGSYMBOL SymInfo;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync rc = RTDbgModSymbolByName(hMod, aSymbols[i].pszSymbol, &SymInfo);
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync if (RT_SUCCESS(rc))
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync {
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync RT_BZERO(aSymbols[i].pvVar, aSymbols[i].cbHost);
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync Assert(aSymbols[i].cbHost >= aSymbols[i].cbGuest);
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync DBGFADDRESS Addr;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/,
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync DBGFR3AddrFromFlat(pUVM, &Addr, (RTGCPTR)SymInfo.Value + pData->AddrKernelBase.FlatPtr),
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync aSymbols[i].pvVar, aSymbols[i].cbGuest);
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync if (RT_SUCCESS(rc))
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync continue;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: Reading '%s' at %RGv: %Rrc\n", aSymbols[i].pszSymbol, Addr.FlatPtr, rc));
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync }
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync else
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: Error looking up '%s': %Rrc\n", aSymbols[i].pszSymbol, rc));
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync RTDbgModRelease(hMod);
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync return VERR_NOT_FOUND;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync }
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync /*
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync * Check if the values make sense.
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync if (pData->f64Bit ? !LNX64_VALID_ADDRESS(GCPtrLogBuf) : !LNX32_VALID_ADDRESS(GCPtrLogBuf))
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync {
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: 'log_buf' value %RGv is not valid.\n", GCPtrLogBuf));
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync return VERR_NOT_FOUND;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync }
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync if ( cbLogBuf < 4096
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync || !RT_IS_POWER_OF_TWO(cbLogBuf)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync || cbLogBuf > 16*_1M)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync {
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: 'log_buf_len' value %#x is not valid.\n", cbLogBuf));
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync return VERR_NOT_FOUND;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync }
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync uint32_t const cbLogAlign = 4;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync if ( idxFirst > cbLogBuf - sizeof(LNXPRINTKHDR)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync || (idxFirst & (cbLogAlign - 1)) != 0)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync {
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: 'log_first_idx' value %#x is not valid.\n", idxFirst));
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync return VERR_NOT_FOUND;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync }
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync if ( idxNext > cbLogBuf - sizeof(LNXPRINTKHDR)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync || (idxNext & (cbLogAlign - 1)) != 0)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync {
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: 'log_next_idx' value %#x is not valid.\n", idxNext));
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync return VERR_NOT_FOUND;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync }
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync /*
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync * Read the whole log buffer.
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync uint8_t *pbLogBuf = (uint8_t *)RTMemAlloc(cbLogBuf);
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync if (!pbLogBuf)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync {
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: Failed to allocate %#x bytes for log buffer\n", cbLogBuf));
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync return VERR_NO_MEMORY;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync }
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync DBGFADDRESS Addr;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &Addr, GCPtrLogBuf), pbLogBuf, cbLogBuf);
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync if (RT_FAILURE(rc))
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync {
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: Error reading %#x bytes of log buffer at %RGv: %Rrc\n",
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync cbLogBuf, Addr.FlatPtr, rc));
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync RTMemFree(pbLogBuf);
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync return VERR_NOT_FOUND;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync }
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync /*
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync * Count the messages in the buffer while doing some basic validation.
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync uint32_t const cbUsed = idxFirst == idxNext ? cbLogBuf /* could be empty... */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync : idxFirst < idxNext ? idxNext - idxFirst : cbLogBuf - idxFirst + idxNext;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync uint32_t cbLeft = cbUsed;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync uint32_t offCur = idxFirst;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync uint32_t cLogMsgs = 0;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync while (cbLeft > 0)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync {
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync PCLNXPRINTKHDR pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync if (!pHdr->cbTotal)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync {
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync /* Wrap around packet, most likely... */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync if (cbLogBuf - offCur >= cbLeft)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync break;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync offCur = 0;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync }
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync if (RT_UNLIKELY( pHdr->cbTotal > cbLogBuf - sizeof(*pHdr) - offCur
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync || pHdr->cbTotal > cbLeft
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync || (pHdr->cbTotal & (cbLogAlign - 1)) != 0
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync || pHdr->cbTotal < (uint32_t)pHdr->cbText + (uint32_t)pHdr->cbDict + sizeof(*pHdr) ))
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync {
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: Invalid printk_log record at %#x: cbTotal=%#x cbText=%#x cbDict=%#x cbLogBuf=%#x cbLeft=%#x\n",
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync offCur, pHdr->cbTotal, pHdr->cbText, pHdr->cbDict, cbLogBuf, cbLeft));
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync rc = VERR_INVALID_STATE;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync break;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync }
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync if (pHdr->cbText > 0)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync cLogMsgs++;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync /* next */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync offCur += pHdr->cbTotal;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync cbLeft -= pHdr->cbTotal;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync }
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync if (RT_FAILURE(rc))
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync {
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync RTMemFree(pbLogBuf);
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync return rc;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync }
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync /*
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync * Copy the messages into the output buffer.
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync offCur = idxFirst;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync cbLeft = cbUsed;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync /* Skip messages that the caller doesn't want. */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync if (cMessages < cLogMsgs)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync {
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync uint32_t cToSkip = cLogMsgs - cMessages;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync while (cToSkip > 0)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync {
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync PCLNXPRINTKHDR pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync if (!pHdr->cbTotal)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync {
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync offCur = 0;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync }
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync if (pHdr->cbText > 0)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync cToSkip--;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync /* next */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync offCur += pHdr->cbTotal;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync cbLeft -= pHdr->cbTotal;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync }
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync }
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync /* Now copy the messages. */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync size_t offDst = 0;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync while (cbLeft > 0)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync {
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync PCLNXPRINTKHDR pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync if (!pHdr->cbTotal)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync {
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync if (cbLogBuf - offCur >= cbLeft)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync break;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync offCur = 0;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync }
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync if (pHdr->cbText > 0)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync {
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync char *pchText = (char *)(pHdr + 1);
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync size_t cchText = RTStrNLen(pchText, pHdr->cbText);
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync if (offDst + cchText < cbBuf)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync {
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync memcpy(&pszBuf[offDst], pHdr + 1, cchText);
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync pszBuf[offDst + cchText] = '\n';
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync }
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync else if (offDst < cbBuf)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync memcpy(&pszBuf[offDst], pHdr + 1, cbBuf - offDst);
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync offDst += cchText + 1;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync }
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync /* next */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync offCur += pHdr->cbTotal;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync cbLeft -= pHdr->cbTotal;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync }
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync /* Done with the buffer. */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync RTMemFree(pbLogBuf);
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync /* Make sure we've reserved a char for the terminator. */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync if (!offDst)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync offDst = 1;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync /* Set return size value. */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync if (pcbActual)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync *pcbActual = offDst;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync /*
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync * All VBox strings are UTF-8 and bad things may in theory happen if we
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync * pass bad UTF-8 to code which assumes it's all valid. So, we enforce
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync * UTF-8 upon the guest kernel messages here even if they (probably) have
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync * no defined code set in reality.
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync */
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync if (offDst <= cbBuf)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync {
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync pszBuf[offDst - 1] = '\0';
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync RTStrPurgeEncoding(pszBuf);
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync return VINF_SUCCESS;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync }
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync if (cbBuf)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync {
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync pszBuf[cbBuf - 1] = '\0';
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync RTStrPurgeEncoding(pszBuf);
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync }
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync return VERR_BUFFER_OVERFLOW;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync}
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/**
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @copydoc DBGFOSREG::pfnQueryInterface
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
98427c0ab08697e468c26dc33ee9571308577867vboxsyncstatic DECLCALLBACK(void *) dbgDiggerLinuxQueryInterface(PUVM pUVM, void *pvData, DBGFOSINTERFACE enmIf)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync{
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync PDBGDIGGERLINUX pThis = (PDBGDIGGERLINUX)pvData;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync switch (enmIf)
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync {
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync case DBGFOSINTERFACE_DMESG:
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync return &pThis->IDmesg;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync default:
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync return NULL;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync}
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/**
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @copydoc DBGFOSREG::pfnQueryVersion
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
98427c0ab08697e468c26dc33ee9571308577867vboxsyncstatic DECLCALLBACK(int) dbgDiggerLinuxQueryVersion(PUVM pUVM, void *pvData, char *pszVersion, size_t cchVersion)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync{
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync PDBGDIGGERLINUX pThis = (PDBGDIGGERLINUX)pvData;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pThis->fValid);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /*
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * It's all in the linux banner.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
98427c0ab08697e468c26dc33ee9571308577867vboxsync int rc = DBGFR3MemReadString(pUVM, 0, &pThis->AddrLinuxBanner, pszVersion, cchVersion);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (RT_SUCCESS(rc))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync char *pszEnd = RTStrEnd(pszVersion, cchVersion);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync AssertReturn(pszEnd, VERR_BUFFER_OVERFLOW);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync while ( pszEnd > pszVersion
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync && RT_C_IS_SPACE(pszEnd[-1]))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pszEnd--;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *pszEnd = '\0';
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync else
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync RTStrPrintf(pszVersion, cchVersion, "DBGFR3MemRead -> %Rrc", rc);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync return rc;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync}
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/**
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @copydoc DBGFOSREG::pfnTerm
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
98427c0ab08697e468c26dc33ee9571308577867vboxsyncstatic DECLCALLBACK(void) dbgDiggerLinuxTerm(PUVM pUVM, void *pvData)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync{
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync PDBGDIGGERLINUX pThis = (PDBGDIGGERLINUX)pvData;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pThis->fValid);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pThis->fValid = false;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync}
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/**
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @copydoc DBGFOSREG::pfnRefresh
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
98427c0ab08697e468c26dc33ee9571308577867vboxsyncstatic DECLCALLBACK(int) dbgDiggerLinuxRefresh(PUVM pUVM, void *pvData)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync{
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync PDBGDIGGERLINUX pThis = (PDBGDIGGERLINUX)pvData;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync NOREF(pThis);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pThis->fValid);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /*
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * For now we'll flush and reload everything.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
98427c0ab08697e468c26dc33ee9571308577867vboxsync dbgDiggerLinuxTerm(pUVM, pvData);
98427c0ab08697e468c26dc33ee9571308577867vboxsync return dbgDiggerLinuxInit(pUVM, pvData);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync}
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync/**
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Worker for dbgDiggerLinuxFindStartOfNamesAndSymbolCount that update the
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * digger data.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync *
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @returns VINF_SUCCESS.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @param pThis The Linux digger data to update.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @param pAddrKernelNames The kallsyms_names address.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @param cKernelSymbols The number of kernel symbol.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @param cbAddress The guest address size.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsyncstatic int dbgDiggerLinuxFoundStartOfNames(PDBGDIGGERLINUX pThis, PCDBGFADDRESS pAddrKernelNames,
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint32_t cKernelSymbols, uint32_t cbAddress)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync{
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync pThis->cKernelSymbols = cKernelSymbols;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync pThis->AddrKernelNames = *pAddrKernelNames;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync pThis->AddrKernelAddresses = *pAddrKernelNames;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync DBGFR3AddrSub(&pThis->AddrKernelAddresses, (cKernelSymbols + 1) * cbAddress);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync Log(("dbgDiggerLinuxFoundStartOfNames: AddrKernelAddresses=%RGv\n"
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync "dbgDiggerLinuxFoundStartOfNames: cKernelSymbols=%#x (at %RGv)\n"
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync "dbgDiggerLinuxFoundStartOfNames: AddrKernelName=%RGv\n",
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync pThis->AddrKernelAddresses.FlatPtr,
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync pThis->cKernelSymbols, pThis->AddrKernelNames.FlatPtr - cbAddress,
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync pThis->AddrKernelNames.FlatPtr));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync return VINF_SUCCESS;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync}
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync/**
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Tries to find the address of the kallsyms_names, kallsyms_num_syms and
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * kallsyms_addresses symbols.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync *
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * The kallsyms_num_syms is read and stored in pThis->cKernelSymbols, while the
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * addresses of the other two are stored as pThis->AddrKernelNames and
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * pThis->AddrKernelAddresses.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync *
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @returns VBox status code, success indicating that all three variables have
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * been found and taken down.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @param pUVM The user mode VM handle.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @param pThis The Linux digger data.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @param pHitAddr An address we think is inside kallsyms_names.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsyncstatic int dbgDiggerLinuxFindStartOfNamesAndSymbolCount(PUVM pUVM, PDBGDIGGERLINUX pThis, PCDBGFADDRESS pHitAddr)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync{
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /*
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Search backwards in chunks.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync union
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint8_t ab[0x1000];
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint32_t au32[0x1000 / sizeof(uint32_t)];
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint64_t au64[0x1000 / sizeof(uint64_t)];
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync } uBuf;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint32_t cbLeft = LNX_MAX_KALLSYMS_NAMES_SIZE;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint32_t cbBuf = pHitAddr->FlatPtr & (sizeof(uBuf) - 1);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync DBGFADDRESS CurAddr = *pHitAddr;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync DBGFR3AddrSub(&CurAddr, cbBuf);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync cbBuf += sizeof(uint64_t) - 1; /* In case our kobj hit is in the first 4/8 bytes. */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync for (;;)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync int rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &CurAddr, &uBuf, sizeof(uBuf));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (RT_FAILURE(rc))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync return rc;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /*
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * We assume that the three symbols are aligned on guest pointer boundrary.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync *
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * The boundrary between the two tables should be noticable as the number
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * is unlikely to be more than 16 millions, there will be at least one zero
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * byte where it is, 64-bit will have 5 zero bytes. Zero bytes aren't all
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * that common in the kallsyms_names table.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync *
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Also the kallsyms_names table starts with a length byte, which means
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * we're likely to see a byte in the range 1..31.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync *
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * The kallsyms_addresses are mostly sorted (except for the start where the
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * absolute symbols are), so we'll spot a bunch of kernel addresses
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * immediately preceeding the kallsyms_num_syms field.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync *
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Lazy bird: If kallsyms_num_syms is on a buffer boundrary, we skip
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * the check for kernel addresses preceeding it.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (pThis->f64Bit)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint32_t i = cbBuf / sizeof(uint64_t);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync while (i-- > 0)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if ( uBuf.au64[i] <= LNX_MAX_KALLSYMS_SYMBOLS
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && uBuf.au64[i] >= LNX_MIN_KALLSYMS_SYMBOLS)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint8_t *pb = (uint8_t *)&uBuf.au64[i + 1];
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if ( pb[0] <= LNX_MAX_KALLSYMS_ENC_LENGTH
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && pb[0] >= LNX_MIN_KALLSYMS_ENC_LENGTH)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if ( (i <= 0 || LNX64_VALID_ADDRESS(uBuf.au64[i - 1]))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && (i <= 1 || LNX64_VALID_ADDRESS(uBuf.au64[i - 2]))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && (i <= 2 || LNX64_VALID_ADDRESS(uBuf.au64[i - 3])))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync return dbgDiggerLinuxFoundStartOfNames(pThis,
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync DBGFR3AddrAdd(&CurAddr, (i + 1) * sizeof(uint64_t)),
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync (uint32_t)uBuf.au64[i], sizeof(uint64_t));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync else
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint32_t i = cbBuf / sizeof(uint32_t);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync while (i-- > 0)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if ( uBuf.au32[i] <= LNX_MAX_KALLSYMS_SYMBOLS
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && uBuf.au32[i] >= LNX_MIN_KALLSYMS_SYMBOLS)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint8_t *pb = (uint8_t *)&uBuf.au32[i + 1];
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if ( pb[0] <= LNX_MAX_KALLSYMS_ENC_LENGTH
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && pb[0] >= LNX_MIN_KALLSYMS_ENC_LENGTH)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if ( (i <= 0 || LNX32_VALID_ADDRESS(uBuf.au32[i - 1]))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && (i <= 1 || LNX32_VALID_ADDRESS(uBuf.au32[i - 2]))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && (i <= 2 || LNX32_VALID_ADDRESS(uBuf.au32[i - 3])))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync return dbgDiggerLinuxFoundStartOfNames(pThis,
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync DBGFR3AddrAdd(&CurAddr, (i + 1) * sizeof(uint32_t)),
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uBuf.au32[i], sizeof(uint32_t));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /*
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Advance
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (RT_UNLIKELY(cbLeft <= sizeof(uBuf)))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync Log(("dbgDiggerLinuxFindStartOfNamesAndSymbolCount: failed (pHitAddr=%RGv)\n", pHitAddr->FlatPtr));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync return VERR_NOT_FOUND;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync cbLeft -= sizeof(uBuf);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync DBGFR3AddrSub(&CurAddr, sizeof(uBuf));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync cbBuf = sizeof(uBuf);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync}
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync/**
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Worker for dbgDiggerLinuxFindEndNames that records the findings.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync *
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @returns VINF_SUCCESS
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @param pThis The linux digger data to update.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @param pAddrMarkers The address of the marker (kallsyms_markers).
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @param cbMarkerEntry The size of a marker entry (32-bit or 64-bit).
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsyncstatic int dbgDiggerLinuxFoundMarkers(PDBGDIGGERLINUX pThis, PCDBGFADDRESS pAddrMarkers, uint32_t cbMarkerEntry)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync{
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync pThis->cbKernelNames = pAddrMarkers->FlatPtr - pThis->AddrKernelNames.FlatPtr - 1;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync pThis->AddrKernelNameMarkers = *pAddrMarkers;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync pThis->cKernelNameMarkers = RT_ALIGN_32(pThis->cKernelSymbols, 256) / 256;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync pThis->AddrKernelTokenTable = *pAddrMarkers;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync DBGFR3AddrAdd(&pThis->AddrKernelTokenTable, pThis->cKernelNameMarkers * cbMarkerEntry);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync Log(("dbgDiggerLinuxFoundMarkers: AddrKernelNames=%RGv cbKernelNames=%#x\n"
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync "dbgDiggerLinuxFoundMarkers: AddrKernelNameMarkers=%RGv cKernelNameMarkers=%#x\n"
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync "dbgDiggerLinuxFoundMarkers: AddrKernelTokenTable=%RGv\n",
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync pThis->AddrKernelNames.FlatPtr, pThis->cbKernelNames,
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync pThis->AddrKernelNameMarkers.FlatPtr, pThis->cKernelNameMarkers,
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync pThis->AddrKernelTokenTable.FlatPtr));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync return VINF_SUCCESS;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync}
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync/**
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Tries to find the end of kallsyms_names and thereby the start of
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * kallsyms_markers and kallsyms_token_table.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync *
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * The kallsyms_names size is stored in pThis->cbKernelNames, the addresses of
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * the two other symbols in pThis->AddrKernelNameMarkers and
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * pThis->AddrKernelTokenTable. The number of marker entries is stored in
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * pThis->cKernelNameMarkers.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync *
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @returns VBox status code, success indicating that all three variables have
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * been found and taken down.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @param pUVM The user mode VM handle.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @param pThis The Linux digger data.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @param pHitAddr An address we think is inside kallsyms_names.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsyncstatic int dbgDiggerLinuxFindEndOfNamesAndMore(PUVM pUVM, PDBGDIGGERLINUX pThis, PCDBGFADDRESS pHitAddr)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync{
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /*
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Search forward in chunks.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync union
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint8_t ab[0x1000];
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint32_t au32[0x1000 / sizeof(uint32_t)];
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint64_t au64[0x1000 / sizeof(uint64_t)];
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync } uBuf;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync bool fPendingZeroHit = false;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint32_t cbLeft = LNX_MAX_KALLSYMS_NAMES_SIZE + sizeof(uBuf);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint32_t offBuf = pHitAddr->FlatPtr & (sizeof(uBuf) - 1);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync DBGFADDRESS CurAddr = *pHitAddr;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync DBGFR3AddrSub(&CurAddr, offBuf);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync for (;;)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync int rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &CurAddr, &uBuf, sizeof(uBuf));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (RT_FAILURE(rc))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync return rc;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /*
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * The kallsyms_names table is followed by kallsyms_markers we assume,
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * using sizeof(unsigned long) alignment like the preceeding symbols.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync *
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * The kallsyms_markers table has entried sizeof(unsigned long) and
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * contains offsets into kallsyms_names. The kallsyms_markers used to
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * index kallsyms_names and reduce seek time when looking up the name
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * of an address/symbol. Each entry in kallsyms_markers covers 256
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * symbol names.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync *
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Because of this, the first entry is always zero and all the entries
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * are ascending. It also follows that the size of the table can be
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * calculated from kallsyms_num_syms.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync *
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Note! We could also have walked kallsyms_names by skipping
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * kallsyms_num_syms names, but this is faster and we will
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * validate the encoded names later.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (pThis->f64Bit)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if ( RT_UNLIKELY(fPendingZeroHit)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && uBuf.au64[0] >= (LNX_MIN_KALLSYMS_ENC_LENGTH + 1) * 256
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && uBuf.au64[0] <= (LNX_MAX_KALLSYMS_ENC_LENGTH + 1) * 256)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync return dbgDiggerLinuxFoundMarkers(pThis, DBGFR3AddrSub(&CurAddr, sizeof(uint64_t)), sizeof(uint64_t));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint32_t const cEntries = sizeof(uBuf) / sizeof(uint64_t);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync for (uint32_t i = offBuf / sizeof(uint64_t); i < cEntries; i++)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (uBuf.au64[i] == 0)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (RT_UNLIKELY(i + 1 >= cEntries))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync fPendingZeroHit = true;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync break;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if ( uBuf.au64[i + 1] >= (LNX_MIN_KALLSYMS_ENC_LENGTH + 1) * 256
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && uBuf.au64[i + 1] <= (LNX_MAX_KALLSYMS_ENC_LENGTH + 1) * 256)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync return dbgDiggerLinuxFoundMarkers(pThis, DBGFR3AddrAdd(&CurAddr, i * sizeof(uint64_t)), sizeof(uint64_t));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync else
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if ( RT_UNLIKELY(fPendingZeroHit)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && uBuf.au32[0] >= (LNX_MIN_KALLSYMS_ENC_LENGTH + 1) * 256
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && uBuf.au32[0] <= (LNX_MAX_KALLSYMS_ENC_LENGTH + 1) * 256)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync return dbgDiggerLinuxFoundMarkers(pThis, DBGFR3AddrSub(&CurAddr, sizeof(uint32_t)), sizeof(uint32_t));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint32_t const cEntries = sizeof(uBuf) / sizeof(uint32_t);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync for (uint32_t i = offBuf / sizeof(uint32_t); i < cEntries; i++)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (uBuf.au32[i] == 0)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (RT_UNLIKELY(i + 1 >= cEntries))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync fPendingZeroHit = true;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync break;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if ( uBuf.au32[i + 1] >= (LNX_MIN_KALLSYMS_ENC_LENGTH + 1) * 256
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && uBuf.au32[i + 1] <= (LNX_MAX_KALLSYMS_ENC_LENGTH + 1) * 256)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync return dbgDiggerLinuxFoundMarkers(pThis, DBGFR3AddrAdd(&CurAddr, i * sizeof(uint32_t)), sizeof(uint32_t));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /*
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Advance
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (RT_UNLIKELY(cbLeft <= sizeof(uBuf)))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync Log(("dbgDiggerLinuxFindEndOfNamesAndMore: failed (pHitAddr=%RGv)\n", pHitAddr->FlatPtr));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync return VERR_NOT_FOUND;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync cbLeft -= sizeof(uBuf);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync DBGFR3AddrAdd(&CurAddr, sizeof(uBuf));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync offBuf = 0;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync}
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync/**
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Locates the kallsyms_token_index table.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync *
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Storing the address in pThis->AddrKernelTokenIndex and the size of the token
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * table in pThis->cbKernelTokenTable.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync *
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @returns VBox status code.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @param pUVM The user mode VM handle.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @param pThis The Linux digger data.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsyncstatic int dbgDiggerLinuxFindTokenIndex(PUVM pUVM, PDBGDIGGERLINUX pThis)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync{
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /*
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * The kallsyms_token_table is very much like a string table. Due to the
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * nature of the compression algorithm it is reasonably short (one example
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * here is 853 bytes), so we'll not be reading it in chunks but in full.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * To be on the safe side, we read 8KB, ASSUMING we won't run into unmapped
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * memory or any other nasty stuff...
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync union
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint8_t ab[0x2000];
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint16_t au16[0x2000 / sizeof(uint16_t)];
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync } uBuf;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync DBGFADDRESS CurAddr = pThis->AddrKernelTokenTable;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync int rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &CurAddr, &uBuf, sizeof(uBuf));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (RT_FAILURE(rc))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync return rc;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /*
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * We've got two choices here, either walk the string table or look for
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * the next structure, kallsyms_token_index.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync *
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * The token index is a table of 256 uint16_t entries (index by bytes
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * from kallsyms_names) that gives offsets in kallsyms_token_table. It
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * starts with a zero entry and the following entries are sorted in
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * ascending order. The range of the entries are reasonably small since
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * kallsyms_token_table is small.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync *
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * The alignment seems to be sizeof(unsigned long), just like
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * kallsyms_token_table.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync *
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * So, we start by looking for a zero 16-bit entry.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint32_t cIncr = (pThis->f64Bit ? sizeof(uint64_t) : sizeof(uint32_t)) / sizeof(uint16_t);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync for (uint32_t i = 0; i < sizeof(uBuf) / sizeof(uint16_t) - 16; i += cIncr)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if ( uBuf.au16[i] == 0
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && uBuf.au16[i + 1] > 0
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && uBuf.au16[i + 1] <= LNX_MAX_KALLSYMS_TOKEN_LEN
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && (uint16_t)(uBuf.au16[i + 2] - uBuf.au16[i + 1] - 1U) <= (uint16_t)LNX_MAX_KALLSYMS_TOKEN_LEN
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && (uint16_t)(uBuf.au16[i + 3] - uBuf.au16[i + 2] - 1U) <= (uint16_t)LNX_MAX_KALLSYMS_TOKEN_LEN
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && (uint16_t)(uBuf.au16[i + 4] - uBuf.au16[i + 3] - 1U) <= (uint16_t)LNX_MAX_KALLSYMS_TOKEN_LEN
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && (uint16_t)(uBuf.au16[i + 5] - uBuf.au16[i + 4] - 1U) <= (uint16_t)LNX_MAX_KALLSYMS_TOKEN_LEN
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && (uint16_t)(uBuf.au16[i + 6] - uBuf.au16[i + 5] - 1U) <= (uint16_t)LNX_MAX_KALLSYMS_TOKEN_LEN
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync )
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync pThis->AddrKernelTokenIndex = CurAddr;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync DBGFR3AddrAdd(&pThis->AddrKernelTokenIndex, i * sizeof(uint16_t));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync pThis->cbKernelTokenTable = i * sizeof(uint16_t);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync return VINF_SUCCESS;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync Log(("dbgDiggerLinuxFindTokenIndex: Failed (%RGv..%RGv)\n", CurAddr.FlatPtr, CurAddr.FlatPtr + (RTGCUINTPTR)sizeof(uBuf)));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync return VERR_NOT_FOUND;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync}
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync/**
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Loads the kernel symbols from the kallsyms tables.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync *
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @returns VBox status code.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @param pUVM The user mode VM handle.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @param pThis The Linux digger data.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsyncstatic int dbgDiggerLinuxLoadKernelSymbols(PUVM pUVM, PDBGDIGGERLINUX pThis)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync{
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /*
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Allocate memory for temporary table copies, reading the tables as we go.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint32_t const cbGuestAddr = pThis->f64Bit ? sizeof(uint64_t) : sizeof(uint32_t);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync void *pvAddresses = RTMemAllocZ(pThis->cKernelSymbols * cbGuestAddr);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync int rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &pThis->AddrKernelAddresses, pvAddresses, pThis->cKernelSymbols * cbGuestAddr);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (RT_SUCCESS(rc))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint8_t *pbNames = (uint8_t *)RTMemAllocZ(pThis->cbKernelNames);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &pThis->AddrKernelNames, pbNames, pThis->cbKernelNames);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (RT_SUCCESS(rc))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync char *pszzTokens = (char *)RTMemAllocZ(pThis->cbKernelTokenTable);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &pThis->AddrKernelTokenTable, pszzTokens, pThis->cbKernelTokenTable);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (RT_SUCCESS(rc))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint16_t *paoffTokens = (uint16_t *)RTMemAllocZ(256 * sizeof(uint16_t));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &pThis->AddrKernelTokenIndex, paoffTokens, 256 * sizeof(uint16_t));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (RT_SUCCESS(rc))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /*
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Figure out the kernel start and end.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync RTGCUINTPTR uKernelStart = pThis->AddrKernelAddresses.FlatPtr;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync RTGCUINTPTR uKernelEnd = pThis->AddrKernelTokenIndex.FlatPtr + 256 * sizeof(uint16_t);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint32_t i;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (cbGuestAddr == sizeof(uint64_t))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint64_t *pauAddrs = (uint64_t *)pvAddresses;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync for (i = 0; i < pThis->cKernelSymbols; i++)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if ( pauAddrs[i] < uKernelStart
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && LNX64_VALID_ADDRESS(pauAddrs[i])
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && uKernelStart - pauAddrs[i] < LNX_MAX_KERNEL_SIZE)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uKernelStart = pauAddrs[i];
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync for (i = pThis->cKernelSymbols - 1; i > 0; i--)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if ( pauAddrs[i] > uKernelEnd
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && LNX64_VALID_ADDRESS(pauAddrs[i])
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && pauAddrs[i] - uKernelEnd < LNX_MAX_KERNEL_SIZE)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uKernelEnd = pauAddrs[i];
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync else
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint32_t *pauAddrs = (uint32_t *)pvAddresses;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync for (i = 0; i < pThis->cKernelSymbols; i++)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if ( pauAddrs[i] < uKernelStart
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && LNX32_VALID_ADDRESS(pauAddrs[i])
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && uKernelStart - pauAddrs[i] < LNX_MAX_KERNEL_SIZE)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uKernelStart = pauAddrs[i];
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync for (i = pThis->cKernelSymbols - 1; i > 0; i--)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if ( pauAddrs[i] > uKernelEnd
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && LNX32_VALID_ADDRESS(pauAddrs[i])
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && pauAddrs[i] - uKernelEnd < LNX_MAX_KERNEL_SIZE)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uKernelEnd = pauAddrs[i];
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync RTGCUINTPTR cbKernel = uKernelEnd - uKernelStart;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync pThis->cbKernel = (uint32_t)cbKernel;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync DBGFR3AddrFromFlat(pUVM, &pThis->AddrKernelBase, uKernelStart);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync Log(("dbgDiggerLinuxLoadKernelSymbols: uKernelStart=%RGv cbKernel=%#x\n", uKernelStart, cbKernel));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /*
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Create a module for the kernel.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync RTDBGMOD hMod;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync rc = RTDbgModCreate(&hMod, "vmlinux", cbKernel, 0 /*fFlags*/);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (RT_SUCCESS(rc))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync rc = RTDbgModSetTag(hMod, DIG_LNX_MOD_TAG); AssertRC(rc);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync rc = VINF_SUCCESS;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /*
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Enumerate the symbols.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint8_t const *pbCurAddr = (uint8_t const *)pvAddresses;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint32_t offName = 0;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint32_t cLeft = pThis->cKernelSymbols;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync while (cLeft-- > 0 && RT_SUCCESS(rc))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /* Decode the symbol name first. */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (RT_LIKELY(offName < pThis->cbKernelNames))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint8_t cbName = pbNames[offName++];
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (RT_LIKELY(offName + cbName <= pThis->cbKernelNames))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync char szSymbol[4096];
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint32_t offSymbol = 0;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync while (cbName-- > 0)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint8_t bEnc = pbNames[offName++];
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint16_t offToken = paoffTokens[bEnc];
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (RT_LIKELY(offToken < pThis->cbKernelTokenTable))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync const char *pszToken = &pszzTokens[offToken];
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync char ch;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync while ((ch = *pszToken++) != '\0')
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (offSymbol < sizeof(szSymbol) - 1)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync szSymbol[offSymbol++] = ch;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync else
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync rc = VERR_INVALID_UTF8_ENCODING;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync break;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync szSymbol[offSymbol < sizeof(szSymbol) ? offSymbol : sizeof(szSymbol) - 1] = '\0';
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /* The address. */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync RTGCUINTPTR uSymAddr = cbGuestAddr == sizeof(uint64_t)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync ? *(uint64_t *)pbCurAddr : *(uint32_t *)pbCurAddr;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync pbCurAddr += cbGuestAddr;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /* Add it without the type char. */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (uSymAddr - uKernelStart <= cbKernel)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync rc = RTDbgModSymbolAdd(hMod, &szSymbol[1], RTDBGSEGIDX_RVA, uSymAddr - uKernelStart,
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync 0 /*cb*/, 0 /*fFlags*/, NULL);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (RT_FAILURE(rc))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if ( rc == VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync || rc == VERR_DBG_INVALID_RVA
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync || rc == VERR_DBG_ADDRESS_CONFLICT
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync || rc == VERR_DBG_DUPLICATE_SYMBOL)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync Log2(("dbgDiggerLinuxLoadKernelSymbols: RTDbgModSymbolAdd(,%s,) failed %Rrc (ignored)\n", szSymbol, rc));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync rc = VINF_SUCCESS;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync else
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync Log(("dbgDiggerLinuxLoadKernelSymbols: RTDbgModSymbolAdd(,%s,) failed %Rrc\n", szSymbol, rc));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync else
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync rc = VERR_END_OF_STRING;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync Log(("dbgDiggerLinuxLoadKernelSymbols: offName=%#x cLeft=%#x cbName=%#x cbKernelNames=%#x\n",
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync offName, cLeft, cbName, pThis->cbKernelNames));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync else
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync rc = VERR_END_OF_STRING;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync Log(("dbgDiggerLinuxLoadKernelSymbols: offName=%#x cLeft=%#x cbKernelNames=%#x\n",
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync offName, cLeft, pThis->cbKernelNames));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /*
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Link the module into the address space.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (RT_SUCCESS(rc))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync RTDBGAS hAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (hAs != NIL_RTDBGAS)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync rc = RTDbgAsModuleLink(hAs, hMod, uKernelStart, RTDBGASLINK_FLAGS_REPLACE);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync else
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync rc = VERR_INTERNAL_ERROR;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync RTDbgAsRelease(hAs);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync else
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync Log(("dbgDiggerLinuxFindTokenIndex: Failed: %Rrc\n", rc));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync RTDbgModRelease(hMod);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync else
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync Log(("dbgDiggerLinuxFindTokenIndex: RTDbgModCreate failed: %Rrc\n", rc));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync else
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync Log(("dbgDiggerLinuxFindTokenIndex: Reading token index at %RGv failed: %Rrc\n",
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync pThis->AddrKernelTokenIndex.FlatPtr, rc));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync RTMemFree(paoffTokens);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync else
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync Log(("dbgDiggerLinuxFindTokenIndex: Reading token table at %RGv failed: %Rrc\n",
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync pThis->AddrKernelTokenTable.FlatPtr, rc));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync RTMemFree(pszzTokens);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync else
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync Log(("dbgDiggerLinuxFindTokenIndex: Reading encoded names at %RGv failed: %Rrc\n",
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync pThis->AddrKernelNames.FlatPtr, rc));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync RTMemFree(pbNames);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync else
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync Log(("dbgDiggerLinuxFindTokenIndex: Reading symbol addresses at %RGv failed: %Rrc\n",
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync pThis->AddrKernelAddresses.FlatPtr, rc));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync RTMemFree(pvAddresses);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync return rc;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync}
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync/**
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Checks if there is a likely kallsyms_names fragment at pHitAddr.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync *
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @returns true if it's a likely fragment, false if not.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @param pUVM The user mode VM handle.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @param pHitAddr The address where paNeedle was found.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @param pabNeedle The fragment we've been searching for.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * @param cbNeedle The length of the fragment.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsyncstatic bool dbgDiggerLinuxIsLikelyNameFragment(PUVM pUVM, PCDBGFADDRESS pHitAddr, uint8_t const *pabNeedle, uint8_t cbNeedle)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync{
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /*
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Examples of lead and tail bytes of our choosen needle in a randomly
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * picked kernel:
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * k o b j
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * 22 6b 6f 62 6a aa
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * fc 6b 6f 62 6a aa
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * 82 6b 6f 62 6a 5f - ascii trail byte (_).
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * ee 6b 6f 62 6a aa
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * fc 6b 6f 62 6a 5f - ascii trail byte (_).
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * 0a 74 6b 6f 62 6a 5f ea - ascii lead (t) and trail (_) bytes.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * 0b 54 6b 6f 62 6a aa - ascii lead byte (T).
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * ... omitting 29 samples similar to the last two ...
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * d8 6b 6f 62 6a aa
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * d8 6b 6f 62 6a aa
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * d8 6b 6f 62 6a aa
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * d8 6b 6f 62 6a aa
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * f9 5f 6b 6f 62 6a 5f 94 - ascii lead and trail bytes (_)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * f9 5f 6b 6f 62 6a 0c - ascii lead byte (_).
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * fd 6b 6f 62 6a 0f
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * ... enough.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint8_t abBuf[32];
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync DBGFADDRESS ReadAddr = *pHitAddr;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync DBGFR3AddrSub(&ReadAddr, 2);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync int rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &ReadAddr, abBuf, 2 + cbNeedle + 2);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (RT_SUCCESS(rc))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (memcmp(&abBuf[2], pabNeedle, cbNeedle) == 0) /* paranoia */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint8_t const bLead = abBuf[1] == '_' || abBuf[1] == 'T' || abBuf[1] == 't' ? abBuf[0] : abBuf[1];
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint8_t const offTail = 2 + cbNeedle;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint8_t const bTail = abBuf[offTail] == '_' ? abBuf[offTail] : abBuf[offTail + 1];
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if ( bLead >= 1 && (bLead < 0x20 || bLead >= 0x80)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && bTail >= 1 && (bTail < 0x20 || bTail >= 0x80))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync return true;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync Log(("dbgDiggerLinuxIsLikelyNameFragment: failed at %RGv: bLead=%#x bTail=%#x (offTail=%#x)\n",
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync pHitAddr->FlatPtr, bLead, bTail, offTail));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync else
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync Log(("dbgDiggerLinuxIsLikelyNameFragment: failed at %RGv: Needle changed!\n", pHitAddr->FlatPtr));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync else
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync Log(("dbgDiggerLinuxIsLikelyNameFragment: failed at %RGv: %Rrc\n", pHitAddr->FlatPtr, rc));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync return false;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync}
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/**
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @copydoc DBGFOSREG::pfnInit
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
98427c0ab08697e468c26dc33ee9571308577867vboxsyncstatic DECLCALLBACK(int) dbgDiggerLinuxInit(PUVM pUVM, void *pvData)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync{
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync PDBGDIGGERLINUX pThis = (PDBGDIGGERLINUX)pvData;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(!pThis->fValid);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /*
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Assume 64-bit kernels all live way beyond 32-bit address space.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync pThis->f64Bit = pThis->AddrLinuxBanner.FlatPtr > UINT32_MAX;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /*
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Go looking for the kallsyms table. If it's there, it will be somewhere
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * after the linux_banner symbol, so use it for starting the search.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync DBGFADDRESS CurAddr = pThis->AddrLinuxBanner;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync uint32_t cbLeft = LNX_MAX_KERNEL_SIZE;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync while (cbLeft > 4096)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync static const uint8_t s_abNeedle[] = "kobj";
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync DBGFADDRESS HitAddr;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync int rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &CurAddr, cbLeft, 1 /*uAlign*/,
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync s_abNeedle, sizeof(s_abNeedle) - 1, &HitAddr);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (RT_FAILURE(rc))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync break;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (dbgDiggerLinuxIsLikelyNameFragment(pUVM, &HitAddr, s_abNeedle, sizeof(s_abNeedle) - 1))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /* There will be another hit near by. */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync DBGFR3AddrAdd(&HitAddr, 1);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &HitAddr, LNX_MAX_KALLSYMS_NAMES_SIZE, 1 /*uAlign*/,
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync s_abNeedle, sizeof(s_abNeedle) - 1, &HitAddr);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if ( RT_SUCCESS(rc)
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync && dbgDiggerLinuxIsLikelyNameFragment(pUVM, &HitAddr, s_abNeedle, sizeof(s_abNeedle) - 1))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /*
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * We've got a very likely candidate for a location inside kallsyms_names.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Try find the start of it, that is to say, try find kallsyms_num_syms.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * kallsyms_num_syms is aligned on sizeof(unsigned long) boundrary
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync rc = dbgDiggerLinuxFindStartOfNamesAndSymbolCount(pUVM, pThis, &HitAddr);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (RT_SUCCESS(rc))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync rc = dbgDiggerLinuxFindEndOfNamesAndMore(pUVM, pThis, &HitAddr);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (RT_SUCCESS(rc))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync rc = dbgDiggerLinuxFindTokenIndex(pUVM, pThis);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (RT_SUCCESS(rc))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync rc = dbgDiggerLinuxLoadKernelSymbols(pUVM, pThis);
f2ffd08143645ae9fe9c2a8d74aebc5bc54ad127vboxsync if (RT_SUCCESS(rc))
f2ffd08143645ae9fe9c2a8d74aebc5bc54ad127vboxsync break;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync /*
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Advance.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync */
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync RTGCUINTPTR cbDistance = HitAddr.FlatPtr - CurAddr.FlatPtr + sizeof(s_abNeedle) - 1;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync if (RT_UNLIKELY(cbDistance >= cbLeft))
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync {
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync Log(("dbgDiggerLinuxInit: Failed to find kallsyms\n"));
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync break;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync cbLeft -= cbDistance;
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync DBGFR3AddrAdd(&CurAddr, cbDistance);
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pThis->fValid = true;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync return VINF_SUCCESS;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync}
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/**
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @copydoc DBGFOSREG::pfnProbe
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
98427c0ab08697e468c26dc33ee9571308577867vboxsyncstatic DECLCALLBACK(bool) dbgDiggerLinuxProbe(PUVM pUVM, void *pvData)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync{
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync PDBGDIGGERLINUX pThis = (PDBGDIGGERLINUX)pvData;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /*
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Look for "Linux version " at the start of the rodata segment.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Hope that this comes before any message buffer or other similar string.
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync *
3b9f25e2647d504f97555ccad843b0380e79bda4vboxsync * Note! Only Linux version 2.x.y, where x in {0..6}.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync for (unsigned i = 0; i < RT_ELEMENTS(g_au64LnxKernelAddresses); i++)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync DBGFADDRESS KernelAddr;
98427c0ab08697e468c26dc33ee9571308577867vboxsync DBGFR3AddrFromFlat(pUVM, &KernelAddr, g_au64LnxKernelAddresses[i]);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync DBGFADDRESS HitAddr;
15bdc996156e4d4ef809be1d15337db5247066aavboxsync static const uint8_t s_abLinuxVersion2x[] = "Linux version 2.";
98427c0ab08697e468c26dc33ee9571308577867vboxsync int rc = DBGFR3MemScan(pUVM, 0, &KernelAddr, LNX_MAX_KERNEL_SIZE, 1,
15bdc996156e4d4ef809be1d15337db5247066aavboxsync s_abLinuxVersion2x, sizeof(s_abLinuxVersion2x) - 1, &HitAddr);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (RT_SUCCESS(rc))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync char szTmp[128];
15bdc996156e4d4ef809be1d15337db5247066aavboxsync char const *pszY = &szTmp[sizeof(s_abLinuxVersion2x) - 1];
98427c0ab08697e468c26dc33ee9571308577867vboxsync rc = DBGFR3MemReadString(pUVM, 0, &HitAddr, szTmp, sizeof(szTmp));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if ( RT_SUCCESS(rc)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync && *pszY >= '0'
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync && *pszY <= '6')
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pThis->AddrKernelBase = KernelAddr;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pThis->AddrLinuxBanner = HitAddr;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync return true;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
15bdc996156e4d4ef809be1d15337db5247066aavboxsync static const uint8_t s_abLinuxVersion3x[] = "Linux version 3.";
15bdc996156e4d4ef809be1d15337db5247066aavboxsync rc = DBGFR3MemScan(pUVM, 0, &KernelAddr, LNX_MAX_KERNEL_SIZE, 1,
15bdc996156e4d4ef809be1d15337db5247066aavboxsync s_abLinuxVersion3x, sizeof(s_abLinuxVersion3x) - 1, &HitAddr);
15bdc996156e4d4ef809be1d15337db5247066aavboxsync if (RT_SUCCESS(rc))
15bdc996156e4d4ef809be1d15337db5247066aavboxsync {
15bdc996156e4d4ef809be1d15337db5247066aavboxsync char szTmp[128];
15bdc996156e4d4ef809be1d15337db5247066aavboxsync char const *pszY = &szTmp[sizeof(s_abLinuxVersion3x) - 1];
15bdc996156e4d4ef809be1d15337db5247066aavboxsync rc = DBGFR3MemReadString(pUVM, 0, &HitAddr, szTmp, sizeof(szTmp));
15bdc996156e4d4ef809be1d15337db5247066aavboxsync if ( RT_SUCCESS(rc)
15bdc996156e4d4ef809be1d15337db5247066aavboxsync && *pszY >= '0'
15bdc996156e4d4ef809be1d15337db5247066aavboxsync && *pszY <= '9')
15bdc996156e4d4ef809be1d15337db5247066aavboxsync {
15bdc996156e4d4ef809be1d15337db5247066aavboxsync pThis->AddrKernelBase = KernelAddr;
15bdc996156e4d4ef809be1d15337db5247066aavboxsync pThis->AddrLinuxBanner = HitAddr;
15bdc996156e4d4ef809be1d15337db5247066aavboxsync return true;
15bdc996156e4d4ef809be1d15337db5247066aavboxsync }
15bdc996156e4d4ef809be1d15337db5247066aavboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync return false;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync}
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/**
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @copydoc DBGFOSREG::pfnDestruct
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
98427c0ab08697e468c26dc33ee9571308577867vboxsyncstatic DECLCALLBACK(void) dbgDiggerLinuxDestruct(PUVM pUVM, void *pvData)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync{
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync}
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/**
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @copydoc DBGFOSREG::pfnConstruct
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
98427c0ab08697e468c26dc33ee9571308577867vboxsyncstatic DECLCALLBACK(int) dbgDiggerLinuxConstruct(PUVM pUVM, void *pvData)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync{
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync PDBGDIGGERLINUX pThis = (PDBGDIGGERLINUX)pvData;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync pThis->IDmesg.u32Magic = DBGFOSIDMESG_MAGIC;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync pThis->IDmesg.pfnQueryKernelLog = dbgDiggerLinuxIDmsg_QueryKernelLog;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync pThis->IDmesg.u32EndMagic = DBGFOSIDMESG_MAGIC;
17d11b8f5a067c2ac0d8d2055fb0eca96199a048vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync return VINF_SUCCESS;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync}
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncconst DBGFOSREG g_DBGDiggerLinux =
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync{
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* .u32Magic = */ DBGFOSREG_MAGIC,
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* .fFlags = */ 0,
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* .cbData = */ sizeof(DBGDIGGERLINUX),
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* .szName = */ "Linux",
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* .pfnConstruct = */ dbgDiggerLinuxConstruct,
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* .pfnDestruct = */ dbgDiggerLinuxDestruct,
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* .pfnProbe = */ dbgDiggerLinuxProbe,
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* .pfnInit = */ dbgDiggerLinuxInit,
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* .pfnRefresh = */ dbgDiggerLinuxRefresh,
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* .pfnTerm = */ dbgDiggerLinuxTerm,
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* .pfnQueryVersion = */ dbgDiggerLinuxQueryVersion,
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* .pfnQueryInterface = */ dbgDiggerLinuxQueryInterface,
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* .u32EndMagic = */ DBGFOSREG_MAGIC
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync};
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync