Use correct notification for drive selection change.
[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     DWORD       os;
123
124     os = ~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     DWORD               tag, size, count, bt;
291     struct dbg_type     rtype;
292
293     if (lvalue->type.id == dbg_itype_none ||
294         !types_get_info(&lvalue->type, TI_GET_SYMTAG, &tag))
295         return;
296
297     switch (tag)
298     {
299     case SymTagBaseType:
300         if (!types_get_info(&lvalue->type, TI_GET_LENGTH, &size) ||
301             !types_get_info(&lvalue->type, TI_GET_BASETYPE, &bt))
302         {
303             WINE_ERR("Couldn't get information\n");
304             RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL);
305         }
306
307         switch (bt)
308         {
309         case btInt:
310             if (!be_cpu->fetch_integer(lvalue, size, TRUE, &val_int)) return;
311             dbg_printf("%lld", val_int);
312             break;
313         case btUInt:
314             if (!be_cpu->fetch_integer(lvalue, size, FALSE, &val_int)) return;
315             dbg_printf("%llu", val_int);
316             break;
317         case btFloat:
318             if (!be_cpu->fetch_float(lvalue, size, &val_real)) return;
319             dbg_printf("%Lf", val_real);
320             break;
321         case btChar:
322             if (!be_cpu->fetch_integer(lvalue, size, TRUE, &val_int)) return;
323             /* FIXME: should do the same for a Unicode character (size == 2) */
324             if (size == 1 && (val_int < 0x20 || val_int > 0x80))
325                 dbg_printf("%d", (int)val_int);
326             else
327                 dbg_printf("'%c'", (char)val_int);
328             break;
329         default:
330             WINE_FIXME("Unsupported basetype %lu\n", bt);
331             break;
332         }
333         break;
334     case SymTagPointerType:
335         if (!memory_read_value(lvalue, sizeof(void*), &val_ptr)) return;
336
337         if (!types_get_info(&lvalue->type, TI_GET_TYPE, &rtype.id) ||
338             rtype.id == dbg_itype_none)
339         {
340             dbg_printf("Internal symbol error: unable to access memory location %p", val_ptr);
341             break;
342         }
343         rtype.module = lvalue->type.module;
344         if (types_get_info(&rtype, TI_GET_SYMTAG, &tag) && tag == SymTagBaseType &&
345             types_get_info(&rtype, TI_GET_BASETYPE, &bt) && bt == btChar &&
346             types_get_info(&rtype, TI_GET_LENGTH, &size))
347         {
348             char    buffer[1024];
349
350             if (!val_ptr) dbg_printf("0x0");
351             else if (memory_get_string(dbg_curr_process, val_ptr, 
352                                        lvalue->cookie == DLV_TARGET,
353                                        size == 2, buffer, sizeof(buffer)))
354                 dbg_printf("\"%s\"", buffer);
355             else
356                 dbg_printf("*** invalid address %p ***", val_ptr);
357         }
358         else dbg_printf("%p", val_ptr);
359         break;
360     case SymTagArrayType:
361     case SymTagUDT:
362         assert(lvalue->cookie == DLV_TARGET);
363         if (!memory_read_value(lvalue, sizeof(val_ptr), &val_ptr)) return;
364         dbg_printf("%p", val_ptr);
365         break;
366     case SymTagEnum:
367         {
368             BOOL        ok = FALSE;
369
370             assert(lvalue->cookie == DLV_TARGET);
371             /* FIXME: it depends on underlying type for enums 
372              * (not supported yet in dbghelp)
373              * Assuming 4 as for an int
374              */
375             if (!be_cpu->fetch_integer(lvalue, 4, TRUE, &val_int)) return;
376
377             if (types_get_info(&lvalue->type, TI_GET_CHILDRENCOUNT, &count))
378             {
379                 char                    buffer[sizeof(TI_FINDCHILDREN_PARAMS) + 256 * sizeof(DWORD)];
380                 TI_FINDCHILDREN_PARAMS* fcp = (TI_FINDCHILDREN_PARAMS*)buffer;
381                 WCHAR*                  ptr;
382                 char                    tmp[256];
383                 VARIANT                 variant;
384                 int                     i;
385                 struct dbg_type         type;
386
387                 fcp->Start = 0;
388                 while (count)
389                 {
390                     fcp->Count = min(count, 256);
391                     if (types_get_info(&lvalue->type, TI_FINDCHILDREN, fcp))
392                     {
393                         type.module = lvalue->type.module;
394                         for (i = 0; i < min(fcp->Count, count); i++)
395                         {
396                             type.id = fcp->ChildId[i];
397                             if (!types_get_info(&type, TI_GET_VALUE, &variant)) 
398                                 continue;
399                             switch (variant.n1.n2.vt)
400                             {
401                             case VT_I4: ok = (val_int == variant.n1.n2.n3.lVal); break;
402                             default: WINE_FIXME("Unsupported variant type (%u)\n", variant.n1.n2.vt);
403                             }
404                             if (ok)
405                             {
406                                 ptr = NULL;
407                                 types_get_info(&type, TI_GET_SYMNAME, &ptr);
408                                 if (!ptr) continue;
409                                 WideCharToMultiByte(CP_ACP, 0, ptr, -1, tmp, sizeof(tmp), NULL, NULL);
410                                 HeapFree(GetProcessHeap(), 0, ptr);
411                                 dbg_printf("%s", tmp);
412                                 count = 0; /* so that we'll get away from outter loop */
413                                 break;
414                             }
415                         }
416                     }
417                 }
418                 count -= min(count, 256);
419                 fcp->Start += 256;
420             }
421             if (!ok) dbg_printf("%lld", val_int);
422         }
423         break;
424     default:
425         WINE_FIXME("Unsupported tag %lu\n", tag);
426         break;
427     }
428 }
429
430 /***********************************************************************
431  *           print_basic
432  *
433  * Implementation of the 'print' command.
434  */
435 void print_basic(const struct dbg_lvalue* lvalue, int count, char format)
436 {
437     long int    res;
438
439     if (lvalue->type.id == dbg_itype_none)
440     {
441         dbg_printf("Unable to evaluate expression\n");
442         return;
443     }
444
445     res = types_extract_as_integer(lvalue);
446
447     /* FIXME: this implies i386 byte ordering */
448     switch (format)
449     {
450     case 'x':
451         if (lvalue->addr.Mode != AddrModeFlat)
452             dbg_printf("0x%04lx", res);
453         else
454             dbg_printf("0x%08lx", res);
455         break;
456
457     case 'd':
458         dbg_printf("%ld\n", res);
459         break;
460
461     case 'c':
462         dbg_printf("%d = '%c'", (char)(res & 0xff), (char)(res & 0xff));
463         break;
464
465     case 'u':
466         {
467             WCHAR wch = (WCHAR)(res & 0xFFFF);
468             dbg_printf("%d = '", wch);
469             dbg_outputW(&wch, 1);
470             dbg_printf("'");
471         }
472         break;
473
474     case 'i':
475     case 's':
476     case 'w':
477     case 'b':
478         dbg_printf("Format specifier '%c' is meaningless in 'print' command\n", format);
479     case 0:
480         print_typed_basic(lvalue);
481         break;
482     }
483 }
484
485 void print_bare_address(const ADDRESS* addr)
486 {
487     switch (addr->Mode)
488     {
489     case AddrModeFlat: 
490         dbg_printf("0x%08lx", addr->Offset); 
491         break;
492     case AddrModeReal:
493     case AddrMode1616:
494         dbg_printf("0x%04x:0x%04lx", addr->Segment, addr->Offset);
495         break;
496     case AddrMode1632:
497         dbg_printf("0x%04x:0x%08lx", addr->Segment, addr->Offset);
498         break;
499     default:
500         dbg_printf("Unknown mode %x\n", addr->Mode);
501         break;
502     }
503 }
504
505 /***********************************************************************
506  *           print_address
507  *
508  * Print an 16- or 32-bit address, with the nearest symbol if any.
509  */
510 void print_address(const ADDRESS* addr, BOOLEAN with_line)
511 {
512     char                buffer[sizeof(SYMBOL_INFO) + 256];
513     SYMBOL_INFO*        si = (SYMBOL_INFO*)buffer;
514     void*               lin = memory_to_linear_addr(addr);
515     DWORD64             disp64;
516     DWORD               disp;
517
518     print_bare_address(addr);
519
520     si->SizeOfStruct = sizeof(*si);
521     si->MaxNameLen   = 256;
522     if (!SymFromAddr(dbg_curr_process->handle, (DWORD_PTR)lin, &disp64, si)) return;
523     dbg_printf(" %s", si->Name);
524     if (disp64) dbg_printf("+0x%lx", (DWORD_PTR)disp64);
525     if (with_line)
526     {
527         IMAGEHLP_LINE               il;
528         IMAGEHLP_MODULE             im;
529
530         il.SizeOfStruct = sizeof(il);
531         if (SymGetLineFromAddr(dbg_curr_process->handle, (DWORD_PTR)lin, &disp, &il))
532             dbg_printf(" [%s:%lu]", il.FileName, il.LineNumber);
533         im.SizeOfStruct = sizeof(im);
534         if (SymGetModuleInfo(dbg_curr_process->handle, (DWORD_PTR)lin, &im))
535             dbg_printf(" in %s", im.ModuleName);
536     }
537 }
538
539 struct sym_enum
540 {
541     char*       tmp;
542     DWORD       frame;
543 };
544
545 static BOOL WINAPI sym_enum_cb(SYMBOL_INFO* sym_info, ULONG size, void* user)
546 {
547     struct sym_enum*    se = (struct sym_enum*)user;
548     DWORD               addr;
549     unsigned            val;
550     long                offset;
551
552     if ((sym_info->Flags & (SYMFLAG_PARAMETER|SYMFLAG_FRAMEREL)) == (SYMFLAG_PARAMETER|SYMFLAG_FRAMEREL))
553     {
554         struct dbg_type     type;
555
556         if (se->tmp[0]) strcat(se->tmp, ", ");
557         addr = se->frame;
558         type.module = sym_info->ModBase;
559         type.id = sym_info->TypeIndex;
560         types_get_info(&type, TI_GET_OFFSET, &offset);
561         addr += offset;
562         if (dbg_read_memory((char*)addr, &val, sizeof(val)))
563             sprintf(se->tmp + strlen(se->tmp), "%s=0x%x", sym_info->Name, val);
564         else
565             sprintf(se->tmp + strlen(se->tmp), "%s=<\?\?\?>", sym_info->Name);
566     }
567     return TRUE;
568 }
569
570 void print_addr_and_args(const ADDRESS* pc, const ADDRESS* frame)
571 {
572     char                        buffer[sizeof(SYMBOL_INFO) + 256];
573     SYMBOL_INFO*                si = (SYMBOL_INFO*)buffer;
574     IMAGEHLP_STACK_FRAME        isf;
575     IMAGEHLP_LINE               il;
576     IMAGEHLP_MODULE             im;
577     DWORD64                     disp64;
578
579     print_bare_address(pc);
580
581     isf.InstructionOffset = (DWORD_PTR)memory_to_linear_addr(pc);
582     isf.FrameOffset       = (DWORD_PTR)memory_to_linear_addr(frame);
583
584     /* grab module where symbol is. If we don't have a module, we cannot print more */
585     im.SizeOfStruct = sizeof(im);
586     if (!SymGetModuleInfo(dbg_curr_process->handle, isf.InstructionOffset, &im))
587         return;
588
589     si->SizeOfStruct = sizeof(*si);
590     si->MaxNameLen   = 256;
591     if (SymFromAddr(dbg_curr_process->handle, isf.InstructionOffset, &disp64, si))
592     {
593         struct sym_enum se;
594         char            tmp[1024];
595         DWORD           disp;
596
597         dbg_printf(" %s", si->Name);
598         if (disp) dbg_printf("+0x%lx", (DWORD_PTR)disp64);
599
600         SymSetContext(dbg_curr_process->handle, &isf, NULL);
601         se.tmp = tmp;
602         se.frame = isf.FrameOffset;
603         tmp[0] = '\0';
604         SymEnumSymbols(dbg_curr_process->handle, 0, NULL, sym_enum_cb, &se);
605         if (tmp[0]) dbg_printf("(%s)", tmp);
606
607         il.SizeOfStruct = sizeof(il);
608         if (SymGetLineFromAddr(dbg_curr_process->handle, isf.InstructionOffset,
609                                &disp, &il))
610             dbg_printf(" [%s:%lu]", il.FileName, il.LineNumber);
611         dbg_printf(" in %s", im.ModuleName);
612     }
613     else dbg_printf(" in %s (+0x%lx)", 
614                     im.ModuleName, (DWORD_PTR)(isf.InstructionOffset - im.BaseOfImage));
615 }
616
617 BOOL memory_disasm_one_insn(ADDRESS* addr)
618 {
619     char        ch;
620
621     print_address(addr, TRUE);
622     dbg_printf(": ");
623     if (!dbg_read_memory(memory_to_linear_addr(addr), &ch, sizeof(ch)))
624     {
625         dbg_printf("-- no code accessible --\n");
626         return FALSE;
627     }
628     be_cpu->disasm_one_insn(addr, TRUE);
629     dbg_printf("\n");
630     return TRUE;
631 }
632
633 void memory_disassemble(const struct dbg_lvalue* xstart, 
634                         const struct dbg_lvalue* xend, int instruction_count)
635 {
636     static ADDRESS last = {0,0,0};
637     int stop = 0;
638     int i;
639
640     if (!xstart && !xend) 
641     {
642         if (!last.Segment && !last.Offset) memory_get_current_pc(&last);
643     }
644     else
645     {
646         if (xstart)
647         {
648             if (xstart->type.id == dbg_itype_none)
649             {
650                 be_cpu->build_addr(dbg_curr_thread->handle, &dbg_context,
651                                    &last, xstart->addr.Segment, xstart->addr.Offset);
652             }
653             else
654             {
655                 last.Mode = AddrModeFlat;
656                 last.Offset = types_extract_as_integer( xstart );
657             }
658         }
659         if (xend) 
660             stop = types_extract_as_integer(xend);
661     }
662     for (i = 0; (instruction_count == 0 || i < instruction_count)  &&
663                 (stop == 0 || last.Offset <= stop); i++)
664         memory_disasm_one_insn(&last);
665 }