winedbg: Added support for constant values passed by dbghelp.
[wine] / programs / winedbg / types.c
1 /*
2  * File types.c - datatype handling stuff for internal debugger.
3  *
4  * Copyright (C) 1997, Eric Youngdale.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Note: This really doesn't do much at the moment, but it forms the framework
21  * upon which full support for datatype handling will eventually be built.
22  */
23
24 #include "config.h"
25 #include <stdlib.h>
26
27 #include "debugger.h"
28 #include "wine/debug.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
31
32 /******************************************************************
33  *              types_get_real_type
34  *
35  * Get rid of any potential typedef in the lvalue's type to get
36  * to the 'real' type (the one we can work upon).
37  */
38 BOOL types_get_real_type(struct dbg_type* type, DWORD* tag)
39 {
40     if (type->id == dbg_itype_none) return FALSE;
41     do
42     {
43         if (!types_get_info(type, TI_GET_SYMTAG, tag))
44             return FALSE;
45         if (*tag != SymTagTypedef) return TRUE;
46     } while (types_get_info(type, TI_GET_TYPE, &type->id));
47     return FALSE;
48 }
49
50 /******************************************************************
51  *              types_extract_as_longlong
52  *
53  * Given a lvalue, try to get an integral (or pointer/address) value
54  * out of it
55  */
56 LONGLONG types_extract_as_longlong(const struct dbg_lvalue* lvalue)
57 {
58     LONGLONG            rtn;
59     DWORD               tag, bt;
60     DWORD64             size;
61     struct dbg_type     type = lvalue->type;
62
63     if (!types_get_real_type(&type, &tag))
64         RaiseException(DEBUG_STATUS_NOT_AN_INTEGER, 0, 0, NULL);
65
66     if (type.id == dbg_itype_segptr)
67     {
68         return (long int)memory_to_linear_addr(&lvalue->addr);
69     }
70
71     switch (tag)
72     {
73     case SymTagBaseType:
74         if (!types_get_info(&type, TI_GET_LENGTH, &size) ||
75             !types_get_info(&type, TI_GET_BASETYPE, &bt))
76         {
77             WINE_ERR("Couldn't get information\n");
78             RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL);
79         }
80         if (size > sizeof(rtn))
81         {
82             WINE_ERR("Size too large (%s)\n", wine_dbgstr_longlong(size));
83             RaiseException(DEBUG_STATUS_NOT_AN_INTEGER, 0, 0, NULL);
84         }
85         switch (bt)
86         {
87         case btChar:
88         case btInt:
89             if (!be_cpu->fetch_integer(lvalue, (unsigned)size, TRUE, &rtn))
90                 RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL);
91             break;
92         case btUInt:
93             if (!be_cpu->fetch_integer(lvalue, (unsigned)size, FALSE, &rtn))
94                 RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL);
95             break;
96         case btFloat:
97             RaiseException(DEBUG_STATUS_NOT_AN_INTEGER, 0, 0, NULL);
98         }
99         break;
100     case SymTagPointerType:
101         if (!be_cpu->fetch_integer(lvalue, sizeof(void*), FALSE, &rtn))
102             RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL);
103         break;
104     case SymTagArrayType:
105     case SymTagUDT:
106         if (!be_cpu->fetch_integer(lvalue, sizeof(unsigned), FALSE, &rtn))
107             RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL);
108         break;
109     case SymTagEnum:
110         /* FIXME: we don't handle enum size */
111         if (!be_cpu->fetch_integer(lvalue, sizeof(unsigned), FALSE, &rtn))
112             RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL);
113         break;
114     case SymTagFunctionType:
115         rtn = (unsigned)memory_to_linear_addr(&lvalue->addr);
116         break;
117     default:
118         WINE_FIXME("Unsupported tag %lu\n", tag);
119         RaiseException(DEBUG_STATUS_NOT_AN_INTEGER, 0, 0, NULL);
120         break;
121     }
122
123     return rtn;
124 }
125
126 /******************************************************************
127  *              types_extract_as_integer
128  *
129  * Given a lvalue, try to get an integral (or pointer/address) value
130  * out of it
131  */
132 long int types_extract_as_integer(const struct dbg_lvalue* lvalue)
133 {
134     return types_extract_as_longlong(lvalue);
135 }
136
137 /******************************************************************
138  *              types_extract_as_address
139  *
140  *
141  */
142 void types_extract_as_address(const struct dbg_lvalue* lvalue, ADDRESS64* addr)
143 {
144     if (lvalue->type.id == dbg_itype_segptr && lvalue->type.module == 0)
145     {
146         *addr = lvalue->addr;
147     }
148     else
149     {
150         addr->Mode = AddrModeFlat;
151         addr->Offset = types_extract_as_longlong( lvalue );
152     }
153 }
154
155 /******************************************************************
156  *              types_deref
157  *
158  */
159 BOOL types_deref(const struct dbg_lvalue* lvalue, struct dbg_lvalue* result)
160 {
161     struct dbg_type     type = lvalue->type;
162     DWORD               tag;
163
164     memset(result, 0, sizeof(*result));
165     result->type.id = dbg_itype_none;
166     result->type.module = 0;
167
168     /*
169      * Make sure that this really makes sense.
170      */
171     if (!types_get_real_type(&type, &tag) || tag != SymTagPointerType ||
172         !memory_read_value(lvalue, sizeof(result->addr.Offset), &result->addr.Offset) ||
173         !types_get_info(&type, TI_GET_TYPE, &result->type.id))
174         return FALSE;
175     result->type.module = type.module;
176     result->cookie = DLV_TARGET;
177     /* FIXME: this is currently buggy.
178      * there is no way to tell were the deref:ed value is...
179      * for example:
180      *  x is a pointer to struct s, x being on the stack
181      *          => lvalue is in debuggee, result is in debugger
182      *  x is a pointer to struct s, x being optimized into a reg
183      *          => lvalue is debugger, result is debuggee
184      *  x is a pointer to internal variable x
185      *          => lvalue is debugger, result is debuggee
186      * so we force debuggee address space, because dereferencing pointers to
187      * internal variables is very unlikely. A correct fix would be
188      * rather large.
189      */
190     result->addr.Mode = AddrModeFlat;
191     return TRUE;
192 }
193
194 /******************************************************************
195  *              types_get_udt_element_lvalue
196  *
197  * Implement a structure derefencement
198  */
199 static BOOL types_get_udt_element_lvalue(struct dbg_lvalue* lvalue, 
200                                          const struct dbg_type* type, long int* tmpbuf)
201 {
202     DWORD       offset, bitoffset;
203     DWORD       bt;
204     DWORD64     length;
205
206     unsigned    mask;
207
208     types_get_info(type, TI_GET_TYPE, &lvalue->type.id);
209     lvalue->type.module = type->module;
210     if (!types_get_info(type, TI_GET_OFFSET, &offset)) return FALSE;
211     lvalue->addr.Offset += offset;
212
213     if (types_get_info(type, TI_GET_BITPOSITION, &bitoffset))
214     {
215         types_get_info(type, TI_GET_LENGTH, &length);
216         /* FIXME: this test isn't sufficient, depending on start of bitfield
217          * (ie a 32 bit field can spread across 5 bytes)
218          */
219         if (length > 8 * sizeof(*tmpbuf)) return FALSE;
220         lvalue->addr.Offset += bitoffset >> 3;
221         /*
222          * Bitfield operation.  We have to extract the field and store
223          * it in a temporary buffer so that we get it all right.
224          */
225         if (!memory_read_value(lvalue, sizeof(*tmpbuf), tmpbuf)) return FALSE;
226         mask = 0xffffffff << (DWORD)length;
227         *tmpbuf >>= bitoffset & 7;
228         *tmpbuf &= ~mask;
229
230         lvalue->cookie      = DLV_HOST;
231         lvalue->addr.Offset = (DWORD)tmpbuf;
232
233         /*
234          * OK, now we have the correct part of the number.
235          * Check to see whether the basic type is signed or not, and if so,
236          * we need to sign extend the number.
237          */
238         if (types_get_info(&lvalue->type, TI_GET_BASETYPE, &bt) && 
239             bt == btInt && (*tmpbuf & (1 << ((DWORD)length - 1))))
240         {
241             *tmpbuf |= mask;
242         }
243     }
244     else
245     {
246         if (!memory_read_value(lvalue, sizeof(*tmpbuf), tmpbuf)) return FALSE;
247     }
248     return TRUE;
249 }
250
251 /******************************************************************
252  *              types_udt_find_element
253  *
254  */
255 BOOL types_udt_find_element(struct dbg_lvalue* lvalue, const char* name, long int* tmpbuf)
256 {
257     DWORD                       tag, count;
258     char                        buffer[sizeof(TI_FINDCHILDREN_PARAMS) + 256 * sizeof(DWORD)];
259     TI_FINDCHILDREN_PARAMS*     fcp = (TI_FINDCHILDREN_PARAMS*)buffer;
260     WCHAR*                      ptr;
261     char                        tmp[256];
262     int                         i;
263     struct dbg_type             type;
264
265     if (!types_get_info(&lvalue->type, TI_GET_SYMTAG, &tag) ||
266         tag != SymTagUDT)
267         return FALSE;
268
269     if (types_get_info(&lvalue->type, TI_GET_CHILDRENCOUNT, &count))
270     {
271         fcp->Start = 0;
272         while (count)
273         {
274             fcp->Count = min(count, 256);
275             if (types_get_info(&lvalue->type, TI_FINDCHILDREN, fcp))
276             {
277                 type.module = lvalue->type.module;
278                 for (i = 0; i < min(fcp->Count, count); i++)
279                 {
280                     ptr = NULL;
281                     type.id = fcp->ChildId[i];
282                     types_get_info(&type, TI_GET_SYMNAME, &ptr);
283                     if (!ptr) continue;
284                     WideCharToMultiByte(CP_ACP, 0, ptr, -1, tmp, sizeof(tmp), NULL, NULL);
285                     HeapFree(GetProcessHeap(), 0, ptr);
286                     if (strcmp(tmp, name)) continue;
287
288                     return types_get_udt_element_lvalue(lvalue, &type, tmpbuf);
289                 }
290             }
291             count -= min(count, 256);
292             fcp->Start += 256;
293         }
294     }
295     return FALSE;
296 }
297
298 /******************************************************************
299  *              types_array_index
300  *
301  * Grab an element from an array
302  */
303 BOOL types_array_index(const struct dbg_lvalue* lvalue, int index, 
304                        struct dbg_lvalue* result)
305 {
306     struct dbg_type     type = lvalue->type;
307     DWORD               tag, count;
308     DWORD64             length;
309
310     if (!types_get_real_type(&type, &tag)) return FALSE;
311     switch (tag)
312     {
313     case SymTagArrayType:
314         types_get_info(&type, TI_GET_COUNT, &count);
315         if (index < 0 || index >= count) return FALSE;
316         /* fall through */
317     case SymTagPointerType:
318         /* Contents of array share same data (addr mode, module...) */
319         *result = *lvalue;
320         /*
321          * Get the base type, so we know how much to index by.
322          */
323         types_get_info(&type, TI_GET_TYPE, &result->type.id);
324         types_get_info(&result->type, TI_GET_LENGTH, &length);
325         memory_read_value(lvalue, sizeof(result->addr.Offset), &result->addr.Offset);
326         result->addr.Offset += index * (DWORD)length;
327         break;
328     default:
329         assert(FALSE);
330     }
331     return TRUE;
332 }
333
334 struct type_find_t
335 {
336     unsigned long       result; /* out: the found type */
337     enum SymTagEnum     tag;    /* in: the tag to look for */
338     union
339     {
340         unsigned long           typeid; /* when tag is SymTagUDT */
341         const char*             name;   /* when tag is SymTagPointerType */
342     } u;
343 };
344
345 static BOOL CALLBACK types_cb(PSYMBOL_INFO sym, ULONG size, void* _user)
346 {
347     struct type_find_t* user = (struct type_find_t*)_user;
348     BOOL                ret = TRUE;
349     struct dbg_type     type;
350     DWORD               type_id;
351
352     if (sym->Tag == user->tag)
353     {
354         switch (user->tag)
355         {
356         case SymTagUDT:
357             if (!strcmp(user->u.name, sym->Name))
358             {
359                 user->result = sym->TypeIndex;
360                 ret = FALSE;
361             }
362             break;
363         case SymTagPointerType:
364             type.module = sym->ModBase;
365             type.id = sym->TypeIndex;
366             if (types_get_info(&type, TI_GET_TYPE, &type_id) && type_id == user->u.typeid)
367             {
368                 user->result = sym->TypeIndex;
369                 ret = FALSE;
370             }
371             break;
372         default: break;
373         }
374     }
375     return ret;
376 }
377
378 /******************************************************************
379  *              types_find_pointer
380  *
381  * Should look up in module based at linear whether (typeid*) exists
382  * Otherwise, we could create it locally
383  */
384 struct dbg_type types_find_pointer(const struct dbg_type* type)
385 {
386     struct type_find_t  f;
387     struct dbg_type     ret;
388
389     f.result = dbg_itype_none;
390     f.tag = SymTagPointerType;
391     f.u.typeid = type->id;
392     SymEnumTypes(dbg_curr_process->handle, type->module, types_cb, &f);
393     ret.module = type->module;
394     ret.id = f.result;
395     return ret;
396 }
397
398 /******************************************************************
399  *              types_find_type
400  *
401  * Should look up in the module based at linear address whether a type
402  * named 'name' and with the correct tag exists
403  */
404 struct dbg_type types_find_type(unsigned long linear, const char* name, enum SymTagEnum tag)
405
406 {
407     struct type_find_t  f;
408     struct dbg_type     ret;
409
410     f.result = dbg_itype_none;
411     f.tag = tag;
412     f.u.name = name;
413     SymEnumTypes(dbg_curr_process->handle, linear, types_cb, &f);
414     ret.module = linear;
415     ret.id = f.result;
416     return ret;
417 }
418
419 /***********************************************************************
420  *           print_value
421  *
422  * Implementation of the 'print' command.
423  */
424 void print_value(const struct dbg_lvalue* lvalue, char format, int level)
425 {
426     struct dbg_type     type = lvalue->type;
427     struct dbg_lvalue   lvalue_field;
428     int                 i;
429     DWORD               tag;
430     DWORD               count;
431     DWORD64             size;
432
433     if (!types_get_real_type(&type, &tag))
434     {
435         WINE_FIXME("---error\n");
436         return;
437     }
438
439     if (type.id == dbg_itype_none)
440     {
441         /* No type, just print the addr value */
442         print_bare_address(&lvalue->addr);
443         goto leave;
444     }
445
446     if (format == 'i' || format == 's' || format == 'w' || format == 'b' || format == 'g')
447     {
448         dbg_printf("Format specifier '%c' is meaningless in 'print' command\n", format);
449         format = '\0';
450     }
451
452     switch (tag)
453     {
454     case SymTagBaseType:
455     case SymTagEnum:
456     case SymTagPointerType:
457         /* FIXME: this in not 100% optimal (as we're going through the typedef handling
458          * stuff again
459          */
460         print_basic(lvalue, 1, format);
461         break;
462     case SymTagUDT:
463         if (types_get_info(&type, TI_GET_CHILDRENCOUNT, &count))
464         {
465             char                        buffer[sizeof(TI_FINDCHILDREN_PARAMS) + 256 * sizeof(DWORD)];
466             TI_FINDCHILDREN_PARAMS*     fcp = (TI_FINDCHILDREN_PARAMS*)buffer;
467             WCHAR*                      ptr;
468             char                        tmp[256];
469             long int                    tmpbuf;
470             struct dbg_type             sub_type;
471
472             dbg_printf("{");
473             fcp->Start = 0;
474             while (count)
475             {
476                 fcp->Count = min(count, 256);
477                 if (types_get_info(&type, TI_FINDCHILDREN, fcp))
478                 {
479                     for (i = 0; i < min(fcp->Count, count); i++)
480                     {
481                         ptr = NULL;
482                         sub_type.module = type.module;
483                         sub_type.id = fcp->ChildId[i];
484                         types_get_info(&sub_type, TI_GET_SYMNAME, &ptr);
485                         if (!ptr) continue;
486                         WideCharToMultiByte(CP_ACP, 0, ptr, -1, tmp, sizeof(tmp), NULL, NULL);
487                         dbg_printf("%s=", tmp);
488                         HeapFree(GetProcessHeap(), 0, ptr);
489                         lvalue_field = *lvalue;
490                         if (types_get_udt_element_lvalue(&lvalue_field, &sub_type, &tmpbuf))
491                         {
492                             print_value(&lvalue_field, format, level + 1);
493                         }
494                         if (i < min(fcp->Count, count) - 1 || count > 256) dbg_printf(", ");
495                     }
496                 }
497                 count -= min(count, 256);
498                 fcp->Start += 256;
499             }
500             dbg_printf("}");
501         }
502         break;
503     case SymTagArrayType:
504         /*
505          * Loop over all of the entries, printing stuff as we go.
506          */
507         count = 1; size = 1;
508         types_get_info(&type, TI_GET_COUNT, &count);
509         types_get_info(&type, TI_GET_LENGTH, &size);
510
511         if (size == count)
512         {
513             unsigned    len;
514             char        buffer[256];
515             /*
516              * Special handling for character arrays.
517              */
518             /* FIXME should check basic type here (should be a char!!!!)... */
519             len = min(count, sizeof(buffer));
520             memory_get_string(dbg_curr_process,
521                               memory_to_linear_addr(&lvalue->addr),
522                               lvalue->cookie == DLV_TARGET, TRUE, buffer, len);
523             dbg_printf("\"%s%s\"", buffer, (len < count) ? "..." : "");
524             break;
525         }
526         lvalue_field = *lvalue;
527         types_get_info(&type, TI_GET_TYPE, &lvalue_field.type.id);
528         dbg_printf("{");
529         for (i = 0; i < count; i++)
530         {
531             print_value(&lvalue_field, format, level + 1);
532             lvalue_field.addr.Offset += size / count;
533             dbg_printf((i == count - 1) ? "}" : ", ");
534         }
535         break;
536     case SymTagFunctionType:
537         dbg_printf("Function ");
538         print_bare_address(&lvalue->addr);
539         dbg_printf(": ");
540         types_print_type(&type, FALSE);
541         break;
542     case SymTagTypedef:
543         lvalue_field = *lvalue;
544         types_get_info(&lvalue->type, TI_GET_TYPE, &lvalue_field.type.id);
545         print_value(&lvalue_field, format, level);
546         break;
547     default:
548         WINE_FIXME("Unknown tag (%lu)\n", tag);
549         RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL);
550         break;
551     }
552
553 leave:
554
555     if (level == 0) dbg_printf("\n");
556 }
557
558 static BOOL CALLBACK print_types_cb(PSYMBOL_INFO sym, ULONG size, void* ctx)
559 {
560     struct dbg_type     type;
561     type.module = sym->ModBase;
562     type.id = sym->TypeIndex;
563     dbg_printf("Mod: %08lx ID: %08lx \n", type.module, type.id);
564     types_print_type(&type, TRUE);
565     dbg_printf("\n");
566     return TRUE;
567 }
568
569 static BOOL CALLBACK print_types_mod_cb(PSTR mod_name, DWORD base, void* ctx)
570 {
571     return SymEnumTypes(dbg_curr_process->handle, base, print_types_cb, ctx);
572 }
573
574 int print_types(void)
575 {
576     SymEnumerateModules(dbg_curr_process->handle, print_types_mod_cb, NULL);
577     return 0;
578 }
579
580 int types_print_type(const struct dbg_type* type, BOOL details)
581 {
582     WCHAR*              ptr;
583     char                tmp[256];
584     const char*         name;
585     DWORD               tag, udt, count;
586     struct dbg_type     subtype;
587
588     if (type->id == dbg_itype_none || !types_get_info(type, TI_GET_SYMTAG, &tag))
589     {
590         dbg_printf("--invalid--<%lxh>--", type->id);
591         return FALSE;
592     }
593
594     if (types_get_info(type, TI_GET_SYMNAME, &ptr) && ptr)
595     {
596         WideCharToMultiByte(CP_ACP, 0, ptr, -1, tmp, sizeof(tmp), NULL, NULL);
597         name = tmp;
598         HeapFree(GetProcessHeap(), 0, ptr);
599     }
600     else name = "--none--";
601
602     switch (tag)
603     {
604     case SymTagBaseType:
605         if (details) dbg_printf("Basic<%s>", name); else dbg_printf("%s", name);
606         break;
607     case SymTagPointerType:
608         types_get_info(type, TI_GET_TYPE, &subtype.id);
609         subtype.module = type->module;
610         types_print_type(&subtype, FALSE);
611         dbg_printf("*");
612         break;
613     case SymTagUDT:
614         types_get_info(type, TI_GET_UDTKIND, &udt);
615         switch (udt)
616         {
617         case UdtStruct: dbg_printf("struct %s", name); break;
618         case UdtUnion:  dbg_printf("union %s", name); break;
619         case UdtClass:  dbg_printf("class %s", name); break;
620         default:        WINE_ERR("Unsupported UDT type (%ld) for %s\n", udt, name); break;
621         }
622         if (details &&
623             types_get_info(type, TI_GET_CHILDRENCOUNT, &count))
624         {
625             char                        buffer[sizeof(TI_FINDCHILDREN_PARAMS) + 256 * sizeof(DWORD)];
626             TI_FINDCHILDREN_PARAMS*     fcp = (TI_FINDCHILDREN_PARAMS*)buffer;
627             WCHAR*                      ptr;
628             char                        tmp[256];
629             int                         i;
630             struct dbg_type             type_elt;
631             dbg_printf(" {");
632
633             fcp->Start = 0;
634             while (count)
635             {
636                 fcp->Count = min(count, 256);
637                 if (types_get_info(type, TI_FINDCHILDREN, fcp))
638                 {
639                     for (i = 0; i < min(fcp->Count, count); i++)
640                     {
641                         ptr = NULL;
642                         type_elt.module = type->module;
643                         type_elt.id = fcp->ChildId[i];
644                         types_get_info(&type_elt, TI_GET_SYMNAME, &ptr);
645                         if (!ptr) continue;
646                         WideCharToMultiByte(CP_ACP, 0, ptr, -1, tmp, sizeof(tmp), NULL, NULL);
647                         HeapFree(GetProcessHeap(), 0, ptr);
648                         dbg_printf("%s", tmp);
649                         if (types_get_info(&type_elt, TI_GET_TYPE, &type_elt.id))
650                         {
651                             dbg_printf(":");
652                             types_print_type(&type_elt, details);
653                         }
654                         if (i < min(fcp->Count, count) - 1 || count > 256) dbg_printf(", ");
655                     }
656                 }
657                 count -= min(count, 256);
658                 fcp->Start += 256;
659             }
660             dbg_printf("}");
661         }
662         break;
663     case SymTagArrayType:
664         types_get_info(type, TI_GET_TYPE, &subtype.id);
665         subtype.module = type->module;
666         types_print_type(&subtype, details);
667         dbg_printf(" %s[]", name);
668         break;
669     case SymTagEnum:
670         dbg_printf("enum %s", name);
671         break;
672     case SymTagFunctionType:
673         types_get_info(type, TI_GET_TYPE, &subtype.id);
674         subtype.module = type->module;
675         types_print_type(&subtype, FALSE);
676         dbg_printf(" (*%s)(", name);
677         if (types_get_info(type, TI_GET_CHILDRENCOUNT, &count))
678         {
679             char                        buffer[sizeof(TI_FINDCHILDREN_PARAMS) + 256 * sizeof(DWORD)];
680             TI_FINDCHILDREN_PARAMS*     fcp = (TI_FINDCHILDREN_PARAMS*)buffer;
681             int                         i;
682
683             fcp->Start = 0;
684             while (count)
685             {
686                 fcp->Count = min(count, 256);
687                 if (types_get_info(type, TI_FINDCHILDREN, fcp))
688                 {
689                     for (i = 0; i < min(fcp->Count, count); i++)
690                     {
691                         subtype.id = fcp->ChildId[i];
692                         types_get_info(&subtype, TI_GET_TYPE, &subtype.id);
693                         types_print_type(&subtype, FALSE);
694                         if (i < min(fcp->Count, count) - 1 || count > 256) dbg_printf(", ");
695                     }
696                 }
697                 count -= min(count, 256);
698                 fcp->Start += 256;
699             }
700         }
701         dbg_printf(")");
702         break;
703     case SymTagTypedef:
704         dbg_printf(name);
705         break;
706     default:
707         WINE_ERR("Unknown type %lu for %s\n", tag, name);
708         break;
709     }
710     
711     return TRUE;
712 }
713
714 /* helper to typecast pInfo to its expected type (_t) */
715 #define X(_t) (*((_t*)pInfo))
716
717 BOOL types_get_info(const struct dbg_type* type, IMAGEHLP_SYMBOL_TYPE_INFO ti, void* pInfo)
718 {
719     if (type->id == dbg_itype_none) return FALSE;
720     if (type->module != 0)
721     {
722         DWORD ret, tag, bt;
723         ret = SymGetTypeInfo(dbg_curr_process->handle, type->module, type->id, ti, pInfo);
724         if (!ret &&
725             SymGetTypeInfo(dbg_curr_process->handle, type->module, type->id, TI_GET_SYMTAG, &tag) &&
726             tag == SymTagBaseType &&
727             SymGetTypeInfo(dbg_curr_process->handle, type->module, type->id, TI_GET_BASETYPE, &bt))
728         {
729             static const WCHAR voidW[] = {'v','o','i','d','\0'};
730             static const WCHAR charW[] = {'c','h','a','r','\0'};
731             static const WCHAR wcharW[] = {'W','C','H','A','R','\0'};
732             static const WCHAR intW[] = {'i','n','t','\0'};
733             static const WCHAR uintW[] = {'u','n','s','i','g','n','e','d',' ','i','n','t','\0'};
734             static const WCHAR floatW[] = {'f','l','o','a','t','\0'};
735             static const WCHAR boolW[] = {'b','o','o','l','\0'};
736             static const WCHAR longW[] = {'l','o','n','g',' ','i','n','t','\0'};
737             static const WCHAR ulongW[] = {'u','n','s','i','g','n','e','d',' ','l','o','n','g',' ','i','n','t','\0'};
738             static const WCHAR complexW[] = {'c','o','m','p','l','e','x','\0'};
739             const WCHAR* name = NULL;
740
741             switch (bt)
742             {
743             case btVoid:        name = voidW; break;
744             case btChar:        name = charW; break;
745             case btWChar:       name = wcharW; break;
746             case btInt:         name = intW; break;
747             case btUInt:        name = uintW; break;
748             case btFloat:       name = floatW; break;
749             case btBool:        name = boolW; break;
750             case btLong:        name = longW; break;
751             case btULong:       name = ulongW; break;
752             case btComplex:     name = complexW; break;
753             default:            WINE_FIXME("Unsupported basic type %ld\n", bt); return FALSE;
754             }
755             X(WCHAR*) = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(name) + 1) * sizeof(WCHAR));
756             if (X(WCHAR*))
757             {
758                 lstrcpyW(X(WCHAR*), name);
759                 ret = TRUE;
760             }
761         }
762         return ret;
763     }
764
765     assert(type->id >= dbg_itype_first);
766
767     switch (type->id)
768     {
769     case dbg_itype_unsigned_int:
770         switch (ti)
771         {
772         case TI_GET_SYMTAG:     X(DWORD)   = SymTagBaseType; break;
773         case TI_GET_LENGTH:     X(DWORD64) = 4; break;
774         case TI_GET_BASETYPE:   X(DWORD)   = btUInt; break;
775         default: WINE_FIXME("unsupported %u for u-int\n", ti); return FALSE;
776         }
777         break;
778     case dbg_itype_signed_int:
779         switch (ti)
780         {
781         case TI_GET_SYMTAG:     X(DWORD)   = SymTagBaseType; break;
782         case TI_GET_LENGTH:     X(DWORD64) = 4; break;
783         case TI_GET_BASETYPE:   X(DWORD)   = btInt; break;
784         default: WINE_FIXME("unsupported %u for s-int\n", ti); return FALSE;
785         }
786         break;
787     case dbg_itype_unsigned_short_int:
788         switch (ti)
789         {
790         case TI_GET_SYMTAG:     X(DWORD)   = SymTagBaseType; break;
791         case TI_GET_LENGTH:     X(DWORD64) = 2; break;
792         case TI_GET_BASETYPE:   X(DWORD)   = btUInt; break;
793         default: WINE_FIXME("unsupported %u for u-short int\n", ti); return FALSE;
794         }
795         break;
796     case dbg_itype_signed_short_int:
797         switch (ti)
798         {
799         case TI_GET_SYMTAG:     X(DWORD)   = SymTagBaseType; break;
800         case TI_GET_LENGTH:     X(DWORD64) = 2; break;
801         case TI_GET_BASETYPE:   X(DWORD)   = btInt; break;
802         default: WINE_FIXME("unsupported %u for s-short int\n", ti); return FALSE;
803         }
804         break;
805     case dbg_itype_unsigned_char_int:
806         switch (ti)
807         {
808         case TI_GET_SYMTAG:     X(DWORD)   = SymTagBaseType; break;
809         case TI_GET_LENGTH:     X(DWORD64) = 1; break;
810         case TI_GET_BASETYPE:   X(DWORD)   = btUInt; break;
811         default: WINE_FIXME("unsupported %u for u-char int\n", ti); return FALSE;
812         }
813         break;
814     case dbg_itype_signed_char_int:
815         switch (ti)
816         {
817         case TI_GET_SYMTAG:     X(DWORD)   = SymTagBaseType; break;
818         case TI_GET_LENGTH:     X(DWORD64) = 1; break;
819         case TI_GET_BASETYPE:   X(DWORD)   = btInt; break;
820         default: WINE_FIXME("unsupported %u for s-char int\n", ti); return FALSE;
821         }
822         break;
823     case dbg_itype_char:
824         switch (ti)
825         {
826         case TI_GET_SYMTAG:     X(DWORD)   = SymTagBaseType; break;
827         case TI_GET_LENGTH:     X(DWORD64) = 1; break;
828         case TI_GET_BASETYPE:   X(DWORD)   = btChar; break;
829         default: WINE_FIXME("unsupported %u for char int\n", ti); return FALSE;
830         }
831         break;
832     case dbg_itype_astring:
833         switch (ti)
834         {
835         case TI_GET_SYMTAG:     X(DWORD)   = SymTagPointerType; break;
836         case TI_GET_LENGTH:     X(DWORD64) = 4; break;
837         case TI_GET_TYPE:       X(DWORD)   = dbg_itype_char; break;
838         default: WINE_FIXME("unsupported %u for a string\n", ti); return FALSE;
839         }
840         break;
841     case dbg_itype_segptr:
842         switch (ti)
843         {
844         case TI_GET_SYMTAG:     X(DWORD)   = SymTagBaseType; break;
845         case TI_GET_LENGTH:     X(DWORD64) = 4; break;
846         case TI_GET_BASETYPE:   X(DWORD)   = btInt; break;
847         default: WINE_FIXME("unsupported %u for seg-ptr\n", ti); return FALSE;
848         }
849         break;
850     default: WINE_FIXME("unsupported type id 0x%lx\n", type->id);
851     }
852
853 #undef X
854     return TRUE;
855 }