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