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