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