VirtualBox

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

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

© 2023 Oracle
ContactPrivacy policyTerms of Use