Added a few more Unicode digits from Unicode version 4.1.
[wine] / programs / winedbg / memory.c
1 /*
2  * Debugger memory handling
3  *
4  * Copyright 1993 Eric Youngdale
5  * Copyright 1995 Alexandre Julliard
6  * Copyright 2000-2004 Eric Pouech
7  *
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.
12  *
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.
17  *
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdio.h>
29
30 #include "debugger.h"
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
34
35 void* be_cpu_linearize(HANDLE hThread, const ADDRESS* addr)
36 {
37     assert(addr->Mode == AddrModeFlat);
38     return (void*)addr->Offset;
39 }
40
41 unsigned be_cpu_build_addr(HANDLE hThread, const CONTEXT* ctx, ADDRESS* addr, 
42                            unsigned seg, unsigned long offset)
43 {
44     addr->Mode    = AddrModeFlat;
45     addr->Segment = 0; /* don't need segment */
46     addr->Offset  = offset;
47     return TRUE;
48 }
49
50 void* memory_to_linear_addr(const ADDRESS* addr)
51 {
52     return be_cpu->linearize(dbg_curr_thread->handle, addr);
53 }
54
55 BOOL memory_get_current_pc(ADDRESS* addr)
56 {
57     assert(be_cpu->get_addr);
58     return be_cpu->get_addr(dbg_curr_thread->handle, &dbg_context, 
59                             be_cpu_addr_pc, addr);
60 }
61
62 BOOL memory_get_current_stack(ADDRESS* addr)
63 {
64     assert(be_cpu->get_addr);
65     return be_cpu->get_addr(dbg_curr_thread->handle, &dbg_context, 
66                             be_cpu_addr_stack, addr);
67 }
68
69 BOOL memory_get_current_frame(ADDRESS* addr)
70 {
71     assert(be_cpu->get_addr);
72     return be_cpu->get_addr(dbg_curr_thread->handle, &dbg_context, 
73                             be_cpu_addr_frame, addr);
74 }
75
76 static void     memory_report_invalid_addr(const void* addr)
77 {
78     ADDRESS     address;
79
80     address.Mode    = AddrModeFlat;
81     address.Segment = 0;
82     address.Offset  = (unsigned long)addr;
83     dbg_printf("*** Invalid address ");
84     print_address(&address, FALSE);
85     dbg_printf("\n");
86 }
87
88 /***********************************************************************
89  *           memory_read_value
90  *
91  * Read a memory value.
92  */
93 BOOL memory_read_value(const struct dbg_lvalue* lvalue, DWORD size, void* result)
94 {
95     BOOL ret = FALSE;
96
97     if (lvalue->cookie == DLV_TARGET)
98     {
99         void*   linear = memory_to_linear_addr(&lvalue->addr);
100         if (!(ret = dbg_read_memory(linear, result, size)))
101             memory_report_invalid_addr(linear);
102     }
103     else
104     {
105         if (lvalue->addr.Offset)
106         {
107             memcpy(result, (void*)lvalue->addr.Offset, size);
108             ret = TRUE;
109         }
110     }
111     return TRUE;
112 }
113
114 /***********************************************************************
115  *           memory_write_value
116  *
117  * Store a value in memory.
118  */
119 BOOL memory_write_value(const struct dbg_lvalue* lvalue, DWORD size, void* value)
120 {
121     BOOL        ret = TRUE;
122     DWORD64     os;
123
124     os = ~(DWORD64)size;
125     types_get_info(&lvalue->type, TI_GET_LENGTH, &os);
126     assert(size == os);
127
128     /* FIXME: only works on little endian systems */
129     if (lvalue->cookie == DLV_TARGET)
130     {
131         void*       linear = memory_to_linear_addr(&lvalue->addr);
132         if (!(ret = dbg_write_memory(linear, value, size)))
133             memory_report_invalid_addr(linear);
134     }
135     else 
136     {
137         memcpy((void*)lvalue->addr.Offset, value, size);
138     }
139     return ret;
140 }
141
142 /***********************************************************************
143  *           memory_examine
144  *
145  * Implementation of the 'x' command.
146  */
147 void memory_examine(const struct dbg_lvalue *lvalue, int count, char format)
148 {
149     int                 i;
150     char                buffer[256];
151     ADDRESS             addr;
152     void               *linear;
153
154     if (lvalue->type.id == dbg_itype_none)
155     {
156         be_cpu->build_addr(dbg_curr_thread->handle, &dbg_context,
157                            &addr, lvalue->addr.Segment, lvalue->addr.Offset);
158     }
159     else
160     {
161         addr.Mode = AddrModeFlat;
162         addr.Offset = types_extract_as_integer( lvalue );
163     }
164     linear = memory_to_linear_addr( &addr );
165
166     if (format != 'i' && count > 1)
167     {
168         print_address(&addr, FALSE);
169         dbg_printf(": ");
170     }
171
172     switch (format)
173     {
174     case 'u':
175         if (count == 1) count = 256;
176         memory_get_string(dbg_curr_process, linear, 
177                           TRUE, TRUE, buffer, min(count, sizeof(buffer)));
178         dbg_printf("%s\n", buffer);
179         return;
180     case 's':
181         if (count == 1) count = 256;
182         memory_get_string(dbg_curr_process, linear,
183                           TRUE, FALSE, buffer, min(count, sizeof(buffer)));
184         dbg_printf("%s\n", buffer);
185         return;
186     case 'i':
187         while (count-- && memory_disasm_one_insn(&addr));
188         return;
189     case 'g':
190         while (count--)
191         {
192             GUID guid;
193             if (!dbg_read_memory(linear, &guid, sizeof(guid)))
194             {
195                 memory_report_invalid_addr(linear);
196                 break;
197             }
198             dbg_printf("{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
199                        guid.Data1, guid.Data2, guid.Data3,
200                        guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
201                        guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
202             linear = (char*)linear + sizeof(guid);
203             addr.Offset += sizeof(guid);
204             if (count)
205             {
206                 print_address(&addr, FALSE);
207                 dbg_printf(": ");
208             }
209         }
210         return;
211
212 #define DO_DUMP2(_t,_l,_f,_vv) {                                        \
213             _t _v;                                                      \
214             for (i = 0; i < count; i++) {                               \
215                 if (!dbg_read_memory(linear, &_v, sizeof(_t)))          \
216                 { memory_report_invalid_addr(linear); break; }          \
217                 dbg_printf(_f, (_vv));                                  \
218                 addr.Offset += sizeof(_t);                              \
219                 linear = (char*)linear + sizeof(_t);                    \
220                 if ((i % (_l)) == (_l) - 1 && i != count - 1)           \
221                 {                                                       \
222                     dbg_printf("\n");                                   \
223                     print_address(&addr, FALSE);                        \
224                     dbg_printf(": ");                                   \
225                 }                                                       \
226             }                                                           \
227             dbg_printf("\n");                                           \
228         }                                                               \
229         return
230 #define DO_DUMP(_t,_l,_f) DO_DUMP2(_t,_l,_f,_v)
231
232     case 'x': DO_DUMP(int, 4, " %8.8x");
233     case 'd': DO_DUMP(unsigned int, 4, " %10d");
234     case 'w': DO_DUMP(unsigned short, 8, " %04x");
235     case 'c': DO_DUMP2(char, 32, " %c", (_v < 0x20) ? ' ' : _v);
236     case 'b': DO_DUMP2(char, 16, " %02x", (_v) & 0xff);
237     }
238 }
239
240 BOOL memory_get_string(struct dbg_process* pcs, void* addr, BOOL in_debuggee,
241                        BOOL unicode, char* buffer, int size)
242 {
243     DWORD       sz;
244     WCHAR*      buffW;
245
246     buffer[0] = 0;
247     if (!addr) return FALSE;
248     if (in_debuggee)
249     {
250         BOOL ret;
251
252         if (!unicode) ret = pcs->process_io->read(pcs->handle, addr, buffer, size, &sz);
253         else
254         {
255             buffW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
256             ret = pcs->process_io->read(pcs->handle, addr, buffW, size * sizeof(WCHAR), &sz);
257             WideCharToMultiByte(CP_ACP, 0, buffW, sz / sizeof(WCHAR), buffer, size,
258                                 NULL, NULL);
259             HeapFree(GetProcessHeap(), 0, buffW);
260         }
261         if (size) buffer[size-1] = 0;
262         return ret;
263     }
264     else
265     {
266         lstrcpynA(buffer, addr, size);
267     }
268     return TRUE;
269 }
270
271 BOOL memory_get_string_indirect(struct dbg_process* pcs, void* addr, BOOL unicode, char* buffer, int size)
272 {
273     void*       ad;
274     DWORD       sz;
275
276     buffer[0] = 0;
277     if (addr && 
278         pcs->process_io->read(pcs->handle, addr, &ad, sizeof(ad), &sz) && sz == sizeof(ad) && ad)
279     {
280         return memory_get_string(pcs, ad, TRUE, unicode, buffer, size);
281     }
282     return FALSE;
283 }
284
285 static void print_typed_basic(const struct dbg_lvalue* lvalue)
286 {
287     long long int       val_int;
288     void*               val_ptr;
289     long double         val_real;
290     DWORD64             size64;
291     DWORD               tag, size, count, bt;
292     struct dbg_type     rtype;
293
294     if (lvalue->type.id == dbg_itype_none ||
295         !types_get_info(&lvalue->type, TI_GET_SYMTAG, &tag))
296         return;
297
298     switch (tag)
299     {
300     case SymTagBaseType:
301         if (!types_get_info(&lvalue->type, TI_GET_LENGTH, &size64) ||
302             !types_get_info(&lvalue->type, TI_GET_BASETYPE, &bt))
303         {
304             WINE_ERR("Couldn't get information\n");
305             RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL);
306         }
307         size = (DWORD)size64;
308         switch (bt)
309         {
310         case btInt:
311             if (!be_cpu->fetch_integer(lvalue, size, TRUE, &val_int)) return;
312             dbg_printf("%lld", val_int);
313             break;
314         case btUInt:
315             if (!be_cpu->fetch_integer(lvalue, size, FALSE, &val_int)) return;
316             dbg_printf("%llu", val_int);
317             break;
318         case btFloat:
319             if (!be_cpu->fetch_float(lvalue, size, &val_real)) return;
320             dbg_printf("%Lf", val_real);
321             break;
322         case btChar:
323             if (!be_cpu->fetch_integer(lvalue, size, TRUE, &val_int)) return;
324             /* FIXME: should do the same for a Unicode character (size == 2) */
325             if (size == 1 && (val_int < 0x20 || val_int > 0x80))
326                 dbg_printf("%d", (int)val_int);
327             else
328                 dbg_printf("'%c'", (char)val_int);
329             break;
330         default:
331             WINE_FIXME("Unsupported basetype %lu\n", bt);
332             break;
333         }
334         break;
335     case SymTagPointerType:
336         if (!memory_read_value(lvalue, sizeof(void*), &val_ptr)) return;
337
338         if (!types_get_info(&lvalue->type, TI_GET_TYPE, &rtype.id) ||
339             rtype.id == dbg_itype_none)
340         {
341             dbg_printf("Internal symbol error: unable to access memory location %p", val_ptr);
342             break;
343         }
344         rtype.module = lvalue->type.module;
345         if (types_get_info(&rtype, TI_GET_SYMTAG, &tag) && tag == SymTagBaseType &&
346             types_get_info(&rtype, TI_GET_BASETYPE, &bt) && bt == btChar &&
347             types_get_info(&rtype, TI_GET_LENGTH, &size64))
348         {
349             char    buffer[1024];
350
351             if (!val_ptr) dbg_printf("0x0");
352             else if (memory_get_string(dbg_curr_process, val_ptr, 
353                                        lvalue->cookie == DLV_TARGET,
354                                        size64 == 2, buffer, sizeof(buffer)))
355                 dbg_printf("\"%s\"", buffer);
356             else
357                 dbg_printf("*** invalid address %p ***", val_ptr);
358         }
359         else dbg_printf("%p", val_ptr);
360         break;
361     case SymTagArrayType:
362     case SymTagUDT:
363         assert(lvalue->cookie == DLV_TARGET);
364         if (!memory_read_value(lvalue, sizeof(val_ptr), &val_ptr)) return;
365         dbg_printf("%p", val_ptr);
366         break;
367     case SymTagEnum:
368         {
369             BOOL        ok = FALSE;
370
371             assert(lvalue->cookie == DLV_TARGET);
372             /* FIXME: it depends on underlying type for enums 
373              * (not supported yet in dbghelp)
374              * Assuming 4 as for an int
375              */
376             if (!be_cpu->fetch_integer(lvalue, 4, TRUE, &val_int)) return;
377
378             if (types_get_info(&lvalue->type, TI_GET_CHILDRENCOUNT, &count))
379             {
380                 char                    buffer[sizeof(TI_FINDCHILDREN_PARAMS) + 256 * sizeof(DWORD)];
381                 TI_FINDCHILDREN_PARAMS* fcp = (TI_FINDCHILDREN_PARAMS*)buffer;
382                 WCHAR*                  ptr;
383                 char                    tmp[256];
384                 VARIANT                 variant;
385                 int                     i;
386                 struct dbg_type         type;
387
388                 fcp->Start = 0;
389                 while (count)
390                 {
391                     fcp->Count = min(count, 256);
392                     if (types_get_info(&lvalue->type, TI_FINDCHILDREN, fcp))
393                     {
394                         type.module = lvalue->type.module;
395                         for (i = 0; i < min(fcp->Count, count); i++)
396                         {
397                             type.id = fcp->ChildId[i];
398                             if (!types_get_info(&type, TI_GET_VALUE, &variant)) 
399                                 continue;
400                             switch (variant.n1.n2.vt)
401                             {
402                             case VT_I4: ok = (val_int == variant.n1.n2.n3.lVal); break;
403                             default: WINE_FIXME("Unsupported variant type (%u)\n", variant.n1.n2.vt);
404                             }
405                             if (ok)
406                             {
407                                 ptr = NULL;
408                                 types_get_info(&type, TI_GET_SYMNAME, &ptr);
409                                 if (!ptr) continue;
410                                 WideCharToMultiByte(CP_ACP, 0, ptr, -1, tmp, sizeof(tmp), NULL, NULL);
411                                 HeapFree(GetProcessHeap(), 0, ptr);
412                                 dbg_printf("%s", tmp);
413                                 count = 0; /* so that we'll get away from outter loop */
414                                 break;
415                             }
416                         }
417                     }
418                 }
419                 count -= min(count, 256);
420                 fcp->Start += 256;
421             }
422             if (!ok) dbg_printf("%lld", val_int);
423         }
424         break;
425     default:
426         WINE_FIXME("Unsupported tag %lu\n", tag);
427         break;
428     }
429 }
430
431 /***********************************************************************
432  *           print_basic
433  *
434  * Implementation of the 'print' command.
435  */
436 void print_basic(const struct dbg_lvalue* lvalue, int count, char format)
437 {
438     long int    res;
439
440     if (lvalue->type.id == dbg_itype_none)
441     {
442         dbg_printf("Unable to evaluate expression\n");
443         return;
444     }
445
446     res = types_extract_as_integer(lvalue);
447
448     /* FIXME: this implies i386 byte ordering */
449     switch (format)
450     {
451     case 'x':
452         if (lvalue->addr.Mode != AddrModeFlat)
453             dbg_printf("0x%04lx", res);
454         else
455             dbg_printf("0x%08lx", res);
456         break;
457
458     case 'd':
459         dbg_printf("%ld\n", res);
460         break;
461
462     case 'c':
463         dbg_printf("%d = '%c'", (char)(res & 0xff), (char)(res & 0xff));
464         break;
465
466     case 'u':
467         {
468             WCHAR wch = (WCHAR)(res & 0xFFFF);
469             dbg_printf("%d = '", wch);
470             dbg_outputW(&wch, 1);
471             dbg_printf("'");
472         }
473         break;
474
475     case 'i':
476     case 's':
477     case 'w':
478     case 'b':
479         dbg_printf("Format specifier '%c' is meaningless in 'print' command\n", format);
480     case 0:
481         print_typed_basic(lvalue);
482         break;
483     }
484 }
485
486 void print_bare_address(const ADDRESS* addr)
487 {
488     switch (addr->Mode)
489     {
490     case AddrModeFlat: 
491         dbg_printf("0x%08lx", addr->Offset); 
492         break;
493     case AddrModeReal:
494     case AddrMode1616:
495         dbg_printf("0x%04x:0x%04lx", addr->Segment, addr->Offset);
496         break;
497     case AddrMode1632:
498         dbg_printf("0x%04x:0x%08lx", addr->Segment, addr->Offset);
499         break;
500     default:
501         dbg_printf("Unknown mode %x\n", addr->Mode);
502         break;
503     }
504 }
505
506 /***********************************************************************
507  *           print_address
508  *
509  * Print an 16- or 32-bit address, with the nearest symbol if any.
510  */
511 void print_address(const ADDRESS* addr, BOOLEAN with_line)
512 {
513     char                buffer[sizeof(SYMBOL_INFO) + 256];
514     SYMBOL_INFO*        si = (SYMBOL_INFO*)buffer;
515     void*               lin = memory_to_linear_addr(addr);
516     DWORD64             disp64;
517     DWORD               disp;
518
519     print_bare_address(addr);
520
521     si->SizeOfStruct = sizeof(*si);
522     si->MaxNameLen   = 256;
523     if (!SymFromAddr(dbg_curr_process->handle, (DWORD_PTR)lin, &disp64, si)) return;
524     dbg_printf(" %s", si->Name);
525     if (disp64) dbg_printf("+0x%lx", (DWORD_PTR)disp64);
526     if (with_line)
527     {
528         IMAGEHLP_LINE               il;
529         IMAGEHLP_MODULE             im;
530
531         il.SizeOfStruct = sizeof(il);
532         if (SymGetLineFromAddr(dbg_curr_process->handle, (DWORD_PTR)lin, &disp, &il))
533             dbg_printf(" [%s:%lu]", il.FileName, il.LineNumber);
534         im.SizeOfStruct = sizeof(im);
535         if (SymGetModuleInfo(dbg_curr_process->handle, (DWORD_PTR)lin, &im))
536             dbg_printf(" in %s", im.ModuleName);
537     }
538 }
539
540 struct sym_enum
541 {
542     char*       tmp;
543     DWORD       frame;
544 };
545
546 static BOOL WINAPI sym_enum_cb(SYMBOL_INFO* sym_info, ULONG size, void* user)
547 {
548     struct sym_enum*    se = (struct sym_enum*)user;
549     DWORD               addr;
550     unsigned            val;
551     long                offset;
552
553     if ((sym_info->Flags & (SYMFLAG_PARAMETER|SYMFLAG_FRAMEREL)) == (SYMFLAG_PARAMETER|SYMFLAG_FRAMEREL))
554     {
555         struct dbg_type     type;
556
557         if (se->tmp[0]) strcat(se->tmp, ", ");
558         addr = se->frame;
559         type.module = sym_info->ModBase;
560         type.id = sym_info->TypeIndex;
561         types_get_info(&type, TI_GET_OFFSET, &offset);
562         addr += offset;
563         if (dbg_read_memory((char*)addr, &val, sizeof(val)))
564             sprintf(se->tmp + strlen(se->tmp), "%s=0x%x", sym_info->Name, val);
565         else
566             sprintf(se->tmp + strlen(se->tmp), "%s=<\?\?\?>", sym_info->Name);
567     }
568     return TRUE;
569 }
570
571 void print_addr_and_args(const ADDRESS* pc, const ADDRESS* frame)
572 {
573     char                        buffer[sizeof(SYMBOL_INFO) + 256];
574     SYMBOL_INFO*                si = (SYMBOL_INFO*)buffer;
575     IMAGEHLP_STACK_FRAME        isf;
576     IMAGEHLP_LINE               il;
577     IMAGEHLP_MODULE             im;
578     DWORD64                     disp64;
579
580     print_bare_address(pc);
581
582     isf.InstructionOffset = (DWORD_PTR)memory_to_linear_addr(pc);
583     isf.FrameOffset       = (DWORD_PTR)memory_to_linear_addr(frame);
584
585     /* grab module where symbol is. If we don't have a module, we cannot print more */
586     im.SizeOfStruct = sizeof(im);
587     if (!SymGetModuleInfo(dbg_curr_process->handle, isf.InstructionOffset, &im))
588         return;
589
590     si->SizeOfStruct = sizeof(*si);
591     si->MaxNameLen   = 256;
592     if (SymFromAddr(dbg_curr_process->handle, isf.InstructionOffset, &disp64, si))
593     {
594         struct sym_enum se;
595         char            tmp[1024];
596         DWORD           disp;
597
598         dbg_printf(" %s", si->Name);
599         if (disp) dbg_printf("+0x%lx", (DWORD_PTR)disp64);
600
601         SymSetContext(dbg_curr_process->handle, &isf, NULL);
602         se.tmp = tmp;
603         se.frame = isf.FrameOffset;
604         tmp[0] = '\0';
605         SymEnumSymbols(dbg_curr_process->handle, 0, NULL, sym_enum_cb, &se);
606         if (tmp[0]) dbg_printf("(%s)", tmp);
607
608         il.SizeOfStruct = sizeof(il);
609         if (SymGetLineFromAddr(dbg_curr_process->handle, isf.InstructionOffset,
610                                &disp, &il))
611             dbg_printf(" [%s:%lu]", il.FileName, il.LineNumber);
612         dbg_printf(" in %s", im.ModuleName);
613     }
614     else dbg_printf(" in %s (+0x%lx)", 
615                     im.ModuleName, (DWORD_PTR)(isf.InstructionOffset - im.BaseOfImage));
616 }
617
618 BOOL memory_disasm_one_insn(ADDRESS* addr)
619 {
620     char        ch;
621
622     print_address(addr, TRUE);
623     dbg_printf(": ");
624     if (!dbg_read_memory(memory_to_linear_addr(addr), &ch, sizeof(ch)))
625     {
626         dbg_printf("-- no code accessible --\n");
627         return FALSE;
628     }
629     be_cpu->disasm_one_insn(addr, TRUE);
630     dbg_printf("\n");
631     return TRUE;
632 }
633
634 void memory_disassemble(const struct dbg_lvalue* xstart, 
635                         const struct dbg_lvalue* xend, int instruction_count)
636 {
637     static ADDRESS last = {0,0,0};
638     int stop = 0;
639     int i;
640
641     if (!xstart && !xend) 
642     {
643         if (!last.Segment && !last.Offset) memory_get_current_pc(&last);
644     }
645     else
646     {
647         if (xstart)
648         {
649             if (xstart->type.id == dbg_itype_none)
650             {
651                 be_cpu->build_addr(dbg_curr_thread->handle, &dbg_context,
652                                    &last, xstart->addr.Segment, xstart->addr.Offset);
653             }
654             else
655             {
656                 last.Mode = AddrModeFlat;
657                 last.Offset = types_extract_as_integer( xstart );
658             }
659         }
660         if (xend) 
661             stop = types_extract_as_integer(xend);
662     }
663     for (i = 0; (instruction_count == 0 || i < instruction_count)  &&
664                 (stop == 0 || last.Offset <= stop); i++)
665         memory_disasm_one_insn(&last);
666 }