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