VirtualBox

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

Last change on this file since 73768 was 73460, checked in by vboxsync, 6 years ago

IPRT,DBGF,Diggers: Moved DBGFRETURNTYPE and the unwind state structure to IPRT (dbg.h) in prep for debug module interface and more. Added stack unwind assist callback for the OS diggers so they can identify special stack frames and supply more info via the sure-register-value array and frame flags. Identify and decode NT/AMD64 trap frames.

  • 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 73460 2018-08-02 21:06:59Z 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::pfnStackUnwindAssist
588 */
589static DECLCALLBACK(int) dbgDiggerFreeBsdStackUnwindAssist(PUVM pUVM, void *pvData, VMCPUID idCpu, PDBGFSTACKFRAME pFrame,
590 PRTDBGUNWINDSTATE pState, PCCPUMCTX pInitialCtx, RTDBGAS hAs,
591 uint64_t *puScratch)
592{
593 RT_NOREF(pUVM, pvData, idCpu, pFrame, pState, pInitialCtx, hAs, puScratch);
594 return VINF_SUCCESS;
595}
596
597
598/**
599 * @copydoc DBGFOSREG::pfnQueryInterface
600 */
601static DECLCALLBACK(void *) dbgDiggerFreeBsdQueryInterface(PUVM pUVM, void *pvData, DBGFOSINTERFACE enmIf)
602{
603 RT_NOREF1(pUVM);
604 PDBGDIGGERFBSD pThis = (PDBGDIGGERFBSD)pvData;
605 switch (enmIf)
606 {
607 case DBGFOSINTERFACE_DMESG:
608 return &pThis->IDmesg;
609
610 default:
611 return NULL;
612 }
613}
614
615
616/**
617 * @copydoc DBGFOSREG::pfnQueryVersion
618 */
619static DECLCALLBACK(int) dbgDiggerFreeBsdQueryVersion(PUVM pUVM, void *pvData, char *pszVersion, size_t cchVersion)
620{
621 PDBGDIGGERFBSD pThis = (PDBGDIGGERFBSD)pvData;
622 Assert(pThis->fValid); RT_NOREF(pThis);
623
624 RTDBGSYMBOL SymInfo;
625 int rc = DBGFR3AsSymbolByName(pUVM, DBGF_AS_KERNEL, "kernel!version", &SymInfo, NULL);
626 if (RT_SUCCESS(rc))
627 {
628 DBGFADDRESS AddrVersion;
629 DBGFR3AddrFromFlat(pUVM, &AddrVersion, SymInfo.Value);
630
631 rc = DBGFR3MemReadString(pUVM, 0, &AddrVersion, pszVersion, cchVersion);
632 if (RT_SUCCESS(rc))
633 {
634 char *pszEnd = RTStrEnd(pszVersion, cchVersion);
635 AssertReturn(pszEnd, VERR_BUFFER_OVERFLOW);
636 while ( pszEnd > pszVersion
637 && RT_C_IS_SPACE(pszEnd[-1]))
638 pszEnd--;
639 *pszEnd = '\0';
640 }
641 else
642 RTStrPrintf(pszVersion, cchVersion, "DBGFR3MemReadString -> %Rrc", rc);
643 }
644
645 return rc;
646}
647
648
649
650/**
651 * @copydoc DBGFOSREG::pfnTerm
652 */
653static DECLCALLBACK(void) dbgDiggerFreeBsdTerm(PUVM pUVM, void *pvData)
654{
655 RT_NOREF1(pUVM);
656 PDBGDIGGERFBSD pThis = (PDBGDIGGERFBSD)pvData;
657 Assert(pThis->fValid);
658
659 RT_NOREF1(pUVM);
660
661 pThis->fValid = false;
662}
663
664
665/**
666 * @copydoc DBGFOSREG::pfnRefresh
667 */
668static DECLCALLBACK(int) dbgDiggerFreeBsdRefresh(PUVM pUVM, void *pvData)
669{
670 PDBGDIGGERFBSD pThis = (PDBGDIGGERFBSD)pvData;
671 NOREF(pThis);
672 Assert(pThis->fValid);
673
674 dbgDiggerFreeBsdTerm(pUVM, pvData);
675 return dbgDiggerFreeBsdInit(pUVM, pvData);
676}
677
678
679/**
680 * @copydoc DBGFOSREG::pfnInit
681 */
682static DECLCALLBACK(int) dbgDiggerFreeBsdInit(PUVM pUVM, void *pvData)
683{
684 PDBGDIGGERFBSD pThis = (PDBGDIGGERFBSD)pvData;
685 Assert(!pThis->fValid);
686
687 RT_NOREF1(pUVM);
688
689 dbgDiggerFreeBsdProcessKernelImage(pThis, pUVM, "kernel");
690 pThis->fValid = true;
691 return VINF_SUCCESS;
692}
693
694
695/**
696 * @copydoc DBGFOSREG::pfnProbe
697 */
698static DECLCALLBACK(bool) dbgDiggerFreeBsdProbe(PUVM pUVM, void *pvData)
699{
700 PDBGDIGGERFBSD pThis = (PDBGDIGGERFBSD)pvData;
701
702 /*
703 * Look for the magic ELF header near the known start addresses.
704 * If one is found look for the magic "/red/herring" string which is in the
705 * "interp" section not far away and then validate the start of the ELF header
706 * to be sure.
707 */
708 for (unsigned i = 0; i < RT_ELEMENTS(g_au64FreeBsdKernelAddresses); i++)
709 {
710 static const uint8_t s_abNeedle[] = ELFMAG;
711 DBGFADDRESS KernelAddr;
712 DBGFR3AddrFromFlat(pUVM, &KernelAddr, g_au64FreeBsdKernelAddresses[i]);
713 DBGFADDRESS HitAddr;
714 uint32_t cbLeft = FBSD_MAX_KERNEL_SIZE;
715
716 while (cbLeft > X86_PAGE_4K_SIZE)
717 {
718 int rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &KernelAddr, cbLeft, 1,
719 s_abNeedle, sizeof(s_abNeedle) - 1, &HitAddr);
720 if (RT_FAILURE(rc))
721 break;
722
723 /*
724 * Look for the magic "/red/herring" near the header and verify the basic
725 * ELF header.
726 */
727 DBGFADDRESS HitAddrInterp;
728 rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &HitAddr, FBSD_MAX_INTERP_OFFSET, 1,
729 g_abNeedleInterp, sizeof(g_abNeedleInterp), &HitAddrInterp);
730 if (RT_SUCCESS(rc))
731 {
732 union
733 {
734 uint8_t ab[2 * X86_PAGE_4K_SIZE];
735 Elf32_Ehdr Hdr32;
736 Elf64_Ehdr Hdr64;
737 } ElfHdr;
738 AssertCompileMembersSameSizeAndOffset(Elf64_Ehdr, e_ident, Elf32_Ehdr, e_ident);
739 AssertCompileMembersSameSizeAndOffset(Elf64_Ehdr, e_type, Elf32_Ehdr, e_type);
740 AssertCompileMembersSameSizeAndOffset(Elf64_Ehdr, e_machine, Elf32_Ehdr, e_machine);
741 AssertCompileMembersSameSizeAndOffset(Elf64_Ehdr, e_version, Elf32_Ehdr, e_version);
742
743 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &HitAddr, &ElfHdr.ab[0], X86_PAGE_4K_SIZE);
744 if (RT_SUCCESS(rc))
745 {
746 /* We verified the magic above already by scanning for it. */
747 if ( ( ElfHdr.Hdr32.e_ident[EI_CLASS] == ELFCLASS32
748 || ElfHdr.Hdr32.e_ident[EI_CLASS] == ELFCLASS64)
749 && ElfHdr.Hdr32.e_ident[EI_DATA] == ELFDATA2LSB
750 && ElfHdr.Hdr32.e_ident[EI_VERSION] == EV_CURRENT
751 && ElfHdr.Hdr32.e_ident[EI_OSABI] == ELFOSABI_FREEBSD
752 && ElfHdr.Hdr32.e_type == ET_EXEC
753 && ( ElfHdr.Hdr32.e_machine == EM_386
754 || ElfHdr.Hdr32.e_machine == EM_X86_64)
755 && ElfHdr.Hdr32.e_version == EV_CURRENT)
756 {
757 pThis->f64Bit = ElfHdr.Hdr32.e_ident[EI_CLASS] == ELFCLASS64;
758 pThis->AddrKernelElfStart = HitAddr;
759 pThis->AddrKernelInterp = HitAddrInterp;
760 pThis->AddrKernelText.FlatPtr = FBSD_UNION(pThis, &ElfHdr, e_entry);
761 LogFunc(("Found %s FreeBSD kernel at %RGv (.interp section at %RGv, .text section at %RGv)\n",
762 pThis->f64Bit ? "amd64" : "i386", pThis->AddrKernelElfStart.FlatPtr,
763 pThis->AddrKernelInterp.FlatPtr, pThis->AddrKernelText.FlatPtr));
764 return true;
765 }
766 }
767 }
768
769 /*
770 * Advance.
771 */
772 RTGCUINTPTR cbDistance = HitAddr.FlatPtr - KernelAddr.FlatPtr + sizeof(s_abNeedle) - 1;
773 if (RT_UNLIKELY(cbDistance >= cbLeft))
774 break;
775
776 cbLeft -= cbDistance;
777 DBGFR3AddrAdd(&KernelAddr, cbDistance);
778 }
779 }
780 return false;
781}
782
783
784/**
785 * @copydoc DBGFOSREG::pfnDestruct
786 */
787static DECLCALLBACK(void) dbgDiggerFreeBsdDestruct(PUVM pUVM, void *pvData)
788{
789 RT_NOREF2(pUVM, pvData);
790}
791
792
793/**
794 * @copydoc DBGFOSREG::pfnConstruct
795 */
796static DECLCALLBACK(int) dbgDiggerFreeBsdConstruct(PUVM pUVM, void *pvData)
797{
798 RT_NOREF1(pUVM);
799 PDBGDIGGERFBSD pThis = (PDBGDIGGERFBSD)pvData;
800
801 pThis->fValid = false;
802 pThis->f64Bit = false;
803 pThis->IDmesg.u32Magic = DBGFOSIDMESG_MAGIC;
804 pThis->IDmesg.pfnQueryKernelLog = dbgDiggerFreeBsdIDmsg_QueryKernelLog;
805 pThis->IDmesg.u32EndMagic = DBGFOSIDMESG_MAGIC;
806
807 return VINF_SUCCESS;
808}
809
810
811const DBGFOSREG g_DBGDiggerFreeBsd =
812{
813 /* .u32Magic = */ DBGFOSREG_MAGIC,
814 /* .fFlags = */ 0,
815 /* .cbData = */ sizeof(DBGDIGGERFBSD),
816 /* .szName = */ "FreeBSD",
817 /* .pfnConstruct = */ dbgDiggerFreeBsdConstruct,
818 /* .pfnDestruct = */ dbgDiggerFreeBsdDestruct,
819 /* .pfnProbe = */ dbgDiggerFreeBsdProbe,
820 /* .pfnInit = */ dbgDiggerFreeBsdInit,
821 /* .pfnRefresh = */ dbgDiggerFreeBsdRefresh,
822 /* .pfnTerm = */ dbgDiggerFreeBsdTerm,
823 /* .pfnQueryVersion = */ dbgDiggerFreeBsdQueryVersion,
824 /* .pfnQueryInterface = */ dbgDiggerFreeBsdQueryInterface,
825 /* .pfnStackUnwindAssist = */ dbgDiggerFreeBsdStackUnwindAssist,
826 /* .u32EndMagic = */ DBGFOSREG_MAGIC
827};
828
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use