VirtualBox

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

Last change on this file since 67981 was 64532, checked in by vboxsync, 8 years ago

more typos

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

© 2023 Oracle
ContactPrivacy policyTerms of Use