include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / programs / winedbg / memory.c
blob2c28d7a569cdccd50857ba8399ab802aa28d60de
1 /*
2 * Debugger memory handling
4 * Copyright 1993 Eric Youngdale
5 * Copyright 1995 Alexandre Julliard
6 * Copyright 2000-2005 Eric Pouech
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <Zydis/Zydis.h>
28 #include "debugger.h"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
33 void* be_cpu_linearize(HANDLE hThread, const ADDRESS64* addr)
35 assert(addr->Mode == AddrModeFlat);
36 return (void*)(DWORD_PTR)addr->Offset;
39 BOOL be_cpu_build_addr(HANDLE hThread, const dbg_ctx_t *ctx, ADDRESS64* addr,
40 unsigned seg, DWORD64 offset)
42 addr->Mode = AddrModeFlat;
43 addr->Segment = 0; /* don't need segment */
44 addr->Offset = offset;
45 return TRUE;
48 void* memory_to_linear_addr(const ADDRESS64* addr)
50 return dbg_curr_process->be_cpu->linearize(dbg_curr_thread->handle, addr);
53 BOOL memory_get_current_pc(ADDRESS64* addr)
55 assert(dbg_curr_process->be_cpu->get_addr);
56 return dbg_curr_process->be_cpu->get_addr(dbg_curr_thread->handle, &dbg_context,
57 be_cpu_addr_pc, addr);
60 BOOL memory_get_current_stack(ADDRESS64* addr)
62 assert(dbg_curr_process->be_cpu->get_addr);
63 return dbg_curr_process->be_cpu->get_addr(dbg_curr_thread->handle, &dbg_context,
64 be_cpu_addr_stack, addr);
67 static void memory_report_invalid_addr(const void* addr)
69 ADDRESS64 address;
71 address.Mode = AddrModeFlat;
72 address.Segment = 0;
73 address.Offset = (ULONG_PTR)addr;
74 dbg_printf("*** Invalid address ");
75 print_address(&address, FALSE);
76 dbg_printf(" ***\n");
79 /***********************************************************************
80 * memory_read_value
82 * Read a memory value.
84 BOOL memory_read_value(const struct dbg_lvalue* lvalue, DWORD size, void* result)
86 BOOL ret = FALSE;
88 if (lvalue->in_debuggee)
90 void* linear = memory_to_linear_addr(&lvalue->addr);
91 if (!(ret = dbg_read_memory(linear, result, size)))
92 memory_report_invalid_addr(linear);
94 else
96 if (lvalue->addr.Offset)
98 memcpy(result, (void*)(DWORD_PTR)lvalue->addr.Offset, size);
99 ret = TRUE;
102 return ret;
105 /***********************************************************************
106 * memory_write_value
108 * Store a value in memory.
110 BOOL memory_write_value(const struct dbg_lvalue* lvalue, DWORD size, void* value)
112 BOOL ret = TRUE;
113 DWORD64 os;
115 if (!types_get_info(&lvalue->type, TI_GET_LENGTH, &os)) return FALSE;
116 if (size != os)
118 dbg_printf("Size mismatch in memory_write_value, got %I64u from type while expecting %lu\n",
119 os, size);
120 return FALSE;
123 /* FIXME: only works on little endian systems */
124 if (lvalue->in_debuggee)
126 void* linear = memory_to_linear_addr(&lvalue->addr);
127 if (!(ret = dbg_write_memory(linear, value, size)))
128 memory_report_invalid_addr(linear);
130 else
132 memcpy((void*)(DWORD_PTR)lvalue->addr.Offset, value, size);
134 return ret;
137 /* transfer a block of memory
138 * the two lvalue:s are expected to be of same size
140 BOOL memory_transfer_value(const struct dbg_lvalue* to, const struct dbg_lvalue* from)
142 DWORD64 size_to, size_from;
143 BYTE tmp[256];
144 BYTE* ptr = tmp;
145 BOOL ret;
147 if (to->bitlen || from->bitlen) return FALSE;
148 if (!types_get_info(&to->type, TI_GET_LENGTH, &size_to) ||
149 !types_get_info(&from->type, TI_GET_LENGTH, &size_from) ||
150 size_from != size_to) return FALSE;
151 /* optimize debugger to debugger transfer */
152 if (!to->in_debuggee && !from->in_debuggee)
154 memcpy(memory_to_linear_addr(&to->addr), memory_to_linear_addr(&from->addr), size_from);
155 return TRUE;
157 if (size_to > sizeof(tmp))
159 ptr = malloc(size_from);
160 if (!ptr) return FALSE;
162 ret = memory_read_value(from, size_from, ptr) &&
163 memory_write_value(to, size_from, ptr);
164 if (size_to > sizeof(tmp)) free(ptr);
165 return ret;
168 /***********************************************************************
169 * memory_examine
171 * Implementation of the 'x' command.
173 void memory_examine(const struct dbg_lvalue *lvalue, int count, char format)
175 int i;
176 char buffer[256];
177 ADDRESS64 addr;
178 void *linear;
180 types_extract_as_address(lvalue, &addr);
181 linear = memory_to_linear_addr(&addr);
183 if (format != 'i' && count > 1)
185 print_address(&addr, FALSE);
186 dbg_printf(": ");
189 switch (format)
191 case 'u':
192 if (count == 1) count = 256;
193 memory_get_string(dbg_curr_process, linear,
194 TRUE, TRUE, buffer, min(count, sizeof(buffer)));
195 dbg_printf("%s\n", buffer);
196 return;
197 case 's':
198 if (count == 1) count = 256;
199 memory_get_string(dbg_curr_process, linear,
200 TRUE, FALSE, buffer, min(count, sizeof(buffer)));
201 dbg_printf("%s\n", buffer);
202 return;
203 case 'i':
204 while (count-- && memory_disasm_one_insn(&addr));
205 return;
206 case 'g':
207 while (count--)
209 GUID guid;
210 if (!dbg_read_memory(linear, &guid, sizeof(guid)))
212 memory_report_invalid_addr(linear);
213 break;
215 dbg_printf("{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
216 guid.Data1, guid.Data2, guid.Data3,
217 guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
218 guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
219 linear = (char*)linear + sizeof(guid);
220 addr.Offset += sizeof(guid);
221 if (count)
223 print_address(&addr, FALSE);
224 dbg_printf(": ");
227 return;
229 #define DO_DUMP2(_t,_l,_f,_vv) { \
230 _t _v; \
231 for (i = 0; i < count; i++) { \
232 if (!dbg_read_memory(linear, &_v, sizeof(_t))) \
233 { memory_report_invalid_addr(linear); break; } \
234 dbg_printf(_f, (_vv)); \
235 addr.Offset += sizeof(_t); \
236 linear = (char*)linear + sizeof(_t); \
237 if ((i % (_l)) == (_l) - 1 && i != count - 1) \
239 dbg_printf("\n"); \
240 print_address(&addr, FALSE); \
241 dbg_printf(": "); \
244 dbg_printf("\n"); \
246 #define DO_DUMP(_t,_l,_f) DO_DUMP2(_t,_l,_f,_v)
248 case 'x': DO_DUMP(int, 4, " %8.8x"); break;
249 case 'd': DO_DUMP(unsigned int, 4, " %4.4d"); break;
250 case 'w': DO_DUMP(unsigned short, 8, " %04x"); break;
251 case 'a':
252 if (ADDRSIZE == 4)
254 DO_DUMP(DWORD, 4, " %8.8lx");
256 else
258 DO_DUMP(DWORD64, 2, " %16.16I64x");
260 break;
261 case 'c': DO_DUMP2(char, 32, " %c", (_v < 0x20) ? ' ' : _v); break;
262 case 'b': DO_DUMP2(char, 16, " %02x", (_v) & 0xff); break;
266 BOOL memory_fetch_integer(const struct dbg_lvalue* lvalue, unsigned size,
267 BOOL is_signed, dbg_lgint_t* ret)
269 /* size must fit in ret and be a power of two */
270 if (size > sizeof(*ret) || (size & (size - 1))) return FALSE;
272 if (lvalue->bitlen)
274 struct dbg_lvalue alt_lvalue = *lvalue;
275 dbg_lguint_t mask;
276 DWORD bt;
277 /* FIXME: this test isn't sufficient, depending on start of bitfield
278 * (ie a 64 bit field can spread across 9 bytes)
280 if (lvalue->bitlen > 8 * sizeof(dbg_lgint_t)) return FALSE;
281 alt_lvalue.addr.Offset += lvalue->bitstart >> 3;
283 * Bitfield operation. We have to extract the field.
285 if (!memory_read_value(&alt_lvalue, sizeof(*ret), ret)) return FALSE;
286 mask = ~(dbg_lguint_t)0 << lvalue->bitlen;
287 *ret >>= lvalue->bitstart & 7;
288 *ret &= ~mask;
291 * OK, now we have the correct part of the number.
292 * Check to see whether the basic type is signed or not, and if so,
293 * we need to sign extend the number.
295 if (types_get_info(&lvalue->type, TI_GET_BASETYPE, &bt) &&
296 (bt == btInt || bt == btLong) && (*ret & (1 << (lvalue->bitlen - 1))))
298 *ret |= mask;
301 else
303 /* we are on little endian CPU */
304 memset(ret, 0, sizeof(*ret)); /* clear unread bytes */
305 if (!memory_read_value(lvalue, size, ret)) return FALSE;
307 /* propagate sign information */
308 if (is_signed && size < 8 && (*ret >> (size * 8 - 1)) != 0)
310 dbg_lguint_t neg = -1;
311 *ret |= neg << (size * 8);
314 return TRUE;
317 BOOL memory_store_integer(const struct dbg_lvalue* lvalue, dbg_lgint_t val)
319 DWORD64 size;
320 if (!types_get_info(&lvalue->type, TI_GET_LENGTH, &size)) return FALSE;
321 if (lvalue->bitlen)
323 struct dbg_lvalue alt_lvalue = *lvalue;
324 dbg_lguint_t mask, dst;
326 /* FIXME: this test isn't sufficient, depending on start of bitfield
327 * (ie a 64 bit field can spread across 9 bytes)
329 if (lvalue->bitlen > 8 * sizeof(dbg_lgint_t)) return FALSE;
330 /* mask is 1 where bitfield is present, 0 outside */
331 mask = (~(dbg_lguint_t)0 >> (sizeof(val) * 8 - lvalue->bitlen)) << (lvalue->bitstart & 7);
332 alt_lvalue.addr.Offset += lvalue->bitstart >> 3;
333 val <<= lvalue->bitstart & 7;
334 if (!memory_read_value(&alt_lvalue, (unsigned)size, &dst)) return FALSE;
335 val = (dst & ~mask) | (val & mask);
336 return memory_write_value(&alt_lvalue, (unsigned)size, &val);
338 /* this is simple if we're on a little endian CPU */
339 return memory_write_value(lvalue, (unsigned)size, &val);
342 BOOL memory_fetch_float(const struct dbg_lvalue* lvalue, double *ret)
344 DWORD64 size;
345 if (!types_get_info(&lvalue->type, TI_GET_LENGTH, &size)) return FALSE;
346 /* FIXME: this assumes that debuggee and debugger use the same
347 * representation for reals
349 if (size > sizeof(*ret)) return FALSE;
350 if (!memory_read_value(lvalue, size, ret)) return FALSE;
352 if (size == sizeof(float)) *ret = *(float*)ret;
353 else if (size != sizeof(double)) return FALSE;
355 return TRUE;
358 BOOL memory_store_float(const struct dbg_lvalue* lvalue, double *ret)
360 DWORD64 size;
361 if (!types_get_info(&lvalue->type, TI_GET_LENGTH, &size)) return FALSE;
362 /* FIXME: this assumes that debuggee and debugger use the same
363 * representation for reals
365 if (size > sizeof(*ret)) return FALSE;
366 if (size == sizeof(float))
368 float f = *ret;
369 return memory_write_value(lvalue, size, &f);
371 if (size != sizeof(double)) return FALSE;
372 return memory_write_value(lvalue, size, ret);
375 BOOL memory_get_string(struct dbg_process* pcs, void* addr, BOOL in_debuggee,
376 BOOL unicode, char* buffer, int size)
378 SIZE_T sz;
379 WCHAR* buffW;
381 buffer[0] = 0;
382 if (!addr) return FALSE;
383 if (in_debuggee)
385 BOOL ret;
387 if (!unicode) ret = pcs->process_io->read(pcs->handle, addr, buffer, size, &sz);
388 else
390 buffW = malloc(size * sizeof(WCHAR));
391 ret = pcs->process_io->read(pcs->handle, addr, buffW, size * sizeof(WCHAR), &sz);
392 WideCharToMultiByte(CP_ACP, 0, buffW, sz / sizeof(WCHAR), buffer, size,
393 NULL, NULL);
394 free(buffW);
396 if (size) buffer[size-1] = 0;
397 return ret;
399 else
401 lstrcpynA(buffer, addr, size);
403 return TRUE;
406 BOOL memory_get_string_indirect(struct dbg_process* pcs, void* addr, BOOL unicode, WCHAR* buffer, int size)
408 void* ad = 0;
409 SIZE_T sz;
411 buffer[0] = 0;
412 if (addr &&
413 pcs->process_io->read(pcs->handle, addr, &ad, pcs->be_cpu->pointer_size, &sz) && sz == pcs->be_cpu->pointer_size && ad)
415 LPSTR buff;
416 BOOL ret;
418 if (unicode)
419 ret = pcs->process_io->read(pcs->handle, ad, buffer, size * sizeof(WCHAR), &sz) && sz != 0;
420 else
422 if ((buff = malloc(size)))
424 ret = pcs->process_io->read(pcs->handle, ad, buff, size, &sz) && sz != 0;
425 MultiByteToWideChar(CP_ACP, 0, buff, sz, buffer, size);
426 free(buff);
428 else ret = FALSE;
430 if (size) buffer[size-1] = 0;
431 return ret;
433 return FALSE;
437 * Convert an address offset to hex string. If mode == 32, treat offset as
438 * 32 bits (discard upper 32 bits), if mode == 64 use all 64 bits, if mode == 0
439 * treat as either 32 or 64 bits, depending on whether we're running as
440 * Wine32 or Wine64.
442 char* memory_offset_to_string(char *str, DWORD64 offset, unsigned mode)
444 if (mode != 32 && mode != 64)
446 #ifdef _WIN64
447 mode = 64;
448 #else
449 mode = 32;
450 #endif
453 if (mode == 32)
454 sprintf(str, "0x%08x", (unsigned int) offset);
455 else
456 sprintf(str, "%#016I64x", offset);
458 return str;
461 static void dbg_print_sdecimal(dbg_lgint_t sv)
463 dbg_printf("%I64d", sv);
466 static void dbg_print_hex(DWORD size, dbg_lgint_t sv)
468 if (!sv)
469 dbg_printf("0");
470 else
471 /* clear unneeded high bits, esp. sign extension */
472 dbg_printf("%#I64x", sv & (~(dbg_lguint_t)0 >> (8 * (sizeof(dbg_lgint_t) - size))));
475 static void print_typed_basic(const struct dbg_lvalue* lvalue)
477 dbg_lgint_t val_int;
478 void* val_ptr;
479 double val_real;
480 DWORD64 size64;
481 DWORD tag, size, count, bt;
482 struct dbg_type type = lvalue->type;
483 struct dbg_type sub_type;
484 struct dbg_lvalue sub_lvalue;
486 if (!types_get_real_type(&type, &tag)) return;
488 switch (tag)
490 case SymTagBaseType:
491 if (!types_get_info(&type, TI_GET_LENGTH, &size64) ||
492 !types_get_info(&type, TI_GET_BASETYPE, &bt))
494 WINE_ERR("Couldn't get information\n");
495 RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL);
496 return;
498 size = (DWORD)size64;
499 switch (bt)
501 case btInt:
502 case btLong:
503 if (!memory_fetch_integer(lvalue, size, TRUE, &val_int)) return;
504 dbg_print_hex(size, val_int);
505 break;
506 case btUInt:
507 case btULong:
508 if (!memory_fetch_integer(lvalue, size, FALSE, &val_int)) return;
509 dbg_print_hex(size, val_int);
510 break;
511 case btFloat:
512 if (!memory_fetch_float(lvalue, &val_real)) return;
513 dbg_printf("%f", val_real);
514 break;
515 case btChar:
516 if (!memory_fetch_integer(lvalue, size, TRUE, &val_int)) return;
517 if (size == 1 && isprint((char)val_int))
518 dbg_printf("'%c'", (char)val_int);
519 else
520 dbg_print_hex(size, val_int);
521 break;
522 case btWChar:
523 if (!memory_fetch_integer(lvalue, size, TRUE, &val_int)) return;
524 if (size == 2 && iswprint((WCHAR)val_int))
525 dbg_printf("L'%lc'", (WCHAR)val_int);
526 else
527 dbg_print_hex(size, val_int);
528 break;
529 case btBool:
530 if (!memory_fetch_integer(lvalue, size, TRUE, &val_int)) return;
531 dbg_printf("%s", val_int ? "true" : "false");
532 break;
533 default:
534 WINE_FIXME("Unsupported basetype %lu\n", bt);
535 break;
537 break;
538 case SymTagPointerType:
539 if (!types_array_index(lvalue, 0, &sub_lvalue))
541 dbg_printf("Internal symbol error: unable to access memory location %p",
542 memory_to_linear_addr(&lvalue->addr));
543 break;
545 val_ptr = memory_to_linear_addr(&sub_lvalue.addr);
546 if (types_get_real_type(&sub_lvalue.type, &tag) && tag == SymTagBaseType &&
547 types_get_info(&sub_lvalue.type, TI_GET_BASETYPE, &bt) &&
548 types_get_info(&sub_lvalue.type, TI_GET_LENGTH, &size64))
550 char buffer[1024];
552 if (!val_ptr) dbg_printf("0x0");
553 else if ((bt == btChar && size64 == 1) || (bt == btWChar && size64 == 2))
555 if (memory_get_string(dbg_curr_process, val_ptr, sub_lvalue.in_debuggee,
556 bt == btWChar, buffer, sizeof(buffer)))
557 dbg_printf("%s\"%s\"", bt == btWChar ? "L" : "", buffer);
558 else
559 dbg_printf("*** invalid address %p ***", val_ptr);
560 break;
563 dbg_printf("%p", val_ptr);
564 break;
565 case SymTagArrayType:
566 case SymTagUDT:
567 if (!memory_read_value(lvalue, sizeof(val_ptr), &val_ptr)) return;
568 dbg_printf("%p", val_ptr);
569 break;
570 case SymTagEnum:
572 BOOL ok = FALSE;
574 if (!types_get_info(&type, TI_GET_LENGTH, &size64) ||
575 !memory_fetch_integer(lvalue, size64, TRUE, &val_int)) return;
577 if (types_get_info(&type, TI_GET_CHILDRENCOUNT, &count))
579 char buffer[sizeof(TI_FINDCHILDREN_PARAMS) + 256 * sizeof(DWORD)];
580 TI_FINDCHILDREN_PARAMS* fcp = (TI_FINDCHILDREN_PARAMS*)buffer;
581 WCHAR* ptr;
582 VARIANT variant;
583 int i;
585 fcp->Start = 0;
586 while (count)
588 fcp->Count = min(count, 256);
589 if (types_get_info(&type, TI_FINDCHILDREN, fcp))
591 sub_type.module = type.module;
592 for (i = 0; i < min(fcp->Count, count); i++)
594 sub_type.id = fcp->ChildId[i];
595 if (!types_get_info(&sub_type, TI_GET_VALUE, &variant))
596 continue;
597 switch (V_VT(&variant))
599 case VT_I1: ok = (val_int == V_I1(&variant)); break;
600 case VT_I2: ok = (val_int == V_I2(&variant)); break;
601 case VT_I4: ok = (val_int == V_I4(&variant)); break;
602 case VT_I8: ok = (val_int == V_I8(&variant)); break;
603 default: WINE_FIXME("Unsupported variant type (%u)\n", V_VT(&variant));
605 if (ok && types_get_info(&sub_type, TI_GET_SYMNAME, &ptr) && ptr)
607 dbg_printf("%ls", ptr);
608 HeapFree(GetProcessHeap(), 0, ptr);
609 count = 0; /* so that we'll get away from outer loop */
610 break;
614 count -= min(count, 256);
615 fcp->Start += 256;
618 if (!ok) dbg_print_sdecimal(val_int);
620 break;
621 default:
622 WINE_FIXME("Unsupported tag %lu\n", tag);
623 break;
627 /***********************************************************************
628 * print_basic
630 * Implementation of the 'print' command.
632 void print_basic(const struct dbg_lvalue* lvalue, char format)
634 if (lvalue->type.id == dbg_itype_none)
636 dbg_printf("Unable to evaluate expression\n");
637 return;
640 if (format != 0)
642 unsigned size;
643 dbg_lgint_t res = types_extract_as_lgint(lvalue, &size, NULL);
645 switch (format)
647 case 'x':
648 dbg_print_hex(size, res);
649 return;
651 case 'd':
652 dbg_print_sdecimal(res);
653 return;
655 case 'c':
656 dbg_printf("%d = '%c'", (char)(res & 0xff), (char)(res & 0xff));
657 return;
659 case 'u':
660 dbg_printf("%d = '%lc'", (WCHAR)(res & 0xFFFF), (WCHAR)(res & 0xFFFF));
661 return;
663 case 'i':
664 case 's':
665 case 'w':
666 case 'b':
667 dbg_printf("Format specifier '%c' is meaningless in 'print' command\n", format);
670 if (lvalue->type.id == dbg_itype_segptr)
672 dbg_print_sdecimal(types_extract_as_lgint(lvalue, NULL, NULL));
674 else print_typed_basic(lvalue);
677 void print_bare_address(const ADDRESS64* addr)
679 char hexbuf[MAX_OFFSET_TO_STR_LEN];
681 switch (addr->Mode)
683 case AddrModeFlat:
684 dbg_printf("%s", memory_offset_to_string(hexbuf, addr->Offset, 0));
685 break;
686 case AddrModeReal:
687 case AddrMode1616:
688 dbg_printf("0x%04x:0x%04x", addr->Segment, (unsigned) addr->Offset);
689 break;
690 case AddrMode1632:
691 dbg_printf("0x%04x:%s", addr->Segment,
692 memory_offset_to_string(hexbuf, addr->Offset, 32));
693 break;
694 default:
695 dbg_printf("Unknown mode %x", addr->Mode);
696 break;
700 static void print_address_symbol(const ADDRESS64* addr, BOOL with_line, const char *sep)
702 char buffer[sizeof(SYMBOL_INFO) + 256];
703 SYMBOL_INFO* si = (SYMBOL_INFO*)buffer;
704 DWORD_PTR lin = (DWORD_PTR)memory_to_linear_addr(addr);
705 DWORD64 disp64;
706 DWORD disp;
707 IMAGEHLP_MODULE im;
709 si->SizeOfStruct = sizeof(*si);
710 si->MaxNameLen = 256;
711 im.SizeOfStruct = 0;
712 if (SymFromAddr(dbg_curr_process->handle, lin, &disp64, si) && disp64 < si->Size)
714 dbg_printf("%s %s", sep, si->Name);
715 if (disp64) dbg_printf("+0x%I64x", disp64);
717 else
719 im.SizeOfStruct = sizeof(im);
720 if (!SymGetModuleInfo(dbg_curr_process->handle, lin, &im)) return;
721 dbg_printf("%s %s", sep, im.ModuleName);
722 if (lin > im.BaseOfImage)
723 dbg_printf("+0x%Ix", lin - (DWORD_PTR)im.BaseOfImage);
725 if (with_line)
727 IMAGEHLP_LINE64 il;
729 il.SizeOfStruct = sizeof(il);
730 if (SymGetLineFromAddr64(dbg_curr_process->handle, lin, &disp, &il))
731 dbg_printf(" [%s:%lu]", il.FileName, il.LineNumber);
732 if (im.SizeOfStruct == 0) /* don't display again module if address is in module+disp form */
734 im.SizeOfStruct = sizeof(im);
735 if (SymGetModuleInfo(dbg_curr_process->handle, lin, &im))
736 dbg_printf(" in %s", im.ModuleName);
741 /***********************************************************************
742 * print_address
744 * Print an 16- or 32-bit address, with the nearest symbol if any.
746 void print_address(const ADDRESS64* addr, BOOLEAN with_line)
748 print_bare_address(addr);
749 print_address_symbol(addr, with_line, "");
752 void memory_disasm_one_x86_insn(ADDRESS64 *addr, int display)
754 ZydisDisassembledInstruction instr = { .runtime_address = addr->Offset };
755 ZydisDecoder decoder;
756 ZydisDecoderContext ctx;
757 unsigned char buffer[16];
758 SIZE_T len;
759 int i;
761 if (!dbg_curr_process->process_io->read( dbg_curr_process->handle, memory_to_linear_addr(addr),
762 buffer, sizeof(buffer), &len )) return;
764 switch (addr->Mode)
766 case AddrModeReal:
767 case AddrMode1616:
768 ZydisDecoderInit( &decoder, ZYDIS_MACHINE_MODE_LEGACY_16, ZYDIS_STACK_WIDTH_16 );
769 break;
770 default:
771 if (ADDRSIZE == 4)
772 ZydisDecoderInit( &decoder, ZYDIS_MACHINE_MODE_LEGACY_32, ZYDIS_STACK_WIDTH_32 );
773 else
774 ZydisDecoderInit( &decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_STACK_WIDTH_64 );
775 break;
777 ZydisDecoderDecodeInstruction( &decoder, &ctx, buffer, len, &instr.info );
778 ZydisDecoderDecodeOperands( &decoder, &ctx, &instr.info,
779 instr.operands, instr.info.operand_count );
781 if (display)
783 ZydisFormatter formatter;
784 ZydisFormatterInit( &formatter, ZYDIS_FORMATTER_STYLE_ATT );
785 ZydisFormatterSetProperty( &formatter, ZYDIS_FORMATTER_PROP_HEX_UPPERCASE, 0 );
786 ZydisFormatterFormatInstruction( &formatter, &instr.info, instr.operands,
787 instr.info.operand_count_visible, instr.text,
788 sizeof(instr.text), instr.runtime_address, NULL );
789 dbg_printf( "%s", instr.text );
790 for (i = 0; i < instr.info.operand_count_visible; i++)
792 ADDRESS64 a = { .Mode = AddrModeFlat };
793 ZyanU64 addr;
795 if (!ZYAN_SUCCESS(ZydisCalcAbsoluteAddress( &instr.info, &instr.operands[i],
796 instr.runtime_address, &addr )))
797 continue;
799 if (instr.info.meta.branch_type == ZYDIS_BRANCH_TYPE_NEAR &&
800 instr.operands[i].type == ZYDIS_OPERAND_TYPE_MEMORY &&
801 instr.operands[i].mem.disp.has_displacement &&
802 instr.operands[i].mem.index == ZYDIS_REGISTER_NONE &&
803 (instr.operands[i].mem.base == ZYDIS_REGISTER_NONE ||
804 instr.operands[i].mem.base == ZYDIS_REGISTER_EIP ||
805 instr.operands[i].mem.base == ZYDIS_REGISTER_RIP))
807 unsigned char dest[8];
808 if (dbg_read_memory( (void *)(ULONG_PTR)addr, dest, ADDRSIZE ))
810 dbg_printf( " -> " );
811 a.Offset = ADDRSIZE == 4 ? *(DWORD *)dest : *(DWORD64 *)dest;
812 print_address( &a, TRUE );
813 break;
816 a.Offset = addr;
817 print_address_symbol( &a, TRUE, instr.info.operand_count_visible > 1 ? " ;" : "" );
818 break;
821 addr->Offset += instr.info.length;
824 BOOL memory_disasm_one_insn(ADDRESS64* addr)
826 char ch;
828 print_address(addr, TRUE);
829 dbg_printf(": ");
830 if (!dbg_read_memory(memory_to_linear_addr(addr), &ch, sizeof(ch)))
832 dbg_printf("-- no code accessible --\n");
833 return FALSE;
835 dbg_curr_process->be_cpu->disasm_one_insn(addr, TRUE);
836 dbg_printf("\n");
837 return TRUE;
840 void memory_disassemble(const struct dbg_lvalue* xstart,
841 const struct dbg_lvalue* xend, int instruction_count)
843 static ADDRESS64 last = {0,0,0};
844 dbg_lgint_t stop = 0;
845 int i;
847 if (!xstart && !xend)
849 if (!last.Segment && !last.Offset) memory_get_current_pc(&last);
851 else
853 if (xstart)
854 types_extract_as_address(xstart, &last);
855 if (xend)
856 stop = types_extract_as_integer(xend);
858 for (i = 0; (instruction_count == 0 || i < instruction_count) &&
859 (stop == 0 || last.Offset <= stop); i++)
860 memory_disasm_one_insn(&last);
863 BOOL memory_get_register(DWORD regno, struct dbg_lvalue* lvalue, char* buffer, int len)
865 const struct dbg_internal_var* div;
867 /* negative register values are wine's dbghelp hacks
868 * see dlls/dbghelp/dbghelp_private.h for the details
870 switch (regno)
872 case -1:
873 if (buffer) snprintf(buffer, len, "<internal error>");
874 return FALSE;
875 case -2:
876 if (buffer) snprintf(buffer, len, "<couldn't compute location>");
877 return FALSE;
878 case -3:
879 if (buffer) snprintf(buffer, len, "<is not available>");
880 return FALSE;
881 case -4:
882 if (buffer) snprintf(buffer, len, "<couldn't read memory>");
883 return FALSE;
884 case -5:
885 if (buffer) snprintf(buffer, len, "<has been optimized away by compiler>");
886 return FALSE;
889 for (div = dbg_curr_process->be_cpu->context_vars; div->name; div++)
891 if (div->val == regno)
893 if (!stack_get_register_frame(div, lvalue))
895 if (buffer) snprintf(buffer, len, "<register %s not accessible in this frame>", div->name);
896 return FALSE;
899 if (buffer) lstrcpynA(buffer, div->name, len);
900 return TRUE;
903 if (buffer) snprintf(buffer, len, "<unknown register %lu>", regno);
904 return FALSE;