1 | /* $Id: VBoxVideoWinDbg.cpp 31885 2010-08-24 07:22:23Z vboxsync $ */
|
---|
2 | /*
|
---|
3 | * Copyright (C) 2010 Oracle Corporation
|
---|
4 | *
|
---|
5 | * This file is part of VirtualBox Open Source Edition (OSE), as
|
---|
6 | * available from http://www.virtualbox.org. This file is free software;
|
---|
7 | * you can redistribute it and/or modify it under the terms of the GNU
|
---|
8 | * General Public License (GPL) as published by the Free Software
|
---|
9 | * Foundation, in version 2 as it comes in the "COPYING" file of the
|
---|
10 | * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
|
---|
11 | * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
|
---|
12 | */
|
---|
13 | #include <windows.h>
|
---|
14 | #define KDEXT_64BIT
|
---|
15 | #include <wdbgexts.h>
|
---|
16 |
|
---|
17 | #define VBOXVWD_VERSION_MAJOR 1
|
---|
18 | #define VBOXVWD_VERSION_MINOR 1
|
---|
19 |
|
---|
20 | static EXT_API_VERSION g_VBoxVWDVersion = {
|
---|
21 | VBOXVWD_VERSION_MAJOR,
|
---|
22 | VBOXVWD_VERSION_MINOR,
|
---|
23 | EXT_API_VERSION_NUMBER64,
|
---|
24 | 0
|
---|
25 | };
|
---|
26 |
|
---|
27 | /**
|
---|
28 | * DLL entry point.
|
---|
29 | */
|
---|
30 | BOOL WINAPI DllMain(HINSTANCE hInstance,
|
---|
31 | DWORD dwReason,
|
---|
32 | LPVOID lpReserved)
|
---|
33 | {
|
---|
34 | BOOL bOk = TRUE;
|
---|
35 |
|
---|
36 | switch (dwReason)
|
---|
37 | {
|
---|
38 | case DLL_PROCESS_ATTACH:
|
---|
39 | {
|
---|
40 | break;
|
---|
41 | }
|
---|
42 |
|
---|
43 | case DLL_PROCESS_DETACH:
|
---|
44 | {
|
---|
45 | break;
|
---|
46 | }
|
---|
47 |
|
---|
48 | default:
|
---|
49 | break;
|
---|
50 | }
|
---|
51 | return bOk;
|
---|
52 | }
|
---|
53 |
|
---|
54 | /* note: need to name it this way to make dprintf & other macros defined in wdbgexts.h work */
|
---|
55 | WINDBG_EXTENSION_APIS64 ExtensionApis = {0};
|
---|
56 | USHORT SavedMajorVersion;
|
---|
57 | USHORT SavedMinorVersion;
|
---|
58 |
|
---|
59 | #ifdef __cplusplus
|
---|
60 | extern "C"
|
---|
61 | {
|
---|
62 | #endif
|
---|
63 | LPEXT_API_VERSION WDBGAPI ExtensionApiVersion();
|
---|
64 | VOID WDBGAPI CheckVersion();
|
---|
65 | VOID WDBGAPI WinDbgExtensionDllInit(PWINDBG_EXTENSION_APIS64 lpExtensionApis, USHORT MajorVersion, USHORT MinorVersion);
|
---|
66 | #ifdef __cplusplus
|
---|
67 | }
|
---|
68 | #endif
|
---|
69 |
|
---|
70 | LPEXT_API_VERSION WDBGAPI ExtensionApiVersion()
|
---|
71 | {
|
---|
72 | return &g_VBoxVWDVersion;
|
---|
73 | }
|
---|
74 |
|
---|
75 | VOID WDBGAPI CheckVersion()
|
---|
76 | {
|
---|
77 | return;
|
---|
78 | }
|
---|
79 |
|
---|
80 | VOID WDBGAPI WinDbgExtensionDllInit(PWINDBG_EXTENSION_APIS64 lpExtensionApis, USHORT MajorVersion, USHORT MinorVersion)
|
---|
81 | {
|
---|
82 | ExtensionApis = *lpExtensionApis;
|
---|
83 | SavedMajorVersion = MajorVersion;
|
---|
84 | SavedMinorVersion = MinorVersion;
|
---|
85 | }
|
---|
86 |
|
---|
87 | DECLARE_API(help)
|
---|
88 | {
|
---|
89 | dprintf("**** VirtulBox Video Driver debugging extension ****\n"
|
---|
90 | " The following commands are supported: \n"
|
---|
91 | " !ms - save memory (video data) to clipboard \n"
|
---|
92 | " usage: !ms <virtual memory address> <width> <height> [bitsPerPixel (default is 32)] [pitch (default is ((width * bpp + 7) >> 3) + 3) & ~3)]\n");
|
---|
93 | }
|
---|
94 |
|
---|
95 | DECLARE_API(ms)
|
---|
96 | {
|
---|
97 | ULONG64 u64Mem;
|
---|
98 | ULONG64 u64Width;
|
---|
99 | ULONG64 u64Height;
|
---|
100 | ULONG64 u64Bpp = 32;
|
---|
101 | ULONG64 u64Pitch;
|
---|
102 | ULONG64 u64DefaultPitch;
|
---|
103 | PCSTR pExpr = args;
|
---|
104 |
|
---|
105 | if (!pExpr) { dprintf("address not specified\n"); return; }
|
---|
106 | if (!GetExpressionEx(pExpr, &u64Mem, &pExpr)) { dprintf("error evaluating address\n"); return; }
|
---|
107 | if (!u64Mem) { dprintf("address value can not be NULL\n"); return; }
|
---|
108 |
|
---|
109 | if (!pExpr) { dprintf("width not specified\n"); return; }
|
---|
110 | if (!GetExpressionEx(pExpr, &u64Width, &pExpr)) { dprintf("error evaluating width\n"); return; }
|
---|
111 | if (!u64Width) { dprintf("width value can not be NULL\n"); return; }
|
---|
112 |
|
---|
113 | if (!pExpr) { dprintf("height not specified\n"); return; }
|
---|
114 | if (!GetExpressionEx(pExpr, &u64Height, &pExpr)) { dprintf("error evaluating height\n"); return; }
|
---|
115 | if (!u64Height) { dprintf("height value can not be NULL\n"); return; }
|
---|
116 |
|
---|
117 | if (pExpr && GetExpressionEx(pExpr, &u64Bpp, &pExpr))
|
---|
118 | {
|
---|
119 | if (!u64Bpp) { dprintf("bpp value can not be NULL\n"); return; }
|
---|
120 | }
|
---|
121 |
|
---|
122 | u64DefaultPitch = (((((u64Width * u64Bpp) + 7) >> 3) + 3) & ~3ULL);
|
---|
123 | if (pExpr && GetExpressionEx(pExpr, &u64Pitch, &pExpr))
|
---|
124 | {
|
---|
125 | if (u64Pitch < u64DefaultPitch) { dprintf("pitch value can not be less than (%I)\n", u64DefaultPitch); return; }
|
---|
126 | }
|
---|
127 | else
|
---|
128 | {
|
---|
129 | u64Pitch = u64DefaultPitch;
|
---|
130 | }
|
---|
131 |
|
---|
132 | dprintf("processing data for address(0x%p), width(%d), height(%d), bpp(%d), pitch(%d)...\n",
|
---|
133 | u64Mem, (UINT)u64Width, (UINT)u64Height, (UINT)u64Bpp, (UINT)u64Pitch);
|
---|
134 |
|
---|
135 | ULONG64 cbSize = u64DefaultPitch * u64Height;
|
---|
136 | PVOID pvBuf = malloc(cbSize);
|
---|
137 | if (pvBuf)
|
---|
138 | {
|
---|
139 | ULONG uRc = 0;
|
---|
140 | if(u64DefaultPitch == u64Pitch)
|
---|
141 | {
|
---|
142 | ULONG cbRead = 0;
|
---|
143 | dprintf("reading the entire memory buffer...\n");
|
---|
144 | uRc = ReadMemory(u64Mem, pvBuf, cbSize, &cbRead);
|
---|
145 | if (!uRc)
|
---|
146 | {
|
---|
147 | dprintf("Failed to read the memory buffer of size(%I)\n", cbSize);
|
---|
148 | }
|
---|
149 | else if (cbRead != cbSize)
|
---|
150 | {
|
---|
151 | dprintf("the actual number of bytes read(%I) no equal the requested size(%I)\n", cbRead, cbSize);
|
---|
152 | uRc = 0;
|
---|
153 | }
|
---|
154 |
|
---|
155 | }
|
---|
156 | else
|
---|
157 | {
|
---|
158 | ULONG64 u64Offset = u64Mem;
|
---|
159 | char* pvcBuf = (char*)pvBuf;
|
---|
160 | ULONG64 i;
|
---|
161 | dprintf("reading memory by chunks since custom pitch is specified...\n");
|
---|
162 | for (i = 0; i < u64Height; ++i, u64Offset+=u64Pitch, pvcBuf+=u64DefaultPitch)
|
---|
163 | {
|
---|
164 | ULONG cbRead = 0;
|
---|
165 | uRc = ReadMemory(u64Offset, pvcBuf, u64DefaultPitch, &cbRead);
|
---|
166 | if (!uRc)
|
---|
167 | {
|
---|
168 | dprintf("Failed to read the memory buffer of size(%I), chunk(%I)\n", u64DefaultPitch, i);
|
---|
169 | break;
|
---|
170 | }
|
---|
171 | else if (cbRead != u64DefaultPitch)
|
---|
172 | {
|
---|
173 | dprintf("the actual number of bytes read(%I) no equal the requested size(%I), chunk(%I)\n", cbRead, u64DefaultPitch, i);
|
---|
174 | uRc = 0;
|
---|
175 | break;
|
---|
176 | }
|
---|
177 | }
|
---|
178 | }
|
---|
179 |
|
---|
180 | if (uRc)
|
---|
181 | {
|
---|
182 | BITMAP Bmp = {0};
|
---|
183 | HBITMAP hBmp;
|
---|
184 | dprintf("read memory succeeded..\n");
|
---|
185 | Bmp.bmType = 0;
|
---|
186 | Bmp.bmWidth = (LONG)u64Width;
|
---|
187 | Bmp.bmHeight = (LONG)u64Height;
|
---|
188 | Bmp.bmWidthBytes = (LONG)u64DefaultPitch;
|
---|
189 | Bmp.bmPlanes = 1;
|
---|
190 | Bmp.bmBitsPixel = (WORD)u64Bpp;
|
---|
191 | Bmp.bmBits = (LPVOID)pvBuf;
|
---|
192 | hBmp = CreateBitmapIndirect(&Bmp);
|
---|
193 | if (hBmp)
|
---|
194 | {
|
---|
195 | if (OpenClipboard(GetDesktopWindow()))
|
---|
196 | {
|
---|
197 | if (EmptyClipboard())
|
---|
198 | {
|
---|
199 | if (SetClipboardData(CF_BITMAP, hBmp))
|
---|
200 | {
|
---|
201 | dprintf("succeeded!! You can now do <ctrl>+v in your favourite image editor\n");
|
---|
202 | }
|
---|
203 | else
|
---|
204 | {
|
---|
205 | DWORD winEr = GetLastError();
|
---|
206 | dprintf("SetClipboardData failed, err(%I)\n", winEr);
|
---|
207 | }
|
---|
208 | }
|
---|
209 | else
|
---|
210 | {
|
---|
211 | DWORD winEr = GetLastError();
|
---|
212 | dprintf("EmptyClipboard failed, err(%I)\n", winEr);
|
---|
213 | }
|
---|
214 |
|
---|
215 | CloseClipboard();
|
---|
216 | }
|
---|
217 | else
|
---|
218 | {
|
---|
219 | DWORD winEr = GetLastError();
|
---|
220 | dprintf("OpenClipboard failed, err(%I)\n", winEr);
|
---|
221 | }
|
---|
222 |
|
---|
223 | DeleteObject(hBmp);
|
---|
224 | }
|
---|
225 | else
|
---|
226 | {
|
---|
227 | DWORD winEr = GetLastError();
|
---|
228 | dprintf("CreateBitmapIndirect failed, err(%I)\n", winEr);
|
---|
229 | }
|
---|
230 | }
|
---|
231 | else
|
---|
232 | {
|
---|
233 | dprintf("read memory failed\n");
|
---|
234 | }
|
---|
235 | free(pvBuf);
|
---|
236 | }
|
---|
237 | else
|
---|
238 | {
|
---|
239 | dprintf("failed to allocate memory buffer of size(%I)\n", cbSize);
|
---|
240 | }
|
---|
241 | }
|
---|