Rizin
unix-like reverse engineering framework and cli tools
io_windbg.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2020 GustavoLCR <gugulcr@gmail.com>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #define INITGUID
5 #include <rz_core.h>
6 #include <DbgEng.h>
7 
8 typedef HRESULT(__stdcall *DebugCreate_t)(
9  _In_ REFIID InterfaceId,
10  _Out_ PVOID *Interface);
11 
12 typedef HRESULT(__stdcall *DebugConnectWide_t)(
13  _In_ PCWSTR RemoteOptions,
14  _In_ REFIID InterfaceId,
15  _Out_ PVOID *Interface);
16 
19 
20 #define WINDBGURI "windbg://"
21 
22 typedef struct { // Keep in sync with debug_windbg.c
23  bool initialized;
24  ULONG64 server;
25  ULONG64 processBase;
26  DWORD lastExecutionStatus;
27  PDEBUG_CLIENT5 dbgClient;
28  PDEBUG_CONTROL4 dbgCtrl;
29  PDEBUG_DATA_SPACES4 dbgData;
30  PDEBUG_REGISTERS2 dbgReg;
31  PDEBUG_SYSTEM_OBJECTS4 dbgSysObj;
32  PDEBUG_SYMBOLS3 dbgSymbols;
33  PDEBUG_ADVANCED3 dbgAdvanced;
35 
36 #define THISCALL(dbginterface, function, ...) dbginterface->lpVtbl->function(dbginterface, __VA_ARGS__)
37 #define ITHISCALL(dbginterface, function, ...) THISCALL(idbg->dbginterface, function, __VA_ARGS__)
38 
39 #define DECLARE_CALLBACKS_IMPL(Type, IFace) \
40  typedef struct IFace##_impl { \
41  IFace *lpVtbl; \
42  DbgEngContext *m_idbg; \
43  LONG m_ref; \
44  } Type##_IMPL, *P##Type##_IMPL;
45 
46 #define INIT_IUNKNOWN_CALLBACKS(IFace, lpVtbl) \
47  lpVtbl->QueryInterface = IFace##_QueryInterface_impl; \
48  lpVtbl->AddRef = IFace##_AddRef_impl; \
49  lpVtbl->Release = IFace##_Release_impl
50 
51 #define DECLARE_NEW(IFace, IVtbl) \
52  static P##IFace IFace##_impl_new( \
53  DbgEngContext *idbg) { \
54  if (!idbg) { \
55  return NULL; \
56  } \
57  P##IFace##_IMPL callbacks = RZ_NEW(IFace##_IMPL); \
58  if (!callbacks) { \
59  return NULL; \
60  } \
61  callbacks->lpVtbl = RZ_NEW(IVtbl); \
62  if (!callbacks->lpVtbl) { \
63  free(callbacks); \
64  return NULL; \
65  } \
66  IFace##_vtbl_init((P##IFace)callbacks); \
67  callbacks->m_idbg = idbg; \
68  callbacks->m_ref = 1; \
69  return (P##IFace)callbacks; \
70  }
71 
72 #define DECLARE_QUERYINTERFACE(IFace, IFaceIID) \
73  static STDMETHODIMP IFace##_QueryInterface_impl( \
74  P##IFace This, \
75  _In_ REFIID InterfaceId, \
76  _Out_ PVOID *Interface) { \
77  *Interface = NULL; \
78  if (IsEqualIID(InterfaceId, &IID_IUnknown) || \
79  IsEqualIID(InterfaceId, &IFaceIID)) { \
80  *Interface = This; \
81  THISCALL(This, AddRef); \
82  return S_OK; \
83  } else { \
84  return E_NOINTERFACE; \
85  } \
86  }
87 
88 #define DECLARE_ADDREF(IFace) \
89  static STDMETHODIMP_(ULONG) IFace##_AddRef_impl( \
90  P##IFace This) { \
91  P##IFace##_IMPL impl = (P##IFace##_IMPL)This; \
92  return InterlockedIncrement(&impl->m_ref); \
93  }
94 
95 #define DECLARE_RELEASE(IFace) \
96  static STDMETHODIMP_(ULONG) IFace##_Release_impl( \
97  P##IFace This) { \
98  P##IFace##_IMPL impl = (P##IFace##_IMPL)This; \
99  LONG ret = InterlockedDecrement(&impl->m_ref); \
100  if (!ret) { \
101  free(This->lpVtbl); \
102  free(This); \
103  } \
104  return ret; \
105  }
106 
107 DECLARE_CALLBACKS_IMPL(DEBUG_EVENT_CALLBACKS, IDebugEventCallbacksVtbl)
108 DECLARE_CALLBACKS_IMPL(DEBUG_INPUT_CALLBACKS, IDebugInputCallbacksVtbl)
109 DECLARE_CALLBACKS_IMPL(DEBUG_OUTPUT_CALLBACKS, IDebugOutputCallbacksVtbl)
110 
111 static STDMETHODIMP __interest_mask(PDEBUG_EVENT_CALLBACKS This, PULONG Mask) {
112  *Mask = DEBUG_EVENT_BREAKPOINT | DEBUG_EVENT_CREATE_PROCESS;
113  *Mask |= DEBUG_EVENT_EXCEPTION | DEBUG_EVENT_SYSTEM_ERROR;
114  *Mask |= DEBUG_EVENT_EXIT_PROCESS;
115  return S_OK;
116 }
117 
118 static STDMETHODIMP __createprocess_cb(
119  PDEBUG_EVENT_CALLBACKS This,
120  ULONG64 ImageFileHandle,
121  ULONG64 Handle,
122  ULONG64 BaseOffset,
123  ULONG ModuleSize,
124  PCSTR ModuleName,
125  PCSTR ImageName,
126  ULONG CheckSum,
127  ULONG TimeDateStamp,
128  ULONG64 InitialThreadHandle,
129  ULONG64 ThreadDataOffset,
130  ULONG64 StartOffset) {
131  PDEBUG_EVENT_CALLBACKS_IMPL impl = (PDEBUG_EVENT_CALLBACKS_IMPL)This;
132  impl->m_idbg->processBase = BaseOffset;
133  return DEBUG_STATUS_BREAK;
134 }
135 
136 static STDMETHODIMP __breakpoint_cb(PDEBUG_EVENT_CALLBACKS This, PDEBUG_BREAKPOINT Bp) {
137  return DEBUG_STATUS_BREAK;
138 }
139 
140 static STDMETHODIMP __exception_cb(PDEBUG_EVENT_CALLBACKS This, PEXCEPTION_RECORD64 Exception, ULONG FirstChance) {
141  return DEBUG_STATUS_BREAK;
142 }
143 
144 static STDMETHODIMP __exit_process_cb(PDEBUG_EVENT_CALLBACKS This, ULONG ExitCode) {
145  return DEBUG_STATUS_BREAK;
146 }
147 
148 static STDMETHODIMP __system_error_cb(PDEBUG_EVENT_CALLBACKS This, ULONG Error, ULONG Level) {
149  return DEBUG_STATUS_BREAK;
150 }
151 
152 static STDMETHODIMP __input_cb(PDEBUG_INPUT_CALLBACKS This, ULONG BufferSize) {
153  char prompt[512];
154  PDEBUG_INPUT_CALLBACKS_IMPL impl = (PDEBUG_INPUT_CALLBACKS_IMPL)This;
155  DbgEngContext *idbg = impl->m_idbg;
156  ITHISCALL(dbgCtrl, GetPromptText, prompt, sizeof(prompt), NULL);
158  const char *str = rz_line_readline();
159  char *ret = rz_str_ndup(str, RZ_MIN(strlen(str), BufferSize));
160  ITHISCALL(dbgCtrl, ReturnInput, ret);
161  return S_OK;
162 }
163 
164 static STDMETHODIMP __input_end_cb(PDEBUG_INPUT_CALLBACKS This) {
165  return S_OK;
166 }
167 
168 static STDMETHODIMP __output_cb(PDEBUG_OUTPUT_CALLBACKS This, ULONG Mask, PCSTR Text) {
169  eprintf("%s", Text);
170  return S_OK;
171 }
172 
173 DECLARE_QUERYINTERFACE(DEBUG_EVENT_CALLBACKS, IID_IDebugEventCallbacks)
174 DECLARE_QUERYINTERFACE(DEBUG_INPUT_CALLBACKS, IID_IDebugInputCallbacks)
175 DECLARE_QUERYINTERFACE(DEBUG_OUTPUT_CALLBACKS, IID_IDebugOutputCallbacks)
176 
177 DECLARE_ADDREF(DEBUG_EVENT_CALLBACKS)
178 DECLARE_ADDREF(DEBUG_INPUT_CALLBACKS)
179 DECLARE_ADDREF(DEBUG_OUTPUT_CALLBACKS)
180 
181 DECLARE_RELEASE(DEBUG_EVENT_CALLBACKS)
182 DECLARE_RELEASE(DEBUG_INPUT_CALLBACKS)
183 DECLARE_RELEASE(DEBUG_OUTPUT_CALLBACKS)
184 
185 static void DEBUG_EVENT_CALLBACKS_vtbl_init(PDEBUG_EVENT_CALLBACKS callbacks) {
186  INIT_IUNKNOWN_CALLBACKS(DEBUG_EVENT_CALLBACKS, callbacks->lpVtbl);
187  callbacks->lpVtbl->GetInterestMask = __interest_mask;
188  callbacks->lpVtbl->Breakpoint = __breakpoint_cb;
189  callbacks->lpVtbl->Exception = __exception_cb;
190  callbacks->lpVtbl->CreateProcess = __createprocess_cb;
191  callbacks->lpVtbl->ExitProcess = __exit_process_cb;
192  callbacks->lpVtbl->SystemError = __system_error_cb;
193 }
194 
195 static void DEBUG_INPUT_CALLBACKS_vtbl_init(PDEBUG_INPUT_CALLBACKS callbacks) {
196  INIT_IUNKNOWN_CALLBACKS(DEBUG_INPUT_CALLBACKS, callbacks->lpVtbl);
197  callbacks->lpVtbl->StartInput = __input_cb;
198  callbacks->lpVtbl->EndInput = __input_end_cb;
199 }
200 
201 static void DEBUG_OUTPUT_CALLBACKS_vtbl_init(PDEBUG_OUTPUT_CALLBACKS callbacks) {
202  INIT_IUNKNOWN_CALLBACKS(DEBUG_OUTPUT_CALLBACKS, callbacks->lpVtbl);
203  callbacks->lpVtbl->Output = __output_cb;
204 }
205 
206 DECLARE_NEW(DEBUG_EVENT_CALLBACKS, IDebugEventCallbacksVtbl)
207 DECLARE_NEW(DEBUG_INPUT_CALLBACKS, IDebugInputCallbacksVtbl)
208 DECLARE_NEW(DEBUG_OUTPUT_CALLBACKS, IDebugOutputCallbacksVtbl)
209 
210 static void __free_context(DbgEngContext *idbg) {
211 #define RELEASE(I) \
212  if (idbg->I) { \
213  ITHISCALL(I, Release); \
214  idbg->I = NULL; \
215  }
216  RELEASE(dbgAdvanced);
217  RELEASE(dbgClient);
218  RELEASE(dbgCtrl);
219  RELEASE(dbgData);
220  RELEASE(dbgReg);
221  RELEASE(dbgSymbols);
222  RELEASE(dbgSysObj);
223  free(idbg);
224 #undef RELEASE
225 }
226 
227 static bool init_callbacks(DbgEngContext *idbg) {
228 #define RELEASE(I) \
229  if (I) \
230  THISCALL(I, Release);
231  if (!idbg->dbgClient) {
232  return false;
233  }
234 
235  PDEBUG_EVENT_CALLBACKS event_callbacks = DEBUG_EVENT_CALLBACKS_impl_new(idbg);
236  PDEBUG_INPUT_CALLBACKS input_callbacks = DEBUG_INPUT_CALLBACKS_impl_new(idbg);
237  PDEBUG_OUTPUT_CALLBACKS output_callbacks = DEBUG_OUTPUT_CALLBACKS_impl_new(idbg);
238 
239  if (!event_callbacks || !output_callbacks || !event_callbacks) {
240  RELEASE(event_callbacks);
241  RELEASE(input_callbacks);
242  RELEASE(output_callbacks);
243  return false;
244  }
245 
246  if (FAILED(ITHISCALL(dbgClient, SetEventCallbacks, event_callbacks)) ||
247  FAILED(ITHISCALL(dbgClient, SetInputCallbacks, input_callbacks)) ||
248  FAILED(ITHISCALL(dbgClient, SetOutputCallbacks, output_callbacks))) {
249  goto fail;
250  }
251 
252  RELEASE(event_callbacks);
253  RELEASE(input_callbacks);
254  RELEASE(output_callbacks);
255  return true;
256 fail:
257  ITHISCALL(dbgClient, SetEventCallbacks, NULL);
258  ITHISCALL(dbgClient, SetInputCallbacks, NULL);
259  ITHISCALL(dbgClient, SetOutputCallbacks, NULL);
260  return false;
261 #undef RELEASE
262 }
263 
264 static DbgEngContext *create_remote_context(const char *opts) {
266 
267  if (!idbg) {
268  return false;
269  }
270 
271  LPWSTR wopts = (LPWSTR)rz_utf8_to_utf16(opts);
272 
273  // Initialize interfaces
274  if (w32_DebugConnectWide(wopts, &IID_IDebugClient5, (PVOID *)&idbg->dbgClient) != S_OK) {
275  goto fail;
276  }
277  if (w32_DebugConnectWide(wopts, &IID_IDebugControl4, (PVOID *)&idbg->dbgCtrl) != S_OK) {
278  goto fail;
279  }
280  if (w32_DebugConnectWide(wopts, &IID_IDebugDataSpaces4, (PVOID *)&idbg->dbgData) != S_OK) {
281  goto fail;
282  }
283  if (w32_DebugConnectWide(wopts, &IID_IDebugRegisters2, (PVOID *)&idbg->dbgReg) != S_OK) {
284  goto fail;
285  }
286  if (w32_DebugConnectWide(wopts, &IID_IDebugSystemObjects4, (PVOID *)&idbg->dbgSysObj) != S_OK) {
287  goto fail;
288  }
289  if (w32_DebugConnectWide(wopts, &IID_IDebugAdvanced3, (PVOID *)&idbg->dbgAdvanced) != S_OK) {
290  goto fail;
291  }
292  if (w32_DebugConnectWide(wopts, &IID_IDebugSymbols3, (PVOID *)&idbg->dbgSymbols) != S_OK) {
293  goto fail;
294  }
295  if (!init_callbacks(idbg)) {
296  goto fail;
297  }
298  idbg->initialized = true;
299  return idbg;
300 fail:
301  __free_context(idbg);
302  return NULL;
303 }
304 
307 
308  if (!idbg) {
309  return false;
310  }
311 
312  // Initialize interfaces
313  if (w32_DebugCreate(&IID_IDebugClient5, (PVOID *)&idbg->dbgClient) != S_OK) {
314  goto fail;
315  }
316  if (w32_DebugCreate(&IID_IDebugControl4, (PVOID *)&idbg->dbgCtrl) != S_OK) {
317  goto fail;
318  }
319  if (w32_DebugCreate(&IID_IDebugDataSpaces4, (PVOID *)&idbg->dbgData) != S_OK) {
320  goto fail;
321  }
322  if (w32_DebugCreate(&IID_IDebugRegisters2, (PVOID *)&idbg->dbgReg) != S_OK) {
323  goto fail;
324  }
325  if (w32_DebugCreate(&IID_IDebugSystemObjects4, (PVOID *)&idbg->dbgSysObj) != S_OK) {
326  goto fail;
327  }
328  if (w32_DebugCreate(&IID_IDebugAdvanced3, (PVOID *)&idbg->dbgAdvanced) != S_OK) {
329  goto fail;
330  }
331  if (w32_DebugCreate(&IID_IDebugSymbols3, (PVOID *)&idbg->dbgSymbols) != S_OK) {
332  goto fail;
333  }
334  if (!init_callbacks(idbg)) {
335  goto fail;
336  }
337  idbg->initialized = true;
338  return idbg;
339 fail:
340  __free_context(idbg);
341  return NULL;
342 }
343 
344 static int windbg_init(void) {
346  return 1;
347  }
348  char *ext_path = rz_sys_getenv("_NT_DEBUGGER_EXTENSION_PATH");
349  HANDLE h = NULL;
350  if (RZ_STR_ISNOTEMPTY(ext_path)) {
351  char *s = strtok(ext_path, ";");
352  do {
353  PWCHAR dir = rz_utf8_to_utf16(s);
354  SetDllDirectoryW(dir);
355  free(dir);
356  h = LoadLibrary(TEXT("dbgeng.dll"));
357  } while (!h && (s = strtok(NULL, ";")));
358  SetDllDirectoryW(NULL);
359  }
360  free(ext_path);
361  if (!h) {
362  h = LoadLibrary(TEXT("dbgeng.dll"));
363  }
364  if (!h) {
365  rz_sys_perror("LoadLibrary (\"dbgeng.dll\")");
366  return 0;
367  }
368 
369  w32_DebugCreate = (DebugCreate_t)GetProcAddress(h, "DebugCreate");
370  if (!w32_DebugCreate) {
371  rz_sys_perror("GetProcAddress (\"DebugCreate\")");
372  return 0;
373  }
374 
375  w32_DebugConnectWide = (DebugConnectWide_t)GetProcAddress(h, "DebugConnectWide");
376  if (!w32_DebugConnectWide) {
377  rz_sys_perror("GetProcAddress (\"DebugConnectWide\")");
378  return 0;
379  }
380 
381  return 1;
382 }
383 
384 static bool windbg_check(RzIO *io, const char *uri, bool many) {
385  return !strncmp(uri, WINDBGURI, strlen(WINDBGURI));
386 }
387 
388 static inline bool cur_dbg_plugin_is_windbg(RzDebug *dbg) {
389  return dbg && dbg->cur && !strcmp(dbg->cur->name, "windbg");
390 }
391 
392 typedef enum {
398 } DbgEngTarget;
399 
400 static RzIODesc *windbg_open(RzIO *io, const char *uri, int perm, int mode) {
401  if (!windbg_check(io, uri, 0)) {
402  return NULL;
403  }
404  if (!windbg_init()) {
405  return NULL;
406  }
407  HRESULT hr = E_FAIL;
408  RzIODesc *fd = NULL;
409  RzCore *core = io->corebind.core;
410  DbgEngContext *idbg = NULL;
411  const char *args = uri + strlen(WINDBGURI);
412  if (rz_str_startswith(args, "-remote")) {
413  args += strlen("-remote") + 1;
414  idbg = create_remote_context(args);
415  if (idbg) {
416  goto remote_client;
417  }
418  } else {
419  idbg = create_context();
420  if (idbg && rz_str_startswith(args, "-premote")) {
421  args += strlen("-premote") + 1;
422  if (FAILED(ITHISCALL(dbgClient, ConnectProcessServer, args, &idbg->server))) {
423  __free_context(idbg);
424  return NULL;
425  }
426  goto remote_client;
427  }
428  }
429  if (!idbg) {
430  return NULL;
431  }
432  ITHISCALL(dbgCtrl, AddEngineOptions, DEBUG_ENGOPT_INITIAL_BREAK);
433  ITHISCALL(dbgCtrl, AddEngineOptions, DEBUG_ENGOPT_FINAL_BREAK);
434  ITHISCALL(dbgCtrl, AddEngineOptions, DEBUG_ENGOPT_ALLOW_READ_ONLY_BREAKPOINTS);
435  ITHISCALL(dbgCtrl, SetCodeLevel, DEBUG_LEVEL_ASSEMBLY);
436  int argc;
437  char **argv = rz_str_argv(args, &argc);
438  const size_t argv_sz = sizeof(char *) * ((size_t)argc + 2);
439  char **tmp = realloc(argv, argv_sz);
440  if (!tmp) {
441  __free_context(idbg);
443  return NULL;
444  }
445  argv = tmp;
446  memmove(argv + 1, argv, argv_sz - sizeof(char *));
447  argv[0] = strdup(WINDBGURI);
448  argc++;
449  const char *command = NULL;
450  bool image_path_set = false, symbol_path_set = false;
452  DWORD spawn_options = DEBUG_ONLY_THIS_PROCESS | CREATE_NEW_CONSOLE;
453  DWORD attach_options = DEBUG_ATTACH_DEFAULT;
454  DWORD pid = 0;
455  int c;
456  RzGetopt opt;
457  rz_getopt_init(&opt, argc, (const char **)argv, "c:dgGh:i:k:op:y:z:");
458  while ((c = rz_getopt_next(&opt)) != -1) {
459  switch (c) {
460  case 'c':
461  command = opt.arg;
462  break;
463  case 'd':
464  ITHISCALL(dbgCtrl, AddEngineOptions, DEBUG_ENGOPT_INITIAL_MODULE_BREAK);
465  break;
466  case 'g':
467  ITHISCALL(dbgCtrl, RemoveEngineOptions, DEBUG_ENGOPT_INITIAL_BREAK);
468  break;
469  case 'G':
470  ITHISCALL(dbgCtrl, RemoveEngineOptions, DEBUG_ENGOPT_FINAL_BREAK);
471  break;
472  case 'h':
473  if (strcmp(opt.arg, "d")) {
474  spawn_options |= DEBUG_CREATE_PROCESS_NO_DEBUG_HEAP;
475  }
476  break;
477  case 'i':
478  ITHISCALL(dbgSymbols, SetImagePath, opt.arg);
479  image_path_set = true;
480  break;
481  case 'k':
482  if (strcmp(opt.arg, "l")) {
483  target = TARGET_LOCAL_KERNEL;
484  } else if (strcmp(opt.arg, "qm")) {
485  ITHISCALL(dbgCtrl, AddEngineOptions, DEBUG_ENGOPT_KD_QUIET_MODE);
486  } else {
487  target = TARGET_KERNEL;
488  args = opt.arg;
489  }
490  break;
491  case 'o':
492  spawn_options &= ~DEBUG_ONLY_THIS_PROCESS;
493  spawn_options |= DEBUG_PROCESS;
494  break;
495  case 'p':
496  if (rz_str_isnumber(opt.arg)) {
497  target = TARGET_LOCAL_ATTACH;
498  pid = atoi(opt.arg);
499  } else {
500  if (strcmp(opt.arg, "b")) {
501  attach_options |= DEBUG_ATTACH_INVASIVE_NO_INITIAL_BREAK;
502  } else if (strcmp(opt.arg, "e")) {
503  attach_options |= DEBUG_ATTACH_EXISTING;
504  } else if (strcmp(opt.arg, "v")) {
505  attach_options |= DEBUG_ATTACH_NONINVASIVE;
506  }
507  }
508  break;
509  case 'y':
510  symbol_path_set = true;
511  ITHISCALL(dbgSymbols, SetSymbolPath, opt.arg);
512  break;
513  case 'z':
514  target = TARGET_DUMP_FILE;
515  args = opt.arg;
516  break;
517  default:
518  break;
519  }
520  }
521  if (!symbol_path_set) {
522  const char *store = io->corebind.cfgGet(core, "pdb.symstore");
523  const char *server = io->corebind.cfgGet(core, "pdb.server");
524  char *s = strdup(server);
525  rz_str_replace_ch(s, ';', '*', true);
526  char *sympath = rz_str_newf("cache*;srv*%s*%s", store, s);
527  ITHISCALL(dbgSymbols, SetSymbolPath, sympath);
528  free(s);
529  free(sympath);
530  }
531  if (!image_path_set) {
532  char *path = rz_sys_getenv("PATH");
533  ITHISCALL(dbgSymbols, AppendImagePath, path);
534  free(path);
535  }
536  switch (target) {
537  case TARGET_LOCAL_SPAWN:
538  if (argv[opt.ind]) {
539  char *cmd = rz_str_format_msvc_argv((size_t)opt.argc - opt.ind, (const char **)argv + opt.ind);
540  hr = ITHISCALL(dbgClient, CreateProcess, 0ULL, cmd, spawn_options);
541  free(cmd);
542  } else {
543  eprintf("Missing argument for local spawn\n");
544  }
545  break;
546  case TARGET_LOCAL_ATTACH: // -p (PID)
547  hr = ITHISCALL(dbgClient, AttachProcess, 0ULL, pid, attach_options);
548  break;
549  case TARGET_LOCAL_KERNEL: // -kl
550  if (ITHISCALL(dbgClient, IsKernelDebuggerEnabled) == S_FALSE) {
551  eprintf("Live Kernel debug not available. Set the /debug boot switch to enable it\n");
552  } else {
553  hr = ITHISCALL(dbgClient, AttachKernel, DEBUG_ATTACH_LOCAL_KERNEL, args);
554  }
555  break;
556  case TARGET_DUMP_FILE: // -z
557  hr = ITHISCALL(dbgClient, OpenDumpFile, args);
558  break;
559  case TARGET_KERNEL: // -k
560  hr = ITHISCALL(dbgClient, AttachKernel, DEBUG_ATTACH_KERNEL_CONNECTION, args);
561  break;
562  }
563  if (hr != S_OK) {
565  __free_context(idbg);
566  return NULL;
567  }
568  ITHISCALL(dbgCtrl, WaitForEvent, DEBUG_WAIT_DEFAULT, INFINITE);
569  if (command) {
570  ITHISCALL(dbgCtrl, Execute, DEBUG_OUTCTL_ALL_CLIENTS, command, DEBUG_EXECUTE_DEFAULT);
571  }
573 remote_client:
574  fd = rz_io_desc_new(io, &rz_io_plugin_windbg, uri, perm | RZ_PERM_X, mode, idbg);
575  fd->name = strdup(args);
576  if (cur_dbg_plugin_is_windbg(core->dbg)) {
577  core->dbg->plugin_data = idbg;
578  }
579  return fd;
580 }
581 
582 static int windbg_close(RzIODesc *fd) {
583  DbgEngContext *idbg = fd->data;
584  if (!idbg) {
585  return 0;
586  }
587  fd->data = NULL;
588  RzCore *core = fd->io->corebind.core;
589  if (idbg->server) {
590  ITHISCALL(dbgClient, EndSession, DEBUG_END_DISCONNECT);
591  ITHISCALL(dbgClient, DisconnectProcessServer, idbg->server);
592  idbg->server = 0ULL;
593  } else {
594  ITHISCALL(dbgClient, EndSession, DEBUG_END_ACTIVE_DETACH);
595  }
596  if (cur_dbg_plugin_is_windbg(core->dbg)) {
597  core->dbg->plugin_data = NULL;
598  }
599  __free_context(idbg);
600  return 0;
601 }
602 
603 static ut64 windbg_lseek(RzIO *io, RzIODesc *fd, ut64 offset, int whence) {
604  switch (whence) {
605  case RZ_IO_SEEK_SET:
606  io->off = offset;
607  break;
608  case RZ_IO_SEEK_CUR:
609  io->off += (st64)offset;
610  break;
611  case RZ_IO_SEEK_END:
612  io->off = UT64_MAX;
613  break;
614  }
615  return io->off;
616 }
617 
618 static int windbg_read(RzIO *io, RzIODesc *fd, ut8 *buf, int count) {
619  DbgEngContext *idbg = fd->data;
620  ULONG bytesRead = 0ULL;
621  if (FAILED(ITHISCALL(dbgData, ReadVirtual, io->off, (PVOID)buf, count, &bytesRead))) {
622  ULONG64 ValidBase;
623  ULONG ValidSize;
624  if (SUCCEEDED(ITHISCALL(dbgData, GetValidRegionVirtual, io->off, count, &ValidBase, &ValidSize))) {
625  if (ValidSize && ValidBase < io->off + count) {
626  const ULONG64 skipped = ValidBase - io->off;
627  const ULONG toRead = count - skipped;
628  ITHISCALL(dbgData, ReadVirtual, ValidBase, (PVOID)(buf + skipped), toRead, &bytesRead);
629  bytesRead += skipped;
630  }
631  }
632  }
633  return bytesRead;
634 }
635 
636 static int windbg_write(RzIO *io, RzIODesc *fd, const ut8 *buf, int count) {
637  DbgEngContext *idbg = fd->data;
638  ULONG bytesWritten = 0ULL;
639  ITHISCALL(dbgData, WriteVirtual, io->off, (PVOID)buf, count, &bytesWritten);
640  return bytesWritten;
641 }
642 
643 static int windbg_getpid(RzIODesc *fd) {
644  DbgEngContext *idbg = fd->data;
645  ULONG Id = 0, Class, Qualifier;
646  if (SUCCEEDED(ITHISCALL(dbgCtrl, GetDebuggeeType, &Class, &Qualifier))) {
647  if (Class == DEBUG_CLASS_KERNEL) {
648  ITHISCALL(dbgSysObj, GetCurrentProcessId, &Id);
649  } else {
650  ITHISCALL(dbgSysObj, GetCurrentProcessSystemId, &Id);
651  }
652  }
653  return Id;
654 }
655 
656 static int windbg_gettid(RzIODesc *fd) {
657  DbgEngContext *idbg = fd->data;
658  ULONG Id = 0, Class, Qualifier;
659  if (SUCCEEDED(ITHISCALL(dbgCtrl, GetDebuggeeType, &Class, &Qualifier))) {
660  if (Class == DEBUG_CLASS_KERNEL) {
661  ITHISCALL(dbgSysObj, GetCurrentThreadId, &Id);
662  } else {
663  ITHISCALL(dbgSysObj, GetCurrentThreadSystemId, &Id);
664  }
665  }
666  return Id;
667 }
668 
669 static bool windbg_getbase(RzIODesc *fd, ut64 *base) {
670  DbgEngContext *idbg = fd->data;
671  *base = idbg->processBase;
672  return true;
673 }
674 
675 static char *windbg_system(RzIO *io, RzIODesc *fd, const char *cmd) {
676  DbgEngContext *idbg = fd->data;
677  if (RZ_STR_ISEMPTY(cmd) || !strncmp("pid", cmd, 3)) {
678  return NULL;
679  }
680  ITHISCALL(dbgCtrl, Execute, DEBUG_OUTCTL_ALL_CLIENTS, cmd, DEBUG_EXECUTE_DEFAULT);
681  return NULL;
682 }
683 
685  .name = "windbg",
686  .desc = "WinDBG (DbgEng.dll) based io plugin for Windows",
687  .license = "LGPL3",
688  .uris = WINDBGURI,
689  .isdbg = true,
690  .init = windbg_init,
691  .open = windbg_open,
692  .lseek = windbg_lseek,
693  .read = windbg_read,
694  .write = windbg_write,
695  .system = windbg_system,
696  .close = windbg_close,
697  .getpid = windbg_getpid,
698  .gettid = windbg_gettid,
699  .getbase = windbg_getbase,
700  .check = windbg_check,
701 };
702 
703 #ifndef RZ_PLUGIN_INCORE
705  .type = RZ_LIB_TYPE_IO,
706  .data = &rz_io_plugin_windbg,
708 };
709 #endif
struct java_interface_t Interface
#define RZ_API
#define NULL
Definition: cris-opc.c:27
static static fork const void static count static fd const char const char static newpath const char static path const char path
Definition: sflib.h:35
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void count
Definition: sflib.h:98
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags cmd
Definition: sflib.h:79
RzDebug * dbg
Definition: desil.c:30
RZ_API const char * rz_line_readline(void)
Definition: dietline.c:913
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
#define WINDBGURI
Definition: io_windbg.c:20
#define DECLARE_ADDREF(IFace)
Definition: io_windbg.c:88
static bool cur_dbg_plugin_is_windbg(RzDebug *dbg)
Definition: io_windbg.c:388
static DebugCreate_t w32_DebugCreate
Definition: io_windbg.c:17
static int windbg_read(RzIO *io, RzIODesc *fd, ut8 *buf, int count)
Definition: io_windbg.c:618
static ut64 windbg_lseek(RzIO *io, RzIODesc *fd, ut64 offset, int whence)
Definition: io_windbg.c:603
DbgEngTarget
Definition: io_windbg.c:392
@ TARGET_KERNEL
Definition: io_windbg.c:397
@ TARGET_DUMP_FILE
Definition: io_windbg.c:396
@ TARGET_LOCAL_KERNEL
Definition: io_windbg.c:395
@ TARGET_LOCAL_SPAWN
Definition: io_windbg.c:393
@ TARGET_LOCAL_ATTACH
Definition: io_windbg.c:394
#define INIT_IUNKNOWN_CALLBACKS(IFace, lpVtbl)
Definition: io_windbg.c:46
static DbgEngContext * create_context(void)
Definition: io_windbg.c:305
#define RELEASE(I)
static int windbg_gettid(RzIODesc *fd)
Definition: io_windbg.c:656
static void DEBUG_EVENT_CALLBACKS_vtbl_init(PDEBUG_EVENT_CALLBACKS callbacks)
Definition: io_windbg.c:185
#define ITHISCALL(dbginterface, function,...)
Definition: io_windbg.c:37
#define DECLARE_NEW(IFace, IVtbl)
Definition: io_windbg.c:51
static void DEBUG_OUTPUT_CALLBACKS_vtbl_init(PDEBUG_OUTPUT_CALLBACKS callbacks)
Definition: io_windbg.c:201
RZ_API RzLibStruct rizin_plugin
Definition: io_windbg.c:704
static STDMETHODIMP __breakpoint_cb(PDEBUG_EVENT_CALLBACKS This, PDEBUG_BREAKPOINT Bp)
Definition: io_windbg.c:136
static STDMETHODIMP __exception_cb(PDEBUG_EVENT_CALLBACKS This, PEXCEPTION_RECORD64 Exception, ULONG FirstChance)
Definition: io_windbg.c:140
static STDMETHODIMP __output_cb(PDEBUG_OUTPUT_CALLBACKS This, ULONG Mask, PCSTR Text)
Definition: io_windbg.c:168
#define DECLARE_RELEASE(IFace)
Definition: io_windbg.c:95
static bool init_callbacks(DbgEngContext *idbg)
Definition: io_windbg.c:227
static DebugConnectWide_t w32_DebugConnectWide
Definition: io_windbg.c:18
static int windbg_write(RzIO *io, RzIODesc *fd, const ut8 *buf, int count)
Definition: io_windbg.c:636
static STDMETHODIMP __interest_mask(PDEBUG_EVENT_CALLBACKS This, PULONG Mask)
Definition: io_windbg.c:111
static STDMETHODIMP __input_cb(PDEBUG_INPUT_CALLBACKS This, ULONG BufferSize)
Definition: io_windbg.c:152
#define DECLARE_CALLBACKS_IMPL(Type, IFace)
Definition: io_windbg.c:39
RzIOPlugin rz_io_plugin_windbg
Definition: io_windbg.c:684
static RzIODesc * windbg_open(RzIO *io, const char *uri, int perm, int mode)
Definition: io_windbg.c:400
static int windbg_close(RzIODesc *fd)
Definition: io_windbg.c:582
static int windbg_init(void)
Definition: io_windbg.c:344
HRESULT(__stdcall * DebugConnectWide_t)(_In_ PCWSTR RemoteOptions, _In_ REFIID InterfaceId, _Out_ PVOID *Interface)
Definition: io_windbg.c:12
static bool windbg_getbase(RzIODesc *fd, ut64 *base)
Definition: io_windbg.c:669
static bool windbg_check(RzIO *io, const char *uri, bool many)
Definition: io_windbg.c:384
static void __free_context(DbgEngContext *idbg)
Definition: io_windbg.c:210
#define DECLARE_QUERYINTERFACE(IFace, IFaceIID)
Definition: io_windbg.c:72
static STDMETHODIMP __system_error_cb(PDEBUG_EVENT_CALLBACKS This, ULONG Error, ULONG Level)
Definition: io_windbg.c:148
static STDMETHODIMP __input_end_cb(PDEBUG_INPUT_CALLBACKS This)
Definition: io_windbg.c:164
static void DEBUG_INPUT_CALLBACKS_vtbl_init(PDEBUG_INPUT_CALLBACKS callbacks)
Definition: io_windbg.c:195
static STDMETHODIMP __createprocess_cb(PDEBUG_EVENT_CALLBACKS This, ULONG64 ImageFileHandle, ULONG64 Handle, ULONG64 BaseOffset, ULONG ModuleSize, PCSTR ModuleName, PCSTR ImageName, ULONG CheckSum, ULONG TimeDateStamp, ULONG64 InitialThreadHandle, ULONG64 ThreadDataOffset, ULONG64 StartOffset)
Definition: io_windbg.c:118
static int windbg_getpid(RzIODesc *fd)
Definition: io_windbg.c:643
static STDMETHODIMP __exit_process_cb(PDEBUG_EVENT_CALLBACKS This, ULONG ExitCode)
Definition: io_windbg.c:144
static char * windbg_system(RzIO *io, RzIODesc *fd, const char *cmd)
Definition: io_windbg.c:675
static DbgEngContext * create_remote_context(const char *opts)
Definition: io_windbg.c:264
HRESULT(__stdcall * DebugCreate_t)(_In_ REFIID InterfaceId, _Out_ PVOID *Interface)
Definition: io_windbg.c:8
voidpf uLong offset
Definition: ioapi.h:144
const char int mode
Definition: ioapi.h:137
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
void * realloc(void *ptr, size_t size)
Definition: malloc.c:144
RZ_API void rz_line_set_prompt(const char *prompt)
Definition: line.c:56
static static fork const void static count static fd const char const char static newpath char char char static envp time_t static t const char static mode static whence const char static dir time_t static t unsigned static seconds const char struct utimbuf static buf static inc pid
Definition: sflib.h:64
static static fork const void static count static fd const char const char static newpath char char argv
Definition: sflib.h:40
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
#define Error(x)
Definition: mach0.c:439
int args
Definition: mipsasm.c:18
int off
Definition: pal.c:13
#define eprintf(x, y...)
Definition: rlcc.c:7
static RzSocket * s
Definition: rtr.c:28
RZ_API void rz_getopt_init(RzGetopt *go, int argc, const char **argv, const char *ostr)
Definition: getopt.c:17
RZ_API int rz_getopt_next(RzGetopt *opt)
Definition: getopt.c:29
#define RZ_IO_SEEK_CUR
Definition: rz_io.h:16
RZ_API RzIODesc * rz_io_desc_new(RzIO *io, RzIOPlugin *plugin, const char *uri, int flags, int mode, void *data)
Definition: io_desc.c:11
#define RZ_IO_SEEK_SET
Definition: rz_io.h:15
#define RZ_IO_SEEK_END
Definition: rz_io.h:17
@ RZ_LIB_TYPE_IO
Definition: rz_lib.h:69
#define RZ_STR_ISNOTEMPTY(x)
Definition: rz_str.h:68
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
RZ_API char * rz_str_ndup(RZ_NULLABLE const char *ptr, int len)
Create new copy of string ptr limited to size len.
Definition: str.c:1006
RZ_API char * rz_str_format_msvc_argv(size_t argc, const char **argv)
Definition: str.c:1844
#define RZ_STR_ISEMPTY(x)
Definition: rz_str.h:67
RZ_API bool rz_str_isnumber(const char *str)
Definition: str.c:3550
RZ_API int rz_str_replace_ch(char *s, char a, char b, bool g)
Definition: str.c:139
RZ_API char ** rz_str_argv(const char *str, int *_argc)
Definition: str.c:2509
RZ_API bool rz_str_startswith(RZ_NONNULL const char *str, RZ_NONNULL const char *needle)
Checks if a string starts with a specifc sequence of characters (case sensitive)
Definition: str.c:3286
RZ_API void rz_str_argv_free(char **argv)
Definition: str.c:2633
RZ_API char * rz_sys_getenv(const char *key)
Get the value of an environment variable named key or NULL if none exists.
Definition: sys.c:483
#define rz_sys_perror(x)
Definition: rz_types.h:336
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_PERM_X
Definition: rz_types.h:95
#define RZ_MIN(x, y)
#define st64
Definition: rz_types_base.h:10
#define UT64_MAX
Definition: rz_types_base.h:86
#define RZ_VERSION
Definition: rz_version.h:8
#define c(i)
Definition: sha256.c:43
#define h(i)
Definition: sha256.c:48
PDEBUG_SYSTEM_OBJECTS4 dbgSysObj
Definition: debug_windbg.c:42
PDEBUG_REGISTERS2 dbgReg
Definition: debug_windbg.c:41
PDEBUG_CONTROL4 dbgCtrl
Definition: debug_windbg.c:39
ULONG64 server
Definition: debug_windbg.c:35
ULONG64 processBase
Definition: debug_windbg.c:36
PDEBUG_CLIENT5 dbgClient
Definition: debug_windbg.c:38
PDEBUG_SYMBOLS3 dbgSymbols
Definition: debug_windbg.c:43
PDEBUG_DATA_SPACES4 dbgData
Definition: debug_windbg.c:40
PDEBUG_ADVANCED3 dbgAdvanced
Definition: debug_windbg.c:44
RzCoreConfigGet cfgGet
Definition: rz_bind.h:44
void * core
Definition: rz_bind.h:31
RzDebug * dbg
Definition: rz_core.h:329
const char * name
Definition: rz_debug.h:359
struct rz_debug_plugin_t * cur
Definition: rz_debug.h:295
void * plugin_data
Definition: rz_debug.h:296
const char * arg
Definition: rz_getopt.h:15
const char * name
Definition: rz_io.h:115
const char * version
Definition: rz_io.h:117
Definition: rz_io.h:59
RzCoreBind corebind
Definition: rz_io.h:92
ut64 off
Definition: rz_io.h:61
char * name
Definition: z80_tab.h:24
const char * command
Definition: main.c:7
#define fail(test)
Definition: tests.h:29
static int initialized
Definition: tricore-dis.c:96
static char * prompt(const char *str, const char *txt)
Definition: vmenus.c:30
DWORD LPWSTR
DWORD * HANDLE
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
ULONG
PVOID
DWORD
PULONG
static const z80_opcode fd[]
Definition: z80_tab.h:997