VirtualBox

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

Last change on this file since 71872 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.3 KB
Line 
1/* $Id: DBGPlugInFreeBsd.cpp 69500 2017-10-28 15:14:05Z vboxsync $ */
2/** @file
3 * DBGPlugInFreeBsd - Debugger and Guest OS Digger Plugin For FreeBSD.
4 */
5
6/*
7 * Copyright (C) 2016-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
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/ctype.h>
28#include <iprt/mem.h>
29#include <iprt/stream.h>
30#include <iprt/string.h>
31
32
33/*********************************************************************************************************************************
34* Defined Constants And Macros *
35*********************************************************************************************************************************/
36/** FreeBSD on little endian ASCII systems. */
37#define DIG_FBSD_MOD_TAG UINT64_C(0x0044534265657246)
38
39
40/*********************************************************************************************************************************
41* Structures and Typedefs *
42*********************************************************************************************************************************/
43
44/**
45 * ELF headers union.
46 */
47typedef union ELFEHDRS
48{
49 /** 32bit version of the ELF header. */
50 Elf32_Ehdr Hdr32;
51 /** 64bit version of the ELF header. */
52 Elf64_Ehdr Hdr64;
53} ELFEHDRS;
54/** Pointer to a ELF header union. */
55typedef ELFEHDRS *PELFEHDRS;
56/** Pointer to const ELF header union. */
57typedef ELFEHDRS const *PCELFEHDRS;
58
59/**
60 * ELF symbol entry union.
61 */
62typedef union ELFSYMS
63{
64 /** 32bit version of the ELF section header. */
65 Elf32_Sym Hdr32;
66 /** 64bit version of the ELF section header. */
67 Elf64_Sym Hdr64;
68} ELFSYMS;
69/** Pointer to a ELF symbol entry union. */
70typedef ELFSYMS *PELFSYMS;
71/** Pointer to const ELF symbol entry union. */
72typedef ELFSYMS const *PCELFSYMS;
73
74/**
75 * Message buffer structure.
76 */
77typedef union FBSDMSGBUF
78{
79 /** 32bit version. */
80 struct
81 {
82 /** Message buffer pointer. */
83 uint32_t msg_ptr;
84 /** Magic value to identify the structure. */
85 uint32_t msg_magic;
86 /** Size of the buffer area. */
87 uint32_t msg_size;
88 /** Write sequence number. */
89 uint32_t msg_wseq;
90 /** Read sequence number. */
91 uint32_t msg_rseq;
92 /** @todo More fields which are not required atm. */
93 } Hdr32;
94 /** 64bit version. */
95 struct
96 {
97 /** Message buffer pointer. */
98 uint64_t msg_ptr;
99 /** Magic value to identify the structure. */
100 uint32_t msg_magic;
101 /** Size of the buffer area. */
102 uint32_t msg_size;
103 /** Write sequence number. */
104 uint32_t msg_wseq;
105 /** Read sequence number. */
106 uint32_t msg_rseq;
107 /** @todo More fields which are not required atm. */
108 } Hdr64;
109} FBSDMSGBUF;
110/** Pointer to a message buffer structure. */
111typedef FBSDMSGBUF *PFBSDMSGBUF;
112/** Pointer to a const message buffer structure. */
113typedef FBSDMSGBUF const *PCFBSDMSGBUF;
114
115/** Magic value to identify the message buffer structure. */
116#define FBSD_MSGBUF_MAGIC UINT32_C(0x063062)
117
118/**
119 * FreeBSD guest OS digger instance data.
120 */
121typedef struct DBGDIGGERFBSD
122{
123 /** Whether the information is valid or not.
124 * (For fending off illegal interface method calls.) */
125 bool fValid;
126 /** 64-bit/32-bit indicator. */
127 bool f64Bit;
128
129 /** Address of the start of the kernel ELF image,
130 * set during probing. */
131 DBGFADDRESS AddrKernelElfStart;
132 /** Address of the interpreter content aka "/red/herring". */
133 DBGFADDRESS AddrKernelInterp;
134 /** Address of the start of the text section. */
135 DBGFADDRESS AddrKernelText;
136
137 /** The kernel message log interface. */
138 DBGFOSIDMESG IDmesg;
139
140} DBGDIGGERFBSD;
141/** Pointer to the FreeBSD guest OS digger instance data. */
142typedef DBGDIGGERFBSD *PDBGDIGGERFBSD;
143
144
145/*********************************************************************************************************************************
146* Defined Constants And Macros *
147*********************************************************************************************************************************/
148/** Min kernel address (32bit). */
149#define FBSD32_MIN_KRNL_ADDR UINT32_C(0x80000000)
150/** Max kernel address (32bit). */
151#define FBSD32_MAX_KRNL_ADDR UINT32_C(0xfffff000)
152
153/** Min kernel address (64bit). */
154#define FBSD64_MIN_KRNL_ADDR UINT64_C(0xFFFFF80000000000)
155/** Max kernel address (64bit). */
156#define FBSD64_MAX_KRNL_ADDR UINT64_C(0xFFFFFFFFFFF00000)
157
158
159/** Validates a 32-bit FreeBSD kernel address */
160#define FBSD32_VALID_ADDRESS(Addr) ( (Addr) > FBSD32_MIN_KRNL_ADDR \
161 && (Addr) < FBSD32_MAX_KRNL_ADDR)
162/** Validates a 64-bit FreeBSD kernel address */
163#define FBSD64_VALID_ADDRESS(Addr) ( (Addr) > FBSD64_MIN_KRNL_ADDR \
164 && (Addr) < FBSD64_MAX_KRNL_ADDR)
165
166/** Validates a FreeBSD kernel address. */
167#define FBSD_VALID_ADDRESS(a_pThis, a_Addr) ((a_pThis)->f64Bit ? FBSD64_VALID_ADDRESS(a_Addr) : FBSD32_VALID_ADDRESS(a_Addr))
168
169/** Maximum offset from the start of the ELF image we look for the /red/herring .interp section content. */
170#define FBSD_MAX_INTERP_OFFSET _16K
171/** The max kernel size. */
172#define FBSD_MAX_KERNEL_SIZE UINT32_C(0x0f000000)
173
174/** Versioned and bitness wrapper. */
175#define FBSD_UNION(a_pThis, a_pUnion, a_Member) ((a_pThis)->f64Bit ? (a_pUnion)->Hdr64. a_Member : (a_pUnion)->Hdr32. a_Member )
176
177
178/*********************************************************************************************************************************
179* Internal Functions *
180*********************************************************************************************************************************/
181static DECLCALLBACK(int) dbgDiggerFreeBsdInit(PUVM pUVM, void *pvData);
182
183
184/*********************************************************************************************************************************
185* Global Variables *
186*********************************************************************************************************************************/
187/** Table of common FreeBSD kernel addresses. */
188static uint64_t g_au64FreeBsdKernelAddresses[] =
189{
190 UINT64_C(0xc0100000),
191 UINT64_C(0xffffffff80100000)
192};
193/** Magic string which resides in the .interp section of the image. */
194static const uint8_t g_abNeedleInterp[] = "/red/herring";
195
196
197/**
198 * Load the symbols from the .dynsym and .dynstr sections given
199 * by their address in guest memory.
200 *
201 * @returns VBox status code.
202 * @param pThis The instance data.
203 * @param pUVM The user mode VM handle.
204 * @param pszName The image name.
205 * @param uKernelStart The kernel start address.
206 * @param cbKernel Size of the kernel image.
207 * @param pAddrDynsym Start address of the .dynsym section.
208 * @param cSymbols Number of symbols in the .dynsym section.
209 * @param pAddrDynstr Start address of the .dynstr section containing the symbol names.
210 * @param cbDynstr Size of the .dynstr section.
211 */
212static int dbgDiggerFreeBsdLoadSymbols(PDBGDIGGERFBSD pThis, PUVM pUVM, const char *pszName, RTGCUINTPTR uKernelStart,
213 size_t cbKernel, PDBGFADDRESS pAddrDynsym, uint32_t cSymbols, PDBGFADDRESS pAddrDynstr,
214 size_t cbDynstr)
215{
216 LogFlowFunc(("pThis=%#p pszName=%s uKernelStart=%RGv cbKernel=%zu pAddrDynsym=%#p{%RGv} cSymbols=%u pAddrDynstr=%#p{%RGv} cbDynstr=%zu\n",
217 pThis, pszName, uKernelStart, cbKernel, pAddrDynsym, pAddrDynsym->FlatPtr, cSymbols, pAddrDynstr, pAddrDynstr->FlatPtr, cbDynstr));
218
219 char *pbDynstr = (char *)RTMemAllocZ(cbDynstr);
220 int rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, pAddrDynstr, pbDynstr, cbDynstr);
221 if (RT_SUCCESS(rc))
222 {
223 uint32_t cbDynsymEnt = pThis->f64Bit ? sizeof(Elf64_Sym) : sizeof(Elf32_Sym);
224 uint8_t *pbDynsym = (uint8_t *)RTMemAllocZ(cSymbols * cbDynsymEnt);
225 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, pAddrDynsym, pbDynsym, cSymbols * cbDynsymEnt);
226 if (RT_SUCCESS(rc))
227 {
228 /*
229 * Create a module for the kernel.
230 */
231 RTDBGMOD hMod;
232 rc = RTDbgModCreate(&hMod, pszName, cbKernel, 0 /*fFlags*/);
233 if (RT_SUCCESS(rc))
234 {
235 rc = RTDbgModSetTag(hMod, DIG_FBSD_MOD_TAG); AssertRC(rc);
236 rc = VINF_SUCCESS;
237
238 /*
239 * Enumerate the symbols.
240 */
241 uint32_t cLeft = cSymbols;
242 while (cLeft-- > 0 && RT_SUCCESS(rc))
243 {
244 PCELFSYMS pSym = (PCELFSYMS)&pbDynsym[cLeft * cbDynsymEnt];
245 uint32_t idxSymStr = FBSD_UNION(pThis, pSym, st_name);
246 uint8_t uType = FBSD_UNION(pThis, pSym, st_info);
247 RTGCUINTPTR AddrVal = FBSD_UNION(pThis, pSym, st_value);
248 size_t cbSymVal = FBSD_UNION(pThis, pSym, st_size);
249
250 /* Add it without the type char. */
251 RT_NOREF(uType);
252 if (AddrVal <= uKernelStart + cbKernel)
253 {
254 rc = RTDbgModSymbolAdd(hMod, &pbDynstr[idxSymStr], RTDBGSEGIDX_RVA, AddrVal - uKernelStart,
255 cbSymVal, 0 /*fFlags*/, NULL);
256 if (RT_FAILURE(rc))
257 {
258 if ( rc == VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE
259 || rc == VERR_DBG_INVALID_RVA
260 || rc == VERR_DBG_ADDRESS_CONFLICT
261 || rc == VERR_DBG_DUPLICATE_SYMBOL)
262 {
263 Log2(("dbgDiggerFreeBsdLoadSymbols: RTDbgModSymbolAdd(,%s,) failed %Rrc (ignored)\n",
264 &pbDynstr[idxSymStr], rc));
265 rc = VINF_SUCCESS;
266 }
267 else
268 Log(("dbgDiggerFreeBsdLoadSymbols: RTDbgModSymbolAdd(,%s,) failed %Rrc\n",
269 &pbDynstr[idxSymStr], rc));
270 }
271 }
272 }
273
274 /*
275 * Link the module into the address space.
276 */
277 if (RT_SUCCESS(rc))
278 {
279 RTDBGAS hAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL);
280 if (hAs != NIL_RTDBGAS)
281 rc = RTDbgAsModuleLink(hAs, hMod, uKernelStart, RTDBGASLINK_FLAGS_REPLACE);
282 else
283 rc = VERR_INTERNAL_ERROR;
284 RTDbgAsRelease(hAs);
285 }
286 else
287 Log(("dbgDiggerFreeBsdLoadSymbols: Failed: %Rrc\n", rc));
288 RTDbgModRelease(hMod);
289 }
290 else
291 Log(("dbgDiggerFreeBsdLoadSymbols: RTDbgModCreate failed: %Rrc\n", rc));
292 }
293 else
294 Log(("dbgDiggerFreeBsdLoadSymbols: Reading symbol table at %RGv failed: %Rrc\n",
295 pAddrDynsym->FlatPtr, rc));
296 RTMemFree(pbDynsym);
297 }
298 else
299 Log(("dbgDiggerFreeBsdLoadSymbols: Reading symbol string table at %RGv failed: %Rrc\n",
300 pAddrDynstr->FlatPtr, rc));
301 RTMemFree(pbDynstr);
302
303 LogFlowFunc(("returns %Rrc\n", rc));
304 return rc;
305}
306
307/**
308 * Process the kernel image.
309 *
310 * @param pThis The instance data.
311 * @param pUVM The user mode VM handle.
312 * @param pszName The image name.
313 */
314static void dbgDiggerFreeBsdProcessKernelImage(PDBGDIGGERFBSD pThis, PUVM pUVM, const char *pszName)
315{
316 /*
317 * FreeBSD has parts of the kernel ELF image in guest memory, starting with the
318 * ELF header and the content of the sections which are indicated to be loaded
319 * into memory (text, rodata, etc.) of course. Whats missing are the section headers
320 * which is understandable but unfortunate because it would make our life easier.
321 *
322 * All checked FreeBSD kernels so far have the following layout in the kernel:
323 * [.interp] - contiains the /red/herring string we used for probing earlier
324 * [.hash] - contains the hashes of the symbol names, 8 byte alignment on 64bit, 4 byte on 32bit
325 * [.dynsym] - contains the ELF symbol descriptors, 8 byte alignment, 4 byte on 32bit
326 * [.dynstr] - contains the symbol names as a string table, 1 byte alignmnt
327 * [.text] - contains the executable code, 16 byte alignment.
328 * The sections are always adjacent (sans alignment) so we just parse the .hash section right after
329 * .interp, ELF states that it can contain 32bit or 64bit words but all observed kernels
330 * always use 32bit words. It contains two counters at the beginning which we can use to
331 * deduct the .hash section size and the beginning of .dynsym.
332 * .dynsym contains an array of symbol descriptors which have a fixed size depending on the
333 * guest bitness.
334 * Finding the end of .dynsym is not easily doable as there is no counter available (it lives
335 * in the section headers) at this point so we just have to check whether the record is valid
336 * and if not check if it contains an ASCII string which marks the start of the .dynstr section.
337 */
338
339 /* Calculate the start of the .hash section. */
340 DBGFADDRESS AddrHashStart = pThis->AddrKernelInterp;
341 DBGFR3AddrAdd(&AddrHashStart, sizeof(g_abNeedleInterp));
342 AddrHashStart.FlatPtr = RT_ALIGN_GCPT(AddrHashStart.FlatPtr, pThis->f64Bit ? 8 : 4, RTGCUINTPTR);
343 uint32_t au32Counters[2];
344 int rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &AddrHashStart, &au32Counters[0], sizeof(au32Counters));
345 if (RT_SUCCESS(rc))
346 {
347 size_t cbHash = (au32Counters[0] + au32Counters[1] + 2) * sizeof(uint32_t);
348 if (AddrHashStart.FlatPtr + cbHash < pThis->AddrKernelText.FlatPtr) /* Should be much smaller */
349 {
350 DBGFADDRESS AddrDynsymStart = AddrHashStart;
351 uint32_t cSymbols = 0;
352 size_t cbKernel = 0;
353 RTGCUINTPTR uKernelStart = pThis->AddrKernelElfStart.FlatPtr;
354
355 DBGFR3AddrAdd(&AddrDynsymStart, cbHash);
356 AddrDynsymStart.FlatPtr = RT_ALIGN_GCPT(AddrDynsymStart.FlatPtr, pThis->f64Bit ? 8 : 4, RTGCUINTPTR);
357
358 DBGFADDRESS AddrDynstrStart = AddrDynsymStart;
359 while (AddrDynstrStart.FlatPtr < pThis->AddrKernelText.FlatPtr)
360 {
361 size_t cbDynSymEnt = pThis->f64Bit ? sizeof(Elf64_Sym) : sizeof(Elf32_Sym);
362 uint8_t abBuf[_16K];
363 size_t cbToRead = RT_MIN(sizeof(abBuf), pThis->AddrKernelText.FlatPtr - AddrDynstrStart.FlatPtr);
364
365 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &AddrDynstrStart, &abBuf[0], cbToRead);
366 if (RT_FAILURE(rc))
367 break;
368
369 for (unsigned i = 0; i < cbToRead / cbDynSymEnt; i++)
370 {
371 PCELFSYMS pSym = (PCELFSYMS)&abBuf[i * cbDynSymEnt];
372 uint32_t idxSymStr = FBSD_UNION(pThis, pSym, st_name);
373 uint8_t uType = FBSD_UNION(pThis, pSym, st_info);
374 RTGCUINTPTR AddrVal = FBSD_UNION(pThis, pSym, st_value);
375 size_t cbSymVal = FBSD_UNION(pThis, pSym, st_size);
376
377 /*
378 * If the entry doesn't look valid check whether it contains an ASCII string,
379 * we then found the start of the .dynstr section.
380 */
381 RT_NOREF(uType);
382 if ( ELF32_ST_TYPE(uType) != STT_NOTYPE
383 && ( !FBSD_VALID_ADDRESS(pThis, AddrVal)
384 || cbSymVal > FBSD_MAX_KERNEL_SIZE
385 || idxSymStr > pThis->AddrKernelText.FlatPtr - AddrDynstrStart.FlatPtr))
386 {
387 LogFlowFunc(("Invalid symbol table entry found at %RGv\n",
388 AddrDynstrStart.FlatPtr + i * cbDynSymEnt));
389
390 uint8_t *pbBuf = &abBuf[i * cbDynSymEnt];
391 size_t cbLeft = cbToRead - i * cbDynSymEnt;
392 /*
393 * Check to the end of the buffer whether it contains only a certain set of
394 * ASCII characters and 0 terminators.
395 */
396 while ( cbLeft > 0
397 && ( RT_C_IS_ALNUM(*pbBuf)
398 || *pbBuf == '_'
399 || *pbBuf == '\0'
400 || *pbBuf == '.'))
401 {
402 cbLeft--;
403 pbBuf++;
404 }
405
406 if (!cbLeft)
407 {
408 DBGFR3AddrAdd(&AddrDynstrStart, i * cbDynSymEnt);
409 LogFlowFunc(("Found all required section start addresses (.dynsym=%RGv cSymbols=%u, .dynstr=%RGv cb=%u)\n",
410 AddrDynsymStart.FlatPtr, cSymbols, AddrDynstrStart.FlatPtr,
411 pThis->AddrKernelText.FlatPtr - AddrDynstrStart.FlatPtr));
412 dbgDiggerFreeBsdLoadSymbols(pThis, pUVM, pszName, uKernelStart, cbKernel, &AddrDynsymStart, cSymbols, &AddrDynstrStart,
413 pThis->AddrKernelText.FlatPtr - AddrDynstrStart.FlatPtr);
414 return;
415 }
416 else
417 LogFlowFunc(("Found invalid ASCII character in .dynstr section candidate: %#x\n", *pbBuf));
418 }
419 else
420 {
421 cSymbols++;
422 if ( ELF32_ST_TYPE(uType) != STT_NOTYPE
423 && FBSD_VALID_ADDRESS(pThis, AddrVal))
424 {
425 uKernelStart = RT_MIN(uKernelStart, AddrVal);
426 cbKernel = RT_MAX(cbKernel, AddrVal + cbSymVal - uKernelStart);
427 }
428 }
429 }
430
431 /* Don't account incomplete entries. */
432 DBGFR3AddrAdd(&AddrDynstrStart, (cbToRead / cbDynSymEnt) * cbDynSymEnt);
433 }
434 }
435 else
436 LogFlowFunc((".hash section overlaps with .text section: %zu (expected much less than %u)\n", cbHash,
437 pThis->AddrKernelText.FlatPtr - AddrHashStart.FlatPtr));
438 }
439}
440
441
442/**
443 * @interface_method_impl{DBGFOSIDMESG,pfnQueryKernelLog}
444 */
445static DECLCALLBACK(int) dbgDiggerFreeBsdIDmsg_QueryKernelLog(PDBGFOSIDMESG pThis, PUVM pUVM, uint32_t fFlags, uint32_t cMessages,
446 char *pszBuf, size_t cbBuf, size_t *pcbActual)
447{
448 RT_NOREF1(fFlags);
449 PDBGDIGGERFBSD pData = RT_FROM_MEMBER(pThis, DBGDIGGERFBSD, IDmesg);
450
451 if (cMessages < 1)
452 return VERR_INVALID_PARAMETER;
453
454 /* Resolve the message buffer address from the msgbufp symbol. */
455 RTDBGSYMBOL SymInfo;
456 int rc = DBGFR3AsSymbolByName(pUVM, DBGF_AS_KERNEL, "kernel!msgbufp", &SymInfo, NULL);
457 if (RT_SUCCESS(rc))
458 {
459 DBGFADDRESS AddrMsgBuf;
460
461 /* Read the message buffer pointer. */
462 RTGCPTR GCPtrMsgBufP = 0;
463 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &AddrMsgBuf, SymInfo.Value),
464 &GCPtrMsgBufP, pData->f64Bit ? sizeof(uint64_t) : sizeof(uint32_t));
465 if (RT_FAILURE(rc))
466 {
467 Log(("dbgDiggerFreeBsdIDmsg_QueryKernelLog: failed to read msgbufp at %RGv: %Rrc\n", AddrMsgBuf.FlatPtr, rc));
468 return VERR_NOT_FOUND;
469 }
470 if (!FBSD_VALID_ADDRESS(pData, GCPtrMsgBufP))
471 {
472 Log(("dbgDiggerFreeBsdIDmsg_QueryKernelLog: Invalid address for msgbufp: %RGv\n", GCPtrMsgBufP));
473 return VERR_NOT_FOUND;
474 }
475
476 /* Read the structure. */
477 FBSDMSGBUF MsgBuf;
478 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &AddrMsgBuf, GCPtrMsgBufP),
479 &MsgBuf, sizeof(MsgBuf));
480 if (RT_SUCCESS(rc))
481 {
482 RTGCUINTPTR AddrBuf = FBSD_UNION(pData, &MsgBuf, msg_ptr);
483 uint32_t cbMsgBuf = FBSD_UNION(pData, &MsgBuf, msg_size);
484 uint32_t uMsgBufSeqR = FBSD_UNION(pData, &MsgBuf, msg_rseq);
485 uint32_t uMsgBufSeqW = FBSD_UNION(pData, &MsgBuf, msg_wseq);
486
487 /*
488 * Validate the structure.
489 */
490 if ( FBSD_UNION(pData, &MsgBuf, msg_magic) != FBSD_MSGBUF_MAGIC
491 || cbMsgBuf < UINT32_C(4096)
492 || cbMsgBuf > 16*_1M
493 || FBSD_UNION(pData, &MsgBuf, msg_rseq) > cbMsgBuf
494 || FBSD_UNION(pData, &MsgBuf, msg_wseq) > cbMsgBuf
495 || !FBSD_VALID_ADDRESS(pData, AddrBuf) )
496 {
497 Log(("dbgDiggerFreeBsdIDmsg_QueryKernelLog: Invalid MsgBuf data: msg_magic=%#x msg_size=%#x msg_rseq=%#x msg_wseq=%#x msg_ptr=%RGv\n",
498 FBSD_UNION(pData, &MsgBuf, msg_magic), cbMsgBuf, uMsgBufSeqR, uMsgBufSeqW, AddrBuf));
499 return VERR_INVALID_STATE;
500 }
501
502 /*
503 * Read the buffer.
504 */
505 char *pchMsgBuf = (char *)RTMemAlloc(cbMsgBuf);
506 if (!pchMsgBuf)
507 {
508 Log(("dbgDiggerFreeBsdIDmsg_QueryKernelLog: Failed to allocate %#x bytes of memory for the log buffer\n",
509 cbMsgBuf));
510 return VERR_INVALID_STATE;
511 }
512 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &AddrMsgBuf, AddrBuf), pchMsgBuf, cbMsgBuf);
513 if (RT_SUCCESS(rc))
514 {
515 /*
516 * Copy it out raw.
517 */
518 uint32_t offDst = 0;
519 if (uMsgBufSeqR < uMsgBufSeqW)
520 {
521 /* Single chunk between the read and write offsets. */
522 uint32_t cbToCopy = uMsgBufSeqW - uMsgBufSeqR;
523 if (cbToCopy < cbBuf)
524 {
525 memcpy(pszBuf, &pchMsgBuf[uMsgBufSeqR], cbToCopy);
526 pszBuf[cbToCopy] = '\0';
527 rc = VINF_SUCCESS;
528 }
529 else
530 {
531 if (cbBuf)
532 {
533 memcpy(pszBuf, &pchMsgBuf[uMsgBufSeqR], cbBuf - 1);
534 pszBuf[cbBuf - 1] = '\0';
535 }
536 rc = VERR_BUFFER_OVERFLOW;
537 }
538 offDst = cbToCopy + 1;
539 }
540 else
541 {
542 /* Two chunks, read offset to end, start to write offset. */
543 uint32_t cbFirst = cbMsgBuf - uMsgBufSeqR;
544 uint32_t cbSecond = uMsgBufSeqW;
545 if (cbFirst + cbSecond < cbBuf)
546 {
547 memcpy(pszBuf, &pchMsgBuf[uMsgBufSeqR], cbFirst);
548 memcpy(&pszBuf[cbFirst], pchMsgBuf, cbSecond);
549 offDst = cbFirst + cbSecond;
550 pszBuf[offDst++] = '\0';
551 rc = VINF_SUCCESS;
552 }
553 else
554 {
555 offDst = cbFirst + cbSecond + 1;
556 if (cbFirst < cbBuf)
557 {
558 memcpy(pszBuf, &pchMsgBuf[uMsgBufSeqR], cbFirst);
559 memcpy(&pszBuf[cbFirst], pchMsgBuf, cbBuf - cbFirst);
560 pszBuf[cbBuf - 1] = '\0';
561 }
562 else if (cbBuf)
563 {
564 memcpy(pszBuf, &pchMsgBuf[uMsgBufSeqR], cbBuf - 1);
565 pszBuf[cbBuf - 1] = '\0';
566 }
567 rc = VERR_BUFFER_OVERFLOW;
568 }
569 }
570
571 if (pcbActual)
572 *pcbActual = offDst;
573 }
574 else
575 Log(("dbgDiggerFreeBsdIDmsg_QueryKernelLog: Error reading %#x bytes at %RGv: %Rrc\n", cbBuf, AddrBuf, rc));
576 RTMemFree(pchMsgBuf);
577 }
578 else
579 LogFlowFunc(("Failed to read message buffer header: %Rrc\n", rc));
580 }
581
582 return rc;
583}
584
585
586/**
587 * @copydoc DBGFOSREG::pfnQueryInterface
588 */
589static DECLCALLBACK(void *) dbgDiggerFreeBsdQueryInterface(PUVM pUVM, void *pvData, DBGFOSINTERFACE enmIf)
590{
591 RT_NOREF1(pUVM);
592 PDBGDIGGERFBSD pThis = (PDBGDIGGERFBSD)pvData;
593 switch (enmIf)
594 {
595 case DBGFOSINTERFACE_DMESG:
596 return &pThis->IDmesg;
597
598 default:
599 return NULL;
600 }
601}
602
603
604/**
605 * @copydoc DBGFOSREG::pfnQueryVersion
606 */
607static DECLCALLBACK(int) dbgDiggerFreeBsdQueryVersion(PUVM pUVM, void *pvData, char *pszVersion, size_t cchVersion)
608{
609 PDBGDIGGERFBSD pThis = (PDBGDIGGERFBSD)pvData;
610 Assert(pThis->fValid); RT_NOREF(pThis);
611
612 RTDBGSYMBOL SymInfo;
613 int rc = DBGFR3AsSymbolByName(pUVM, DBGF_AS_KERNEL, "kernel!version", &SymInfo, NULL);
614 if (RT_SUCCESS(rc))
615 {
616 DBGFADDRESS AddrVersion;
617 DBGFR3AddrFromFlat(pUVM, &AddrVersion, SymInfo.Value);
618
619 rc = DBGFR3MemReadString(pUVM, 0, &AddrVersion, pszVersion, cchVersion);
620 if (RT_SUCCESS(rc))
621 {
622 char *pszEnd = RTStrEnd(pszVersion, cchVersion);
623 AssertReturn(pszEnd, VERR_BUFFER_OVERFLOW);
624 while ( pszEnd > pszVersion
625 && RT_C_IS_SPACE(pszEnd[-1]))
626 pszEnd--;
627 *pszEnd = '\0';
628 }
629 else
630 RTStrPrintf(pszVersion, cchVersion, "DBGFR3MemReadString -> %Rrc", rc);
631 }
632
633 return rc;
634}
635
636
637
638/**
639 * @copydoc DBGFOSREG::pfnTerm
640 */
641static DECLCALLBACK(void) dbgDiggerFreeBsdTerm(PUVM pUVM, void *pvData)
642{
643 RT_NOREF1(pUVM);
644 PDBGDIGGERFBSD pThis = (PDBGDIGGERFBSD)pvData;
645 Assert(pThis->fValid);
646
647 RT_NOREF1(pUVM);
648
649 pThis->fValid = false;
650}
651
652
653/**
654 * @copydoc DBGFOSREG::pfnRefresh
655 */
656static DECLCALLBACK(int) dbgDiggerFreeBsdRefresh(PUVM pUVM, void *pvData)
657{
658 PDBGDIGGERFBSD pThis = (PDBGDIGGERFBSD)pvData;
659 NOREF(pThis);
660 Assert(pThis->fValid);
661
662 dbgDiggerFreeBsdTerm(pUVM, pvData);
663 return dbgDiggerFreeBsdInit(pUVM, pvData);
664}
665
666
667/**
668 * @copydoc DBGFOSREG::pfnInit
669 */
670static DECLCALLBACK(int) dbgDiggerFreeBsdInit(PUVM pUVM, void *pvData)
671{
672 PDBGDIGGERFBSD pThis = (PDBGDIGGERFBSD)pvData;
673 Assert(!pThis->fValid);
674
675 RT_NOREF1(pUVM);
676
677 dbgDiggerFreeBsdProcessKernelImage(pThis, pUVM, "kernel");
678 pThis->fValid = true;
679 return VINF_SUCCESS;
680}
681
682
683/**
684 * @copydoc DBGFOSREG::pfnProbe
685 */
686static DECLCALLBACK(bool) dbgDiggerFreeBsdProbe(PUVM pUVM, void *pvData)
687{
688 PDBGDIGGERFBSD pThis = (PDBGDIGGERFBSD)pvData;
689
690 /*
691 * Look for the magic ELF header near the known start addresses.
692 * If one is found look for the magic "/red/herring" string which is in the
693 * "interp" section not far away and then validate the start of the ELF header
694 * to be sure.
695 */
696 for (unsigned i = 0; i < RT_ELEMENTS(g_au64FreeBsdKernelAddresses); i++)
697 {
698 static const uint8_t s_abNeedle[] = ELFMAG;
699 DBGFADDRESS KernelAddr;
700 DBGFR3AddrFromFlat(pUVM, &KernelAddr, g_au64FreeBsdKernelAddresses[i]);
701 DBGFADDRESS HitAddr;
702 uint32_t cbLeft = FBSD_MAX_KERNEL_SIZE;
703
704 while (cbLeft > X86_PAGE_4K_SIZE)
705 {
706 int rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &KernelAddr, cbLeft, 1,
707 s_abNeedle, sizeof(s_abNeedle) - 1, &HitAddr);
708 if (RT_FAILURE(rc))
709 break;
710
711 /*
712 * Look for the magic "/red/herring" near the header and verify the basic
713 * ELF header.
714 */
715 DBGFADDRESS HitAddrInterp;
716 rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &HitAddr, FBSD_MAX_INTERP_OFFSET, 1,
717 g_abNeedleInterp, sizeof(g_abNeedleInterp), &HitAddrInterp);
718 if (RT_SUCCESS(rc))
719 {
720 union
721 {
722 uint8_t ab[2 * X86_PAGE_4K_SIZE];
723 Elf32_Ehdr Hdr32;
724 Elf64_Ehdr Hdr64;
725 } ElfHdr;
726 AssertCompileMembersSameSizeAndOffset(Elf64_Ehdr, e_ident, Elf32_Ehdr, e_ident);
727 AssertCompileMembersSameSizeAndOffset(Elf64_Ehdr, e_type, Elf32_Ehdr, e_type);
728 AssertCompileMembersSameSizeAndOffset(Elf64_Ehdr, e_machine, Elf32_Ehdr, e_machine);
729 AssertCompileMembersSameSizeAndOffset(Elf64_Ehdr, e_version, Elf32_Ehdr, e_version);
730
731 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &HitAddr, &ElfHdr.ab[0], X86_PAGE_4K_SIZE);
732 if (RT_SUCCESS(rc))
733 {
734 /* We verified the magic above already by scanning for it. */
735 if ( ( ElfHdr.Hdr32.e_ident[EI_CLASS] == ELFCLASS32
736 || ElfHdr.Hdr32.e_ident[EI_CLASS] == ELFCLASS64)
737 && ElfHdr.Hdr32.e_ident[EI_DATA] == ELFDATA2LSB
738 && ElfHdr.Hdr32.e_ident[EI_VERSION] == EV_CURRENT
739 && ElfHdr.Hdr32.e_ident[EI_OSABI] == ELFOSABI_FREEBSD
740 && ElfHdr.Hdr32.e_type == ET_EXEC
741 && ( ElfHdr.Hdr32.e_machine == EM_386
742 || ElfHdr.Hdr32.e_machine == EM_X86_64)
743 && ElfHdr.Hdr32.e_version == EV_CURRENT)
744 {
745 pThis->f64Bit = ElfHdr.Hdr32.e_ident[EI_CLASS] == ELFCLASS64;
746 pThis->AddrKernelElfStart = HitAddr;
747 pThis->AddrKernelInterp = HitAddrInterp;
748 pThis->AddrKernelText.FlatPtr = FBSD_UNION(pThis, &ElfHdr, e_entry);
749 LogFunc(("Found %s FreeBSD kernel at %RGv (.interp section at %RGv, .text section at %RGv)\n",
750 pThis->f64Bit ? "amd64" : "i386", pThis->AddrKernelElfStart.FlatPtr,
751 pThis->AddrKernelInterp.FlatPtr, pThis->AddrKernelText.FlatPtr));
752 return true;
753 }
754 }
755 }
756
757 /*
758 * Advance.
759 */
760 RTGCUINTPTR cbDistance = HitAddr.FlatPtr - KernelAddr.FlatPtr + sizeof(s_abNeedle) - 1;
761 if (RT_UNLIKELY(cbDistance >= cbLeft))
762 break;
763
764 cbLeft -= cbDistance;
765 DBGFR3AddrAdd(&KernelAddr, cbDistance);
766 }
767 }
768 return false;
769}
770
771
772/**
773 * @copydoc DBGFOSREG::pfnDestruct
774 */
775static DECLCALLBACK(void) dbgDiggerFreeBsdDestruct(PUVM pUVM, void *pvData)
776{
777 RT_NOREF2(pUVM, pvData);
778}
779
780
781/**
782 * @copydoc DBGFOSREG::pfnConstruct
783 */
784static DECLCALLBACK(int) dbgDiggerFreeBsdConstruct(PUVM pUVM, void *pvData)
785{
786 RT_NOREF1(pUVM);
787 PDBGDIGGERFBSD pThis = (PDBGDIGGERFBSD)pvData;
788
789 pThis->fValid = false;
790 pThis->f64Bit = false;
791 pThis->IDmesg.u32Magic = DBGFOSIDMESG_MAGIC;
792 pThis->IDmesg.pfnQueryKernelLog = dbgDiggerFreeBsdIDmsg_QueryKernelLog;
793 pThis->IDmesg.u32EndMagic = DBGFOSIDMESG_MAGIC;
794
795 return VINF_SUCCESS;
796}
797
798
799const DBGFOSREG g_DBGDiggerFreeBsd =
800{
801 /* .u32Magic = */ DBGFOSREG_MAGIC,
802 /* .fFlags = */ 0,
803 /* .cbData = */ sizeof(DBGDIGGERFBSD),
804 /* .szName = */ "FreeBSD",
805 /* .pfnConstruct = */ dbgDiggerFreeBsdConstruct,
806 /* .pfnDestruct = */ dbgDiggerFreeBsdDestruct,
807 /* .pfnProbe = */ dbgDiggerFreeBsdProbe,
808 /* .pfnInit = */ dbgDiggerFreeBsdInit,
809 /* .pfnRefresh = */ dbgDiggerFreeBsdRefresh,
810 /* .pfnTerm = */ dbgDiggerFreeBsdTerm,
811 /* .pfnQueryVersion = */ dbgDiggerFreeBsdQueryVersion,
812 /* .pfnQueryInterface = */ dbgDiggerFreeBsdQueryInterface,
813 /* .u32EndMagic = */ DBGFOSREG_MAGIC
814};
815
Note: See TracBrowser for help on using the repository browser.

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