VirtualBox

source: vbox/trunk/src/VBox/Debugger/DBGPlugInFreeBsd.cpp@ 64372

Last change on this file since 64372 was 64372, checked in by vboxsync, 9 years ago

properties

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.9 KB
Line 
1/* $Id: DBGPlugInFreeBsd.cpp 64372 2016-10-23 00:54:01Z vboxsync $ */
2/** @file
3 * DBGPlugInFreeBsd - Debugger and Guest OS Digger Plugin For FreeBSD.
4 */
5
6/*
7 * Copyright (C) 2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DBGF /// @todo add new log group.
23#include "DBGPlugIns.h"
24#include "DBGPlugInCommonELF.h"
25#include <VBox/vmm/dbgf.h>
26#include <iprt/asm.h>
27#include <iprt/mem.h>
28#include <iprt/stream.h>
29#include <iprt/string.h>
30
31
32/*********************************************************************************************************************************
33* Defined Constants And Macros *
34*********************************************************************************************************************************/
35/** FreeBSD on little endian ASCII systems. */
36#define DIG_FBSD_MOD_TAG UINT64_C(0x0044534265657246)
37
38
39/*********************************************************************************************************************************
40* Structures and Typedefs *
41*********************************************************************************************************************************/
42
43/**
44 * FreeBSD guest OS digger instance data.
45 */
46typedef struct DBGDIGGERFBSD
47{
48 /** Whether the information is valid or not.
49 * (For fending off illegal interface method calls.) */
50 bool fValid;
51 /** 64-bit/32-bit indicator. */
52 bool f64Bit;
53
54 /** Address of the start of the kernel ELF image,
55 * set during probing. */
56 DBGFADDRESS AddrKernelElfStart;
57
58} DBGDIGGERFBSD;
59/** Pointer to the FreeBSD guest OS digger instance data. */
60typedef DBGDIGGERFBSD *PDBGDIGGERFBSD;
61
62
63/*********************************************************************************************************************************
64* Defined Constants And Macros *
65*********************************************************************************************************************************/
66/** Min kernel address (32bit). */
67#define FBSD32_MIN_KRNL_ADDR UINT32_C(0x80000000)
68/** Max kernel address (32bit). */
69#define FBSD32_MAX_KRNL_ADDR UINT32_C(0xfffff000)
70
71/** Min kernel address (64bit). */
72#define FBSD64_MIN_KRNL_ADDR UINT64_C(0xFFFFFE0000000000)
73/** Max kernel address (64bit). */
74#define FBSD64_MAX_KRNL_ADDR UINT64_C(0xFFFFFFFFFFF00000)
75
76
77/** Validates a 32-bit FreeBSD kernel address */
78#define FBSD32_VALID_ADDRESS(Addr) ( (Addr) > FBSD32_MIN_KRNL_ADDR \
79 && (Addr) < FBSD32_MAX_KRNL_ADDR)
80/** Validates a 64-bit FreeBSD kernel address */
81#define FBSD64_VALID_ADDRESS(Addr) ( (Addr) > FBSD64_MIN_KRNL_ADDR \
82 && (Addr) < FBSD64_MAX_KRNL_ADDR)
83
84/** Maximum offset from the start of the ELF image we look for the /red/herring .interp section content. */
85#define FBSD_MAX_INTERP_OFFSET _16K
86/** The max kernel size. */
87#define FBSD_MAX_KERNEL_SIZE UINT32_C(0x0f000000)
88
89
90/*********************************************************************************************************************************
91* Internal Functions *
92*********************************************************************************************************************************/
93static DECLCALLBACK(int) dbgDiggerFreeBsdInit(PUVM pUVM, void *pvData);
94
95/*********************************************************************************************************************************
96* Global Variables *
97*********************************************************************************************************************************/
98/** Table of common FreeBSD kernel addresses. */
99static uint64_t g_au64FreeBsdKernelAddresses[] =
100{
101 UINT64_C(0xc0100000),
102 UINT64_C(0xffffffff80100000)
103};
104
105/**
106 * @copydoc DBGFOSREG::pfnQueryInterface
107 */
108static DECLCALLBACK(void *) dbgDiggerFreeBsdQueryInterface(PUVM pUVM, void *pvData, DBGFOSINTERFACE enmIf)
109{
110 RT_NOREF3(pUVM, pvData, enmIf);
111 return NULL;
112}
113
114
115/**
116 * @copydoc DBGFOSREG::pfnQueryVersion
117 */
118static DECLCALLBACK(int) dbgDiggerFreeBsdQueryVersion(PUVM pUVM, void *pvData, char *pszVersion, size_t cchVersion)
119{
120 PDBGDIGGERFBSD pThis = (PDBGDIGGERFBSD)pvData;
121 Assert(pThis->fValid);
122
123 RT_NOREF4(pUVM, pThis, pszVersion, cchVersion);
124
125 return VERR_NOT_IMPLEMENTED;
126}
127
128
129
130/**
131 * @copydoc DBGFOSREG::pfnTerm
132 */
133static DECLCALLBACK(void) dbgDiggerFreeBsdTerm(PUVM pUVM, void *pvData)
134{
135 RT_NOREF1(pUVM);
136 PDBGDIGGERFBSD pThis = (PDBGDIGGERFBSD)pvData;
137 Assert(pThis->fValid);
138
139 RT_NOREF1(pUVM);
140
141 pThis->fValid = false;
142}
143
144
145/**
146 * @copydoc DBGFOSREG::pfnRefresh
147 */
148static DECLCALLBACK(int) dbgDiggerFreeBsdRefresh(PUVM pUVM, void *pvData)
149{
150 PDBGDIGGERFBSD pThis = (PDBGDIGGERFBSD)pvData;
151 NOREF(pThis);
152 Assert(pThis->fValid);
153
154 dbgDiggerFreeBsdTerm(pUVM, pvData);
155 return dbgDiggerFreeBsdInit(pUVM, pvData);
156}
157
158
159/**
160 * @copydoc DBGFOSREG::pfnInit
161 */
162static DECLCALLBACK(int) dbgDiggerFreeBsdInit(PUVM pUVM, void *pvData)
163{
164 PDBGDIGGERFBSD pThis = (PDBGDIGGERFBSD)pvData;
165 Assert(!pThis->fValid);
166
167 RT_NOREF1(pUVM);
168
169 pThis->fValid = true;
170 return VINF_SUCCESS;
171}
172
173
174/**
175 * @copydoc DBGFOSREG::pfnProbe
176 */
177static DECLCALLBACK(bool) dbgDiggerFreeBsdProbe(PUVM pUVM, void *pvData)
178{
179 PDBGDIGGERFBSD pThis = (PDBGDIGGERFBSD)pvData;
180
181 /*
182 * Look for the magic ELF header near the known start addresses.
183 * If one is found look for the magic "/red/herring" string which is in the
184 * "interp" section not far away and then validate the start of the ELF header
185 * to be sure.
186 */
187 for (unsigned i = 0; i < RT_ELEMENTS(g_au64FreeBsdKernelAddresses); i++)
188 {
189 static const uint8_t s_abNeedle[] = ELFMAG;
190 DBGFADDRESS KernelAddr;
191 DBGFR3AddrFromFlat(pUVM, &KernelAddr, g_au64FreeBsdKernelAddresses[i]);
192 DBGFADDRESS HitAddr;
193 uint32_t cbLeft = FBSD_MAX_KERNEL_SIZE;
194
195 while (cbLeft > X86_PAGE_4K_SIZE)
196 {
197 int rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &KernelAddr, cbLeft, 1,
198 s_abNeedle, sizeof(s_abNeedle) - 1, &HitAddr);
199 if (RT_FAILURE(rc))
200 break;
201
202 /*
203 * Look for the magic "/red/herring" near the header and verify the basic
204 * ELF header.
205 */
206 static const uint8_t s_abNeedleInterp[] = "/red/herring";
207 DBGFADDRESS HitAddrInterp;
208 rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &HitAddr, FBSD_MAX_INTERP_OFFSET, 1,
209 s_abNeedleInterp, sizeof(s_abNeedleInterp), &HitAddrInterp);
210 if (RT_SUCCESS(rc))
211 {
212 union
213 {
214 uint8_t ab[2 * X86_PAGE_4K_SIZE];
215 Elf32_Ehdr Hdr32;
216 Elf64_Ehdr Hdr64;
217 } ElfHdr;
218 AssertCompileMembersSameSizeAndOffset(Elf64_Ehdr, e_ident, Elf32_Ehdr, e_ident);
219 AssertCompileMembersSameSizeAndOffset(Elf64_Ehdr, e_type, Elf32_Ehdr, e_type);
220 AssertCompileMembersSameSizeAndOffset(Elf64_Ehdr, e_machine, Elf32_Ehdr, e_machine);
221 AssertCompileMembersSameSizeAndOffset(Elf64_Ehdr, e_version, Elf32_Ehdr, e_version);
222
223 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &HitAddr, &ElfHdr.ab[0], X86_PAGE_4K_SIZE);
224 if (RT_SUCCESS(rc))
225 {
226 /* We verified the magic above already by scanning for it. */
227 if ( ( ElfHdr.Hdr32.e_ident[EI_CLASS] == ELFCLASS32
228 || ElfHdr.Hdr32.e_ident[EI_CLASS] == ELFCLASS64)
229 && ElfHdr.Hdr32.e_ident[EI_DATA] == ELFDATA2LSB
230 && ElfHdr.Hdr32.e_ident[EI_VERSION] == EV_CURRENT
231 && ElfHdr.Hdr32.e_ident[EI_OSABI] == ELFOSABI_FREEBSD
232 && ElfHdr.Hdr32.e_type == ET_EXEC
233 && ( ElfHdr.Hdr32.e_machine == EM_386
234 || ElfHdr.Hdr32.e_machine == EM_X86_64)
235 && ElfHdr.Hdr32.e_version == EV_CURRENT)
236 {
237 pThis->f64Bit = ElfHdr.Hdr32.e_ident[EI_CLASS] == ELFCLASS64;
238 pThis->AddrKernelElfStart = HitAddr;
239 return true;
240 }
241 }
242 }
243
244 /*
245 * Advance.
246 */
247 RTGCUINTPTR cbDistance = HitAddr.FlatPtr - KernelAddr.FlatPtr + sizeof(s_abNeedle) - 1;
248 if (RT_UNLIKELY(cbDistance >= cbLeft))
249 break;
250
251 cbLeft -= cbDistance;
252 DBGFR3AddrAdd(&KernelAddr, cbDistance);
253 }
254 }
255 return false;
256}
257
258
259/**
260 * @copydoc DBGFOSREG::pfnDestruct
261 */
262static DECLCALLBACK(void) dbgDiggerFreeBsdDestruct(PUVM pUVM, void *pvData)
263{
264 RT_NOREF2(pUVM, pvData);
265}
266
267
268/**
269 * @copydoc DBGFOSREG::pfnConstruct
270 */
271static DECLCALLBACK(int) dbgDiggerFreeBsdConstruct(PUVM pUVM, void *pvData)
272{
273 RT_NOREF2(pUVM, pvData);
274 return VINF_SUCCESS;
275}
276
277
278const DBGFOSREG g_DBGDiggerFreeBsd =
279{
280 /* .u32Magic = */ DBGFOSREG_MAGIC,
281 /* .fFlags = */ 0,
282 /* .cbData = */ sizeof(DBGDIGGERFBSD),
283 /* .szName = */ "FreeBSD",
284 /* .pfnConstruct = */ dbgDiggerFreeBsdConstruct,
285 /* .pfnDestruct = */ dbgDiggerFreeBsdDestruct,
286 /* .pfnProbe = */ dbgDiggerFreeBsdProbe,
287 /* .pfnInit = */ dbgDiggerFreeBsdInit,
288 /* .pfnRefresh = */ dbgDiggerFreeBsdRefresh,
289 /* .pfnTerm = */ dbgDiggerFreeBsdTerm,
290 /* .pfnQueryVersion = */ dbgDiggerFreeBsdQueryVersion,
291 /* .pfnQueryInterface = */ dbgDiggerFreeBsdQueryInterface,
292 /* .u32EndMagic = */ DBGFOSREG_MAGIC
293};
294
Note: See TracBrowser for help on using the repository browser.

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