3 * DBGPlugInOS2 - Debugger and Guest OS Digger Plugin For OS/2.
7 * Copyright (C) 2009-2012 Oracle Corporation
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.
19 /*******************************************************************************
21 *******************************************************************************/
22 #define LOG_GROUP LOG_GROUP_DBGF ///@todo add new log group.
23 #include "DBGPlugIns.h"
24 #include <VBox/vmm/dbgf.h>
26 #include <VBox/param.h>
27 #include <iprt/string.h>
29 #include <iprt/stream.h>
32 /*******************************************************************************
33 * Structures and Typedefs *
34 *******************************************************************************/
36 /** @name Internal OS/2 structures */
41 typedef enum DBGDIGGEROS2VER
43 DBGDIGGEROS2VER_UNKNOWN
,
52 * OS/2 guest OS digger instance data.
54 typedef struct DBGDIGGEROS2
56 /** Whether the information is valid or not.
57 * (For fending off illegal interface method calls.) */
59 /** 32-bit (true) or 16-bit (false) */
62 /** The OS/2 guest version. */
63 DBGDIGGEROS2VER enmVer
;
64 uint8_t OS2MajorVersion
;
65 uint8_t OS2MinorVersion
;
67 /** Guest's Global Info Segment selector. */
71 /** Pointer to the OS/2 guest OS digger instance data. */
72 typedef DBGDIGGEROS2
*PDBGDIGGEROS2
;
75 /*******************************************************************************
76 * Defined Constants And Macros *
77 *******************************************************************************/
78 /** The 'SAS ' signature. */
79 #define DIG_OS2_SAS_SIG RT_MAKE_U32_FROM_U8('S','A','S',' ')
81 /** OS/2Warp on little endian ASCII systems. */
82 #define DIG_OS2_MOD_TAG UINT64_C(0x43532f3257617270)
84 /*******************************************************************************
85 * Internal Functions *
86 *******************************************************************************/
87 static DECLCALLBACK(int) dbgDiggerOS2Init(PVM pVM
, void *pvData
);
90 /*******************************************************************************
92 *******************************************************************************/
96 * Process a PE image found in guest memory.
98 * @param pThis The instance data.
99 * @param pVM The VM handle.
100 * @param pszName The image name.
101 * @param pImageAddr The image address.
102 * @param cbImage The size of the image.
103 * @param pbBuf Scratch buffer containing the first
104 * RT_MIN(cbBuf, cbImage) bytes of the image.
105 * @param cbBuf The scratch buffer size.
107 static void dbgDiggerOS2ProcessImage(PDBGDIGGEROS2 pThis
, PVM pVM
, const char *pszName
,
108 PCDBGFADDRESS pImageAddr
, uint32_t cbImage
,
109 uint8_t *pbBuf
, size_t cbBuf
)
111 LogFlow(("DigOS2: %RGp %#x %s\n", pImageAddr
->FlatPtr
, cbImage
, pszName
));
113 /* To be implemented.*/
118 * @copydoc DBGFOSREG::pfnQueryInterface
120 static DECLCALLBACK(void *) dbgDiggerOS2QueryInterface(PVM pVM
, void *pvData
, DBGFOSINTERFACE enmIf
)
127 * @copydoc DBGFOSREG::pfnQueryVersion
129 static DECLCALLBACK(int) dbgDiggerOS2QueryVersion(PVM pVM
, void *pvData
, char *pszVersion
, size_t cchVersion
)
131 PDBGDIGGEROS2 pThis
= (PDBGDIGGEROS2
)pvData
;
132 Assert(pThis
->fValid
);
133 char *achOS2ProductType
[32];
134 char *pszOS2ProductType
= (char *)achOS2ProductType
;
136 if (pThis
->OS2MajorVersion
== 10)
138 RTStrPrintf(pszOS2ProductType
, sizeof(achOS2ProductType
), "OS/2 1.%02d", pThis
->OS2MinorVersion
);
139 pThis
->enmVer
= DBGDIGGEROS2VER_1_x
;
141 else if (pThis
->OS2MajorVersion
== 20)
143 if (pThis
->OS2MinorVersion
< 30)
145 RTStrPrintf(pszOS2ProductType
, sizeof(achOS2ProductType
), "OS/2 2.%02d", pThis
->OS2MinorVersion
);
146 pThis
->enmVer
= DBGDIGGEROS2VER_2_x
;
148 else if (pThis
->OS2MinorVersion
< 40)
150 RTStrPrintf(pszOS2ProductType
, sizeof(achOS2ProductType
), "OS/2 Warp", pThis
->OS2MinorVersion
);
151 pThis
->enmVer
= DBGDIGGEROS2VER_3_0
;
153 else if (pThis
->OS2MinorVersion
== 40)
155 RTStrPrintf(pszOS2ProductType
, sizeof(achOS2ProductType
), "OS/2 Warp 4", pThis
->OS2MinorVersion
);
156 pThis
->enmVer
= DBGDIGGEROS2VER_4_0
;
160 RTStrPrintf(pszOS2ProductType
, sizeof(achOS2ProductType
), "OS/2 Warp %d.%d",
161 pThis
->OS2MinorVersion
/ 10, pThis
->OS2MinorVersion
% 10);
162 pThis
->enmVer
= DBGDIGGEROS2VER_4_5
;
165 RTStrPrintf(pszVersion
, cchVersion
, "%u.%u (%s)", pThis
->OS2MajorVersion
, pThis
->OS2MinorVersion
, pszOS2ProductType
);
171 * @copydoc DBGFOSREG::pfnTerm
173 static DECLCALLBACK(void) dbgDiggerOS2Term(PVM pVM
, void *pvData
)
175 PDBGDIGGEROS2 pThis
= (PDBGDIGGEROS2
)pvData
;
176 Assert(pThis
->fValid
);
178 pThis
->fValid
= false;
183 * @copydoc DBGFOSREG::pfnRefresh
185 static DECLCALLBACK(int) dbgDiggerOS2Refresh(PVM pVM
, void *pvData
)
187 PDBGDIGGEROS2 pThis
= (PDBGDIGGEROS2
)pvData
;
189 Assert(pThis
->fValid
);
192 * For now we'll flush and reload everything.
194 RTDBGAS hDbgAs
= DBGFR3AsResolveAndRetain(pVM
, DBGF_AS_KERNEL
);
195 if (hDbgAs
!= NIL_RTDBGAS
)
197 uint32_t iMod
= RTDbgAsModuleCount(hDbgAs
);
200 RTDBGMOD hMod
= RTDbgAsModuleByIndex(hDbgAs
, iMod
);
201 if (hMod
!= NIL_RTDBGMOD
)
203 if (RTDbgModGetTag(hMod
) == DIG_OS2_MOD_TAG
)
205 int rc
= RTDbgAsModuleUnlink(hDbgAs
, hMod
);
208 RTDbgModRelease(hMod
);
211 RTDbgAsRelease(hDbgAs
);
214 dbgDiggerOS2Term(pVM
, pvData
);
215 return dbgDiggerOS2Init(pVM
, pvData
);
220 * @copydoc DBGFOSREG::pfnInit
222 static DECLCALLBACK(int) dbgDiggerOS2Init(PVM pVM
, void *pvData
)
224 PDBGDIGGEROS2 pThis
= (PDBGDIGGEROS2
)pvData
;
225 Assert(!pThis
->fValid
);
230 uint16_t au16
[0x2000/2];
231 uint32_t au32
[0x2000/4];
232 RTUTF16 wsz
[0x2000/2];
238 * Determine the OS/2 version.
241 /* Version info is at GIS:15h (major/minor/revision). */
242 rc
= DBGFR3AddrFromSelOff(pVM
, 0 /*idCpu*/, &Addr
, pThis
->selGIS
, 0x15);
245 rc
= DBGFR3MemRead(pVM
, 0 /*idCpu*/, &Addr
, u
.au32
, sizeof(uint32_t));
249 pThis
->OS2MajorVersion
= u
.au8
[0];
250 pThis
->OS2MinorVersion
= u
.au8
[1];
252 pThis
->fValid
= true;
255 return VERR_NOT_SUPPORTED
;
260 * @copydoc DBGFOSREG::pfnProbe
262 static DECLCALLBACK(bool) dbgDiggerOS2Probe(PVM pVM
, void *pvData
)
264 PDBGDIGGEROS2 pThis
= (PDBGDIGGEROS2
)pvData
;
271 uint16_t au16
[8192/2];
272 uint32_t au32
[8192/4];
277 * If the DWORD at 70:0 contains 'SAS ' it's quite unlikely that this wouldn't be OS/2.
278 * Note: The SAS layout is similar between 16-bit and 32-bit OS/2, but not identical.
279 * 32-bit OS/2 will have the flat kernel data selector at SAS:06. The selector is 168h
280 * or similar. For 16-bit OS/2 the field contains a table offset into the SAS which will
281 * be much smaller. Fun fact: The global infoseg selector in the SAS is bimodal in 16-bit
282 * OS/2 and will work in real mode as well.
285 rc
= DBGFR3AddrFromSelOff(pVM
, 0 /*idCpu*/, &Addr
, 0x70, 0x00);
288 rc
= DBGFR3MemRead(pVM
, 0 /*idCpu*/, &Addr
, u
.au32
, 256);
291 if (u
.au32
[0] != DIG_OS2_SAS_SIG
)
294 /* This sure looks like OS/2, but a bit of paranoia won't hurt. */
295 if (u
.au16
[2] >= u
.au16
[4])
298 /* If 4th word is bigger than 5th, it's the flat kernel mode selector. */
299 if (u
.au16
[3] > u
.au16
[4])
300 pThis
->f32Bit
= true;
302 /* Offset into info table is either at SAS:14h or SAS:16h. */
304 offInfo
= u
.au16
[0x14/2];
306 offInfo
= u
.au16
[0x16/2];
308 /* The global infoseg selector is the first entry in the info table. */
309 pThis
->selGIS
= u
.au16
[offInfo
/2];
318 * @copydoc DBGFOSREG::pfnDestruct
320 static DECLCALLBACK(void) dbgDiggerOS2Destruct(PVM pVM
, void *pvData
)
327 * @copydoc DBGFOSREG::pfnConstruct
329 static DECLCALLBACK(int) dbgDiggerOS2Construct(PVM pVM
, void *pvData
)
331 PDBGDIGGEROS2 pThis
= (PDBGDIGGEROS2
)pvData
;
332 pThis
->fValid
= false;
333 pThis
->f32Bit
= false;
334 pThis
->enmVer
= DBGDIGGEROS2VER_UNKNOWN
;
339 const DBGFOSREG g_DBGDiggerOS2
=
341 /* .u32Magic = */ DBGFOSREG_MAGIC
,
343 /* .cbData = */ sizeof(DBGDIGGEROS2
),
344 /* .szName = */ "OS/2",
345 /* .pfnConstruct = */ dbgDiggerOS2Construct
,
346 /* .pfnDestruct = */ dbgDiggerOS2Destruct
,
347 /* .pfnProbe = */ dbgDiggerOS2Probe
,
348 /* .pfnInit = */ dbgDiggerOS2Init
,
349 /* .pfnRefresh = */ dbgDiggerOS2Refresh
,
350 /* .pfnTerm = */ dbgDiggerOS2Term
,
351 /* .pfnQueryVersion = */ dbgDiggerOS2QueryVersion
,
352 /* .pfnQueryInterface = */ dbgDiggerOS2QueryInterface
,
353 /* .u32EndMagic = */ DBGFOSREG_MAGIC