winedbg: Don't assert on some lvalue's write conditions.
[wine] / programs / winedbg / symbol.c
1 /*
2  * Generate hash tables for Wine debugger symbols
3  *
4  * Copyright (C) 1993, Eric Youngdale.
5  *               2004-2005, Eric Pouech.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #define NONAMELESSUNION
23 #define NONAMELESSSTRUCT
24
25 #include "config.h"
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29
30 #include "debugger.h"
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
34
35 static BOOL symbol_get_debug_start(const struct dbg_type* func, ULONG64* start)
36 {
37     DWORD                       count, tag;
38     char                        buffer[sizeof(TI_FINDCHILDREN_PARAMS) + 256 * sizeof(DWORD)];
39     TI_FINDCHILDREN_PARAMS*     fcp = (TI_FINDCHILDREN_PARAMS*)buffer;
40     int                         i;
41     struct dbg_type             child;
42
43     if (!func->id) return FALSE; /* native dbghelp not always fills the info field */
44
45     if (!types_get_info(func, TI_GET_CHILDRENCOUNT, &count)) return FALSE;
46     fcp->Start = 0;
47     while (count)
48     {
49         fcp->Count = min(count, 256);
50         if (types_get_info(func, TI_FINDCHILDREN, fcp))
51         {
52             for (i = 0; i < min(fcp->Count, count); i++)
53             {
54                 child.module = func->module;
55                 child.id = fcp->ChildId[i];
56                 types_get_info(&child, TI_GET_SYMTAG, &tag);
57                 if (tag != SymTagFuncDebugStart) continue;
58                 return types_get_info(&child, TI_GET_ADDRESS, start);
59             }
60             count -= min(count, 256);
61             fcp->Start += 256;
62             fcp->Start += 256;
63         }
64     }
65     return FALSE;
66 }
67
68 static BOOL fill_sym_lvalue(const SYMBOL_INFO* sym, ULONG_PTR base,
69                             struct dbg_lvalue* lvalue, char* buffer, size_t sz)
70 {
71     if (buffer) buffer[0] = '\0';
72     if (sym->Flags & SYMFLAG_REGISTER)
73     {
74         DWORD_PTR* pval;
75
76         if (!memory_get_register(sym->Register, &pval, buffer, sz))
77             return FALSE;
78         lvalue->cookie = DLV_HOST;
79         lvalue->addr.Offset = (DWORD_PTR)pval;
80     }
81     else if (sym->Flags & SYMFLAG_REGREL)
82     {
83         DWORD_PTR* pval;
84
85         if (!memory_get_register(sym->Register, &pval, buffer, sz))
86             return FALSE;
87         lvalue->cookie = DLV_TARGET;
88         lvalue->addr.Offset = (ULONG64)*pval + sym->Address;
89     }
90     else if (sym->Flags & SYMFLAG_VALUEPRESENT)
91     {
92         struct dbg_type type;
93         VARIANT         v;
94
95         type.module = sym->ModBase;
96         type.id = sym->info;
97
98         if (!types_get_info(&type, TI_GET_VALUE, &v))
99         {
100             if (buffer) snprintf(buffer, sz, "Couldn't get full value information for %s", sym->Name);
101             return FALSE;
102         }
103         else if (v.n1.n2.vt & VT_BYREF)
104         {
105             /* FIXME: this won't work for pointers or arrays, as we don't always
106              * know, if the value to be dereferenced lies in debuggee or
107              * debugger address space.
108              */
109             if (sym->Tag == SymTagPointerType || sym->Tag == SymTagArrayType)
110             {
111                 if (buffer) snprintf(buffer, sz, "Couldn't dereference pointer for const value for %s", sym->Name);
112                 return FALSE;
113             }
114             /* this is likely Wine's dbghelp which passes const values by reference
115              * (object is managed by dbghelp, hence in debugger address space)
116              */
117             lvalue->cookie = DLV_HOST;
118             lvalue->addr.Offset = (DWORD_PTR)sym->Value;
119         }
120         else
121         {
122             DWORD* pdw = (DWORD*)lexeme_alloc_size(sizeof(*pdw));
123             lvalue->cookie = DLV_HOST;
124             lvalue->addr.Offset = (DWORD_PTR)pdw;
125             *pdw = sym->Value;
126         }
127     }
128     else if (sym->Flags & SYMFLAG_LOCAL)
129     {
130         lvalue->cookie = DLV_TARGET;
131         lvalue->addr.Offset = base + sym->Address;
132     }
133     else
134     {
135         lvalue->cookie = DLV_TARGET;
136         lvalue->addr.Offset = sym->Address;
137     }
138     lvalue->addr.Mode = AddrModeFlat;
139     lvalue->type.module = sym->ModBase;
140     lvalue->type.id = sym->TypeIndex;
141
142     return TRUE;
143 }
144
145 struct sgv_data
146 {
147 #define NUMDBGV                 100
148     struct
149     {
150         /* FIXME: NUMDBGV should be made variable */
151         struct dbg_lvalue               lvalue;
152         DWORD                           flags;
153         DWORD                           sym_info;
154     }                           syms[NUMDBGV];  /* out     : will be filled in with various found symbols */
155     int                         num;            /* out     : number of found symbols */
156     int                         num_thunks;     /* out     : number of thunks found */
157     const char*                 name;           /* in      : name of symbol to look up */
158     unsigned                    do_thunks : 1;  /* in      : whether we return thunks tags */
159     ULONG64                     frame_offset;   /* in      : frame for local & parameter variables look up */
160 };
161
162 static BOOL CALLBACK sgv_cb(PSYMBOL_INFO sym, ULONG size, PVOID ctx)
163 {
164     struct sgv_data*    sgv = ctx;
165     unsigned            insp;
166     char                tmp[64];
167
168     if (sym->Flags & SYMFLAG_THUNK)
169     {
170         if (!sgv->do_thunks) return TRUE;
171         sgv->num_thunks++;
172     }
173
174     if (sgv->num >= NUMDBGV)
175     {
176         dbg_printf("Too many addresses for symbol '%s', limiting the first %d\n",
177                    sgv->name, NUMDBGV);
178         return FALSE;
179     }
180     WINE_TRACE("==> %s %s%s%s%s%s%s%s\n", 
181                sym->Name, 
182                (sym->Flags & SYMFLAG_FUNCTION) ? "func " : "",
183                (sym->Flags & SYMFLAG_FRAMEREL) ? "framerel " : "",
184                (sym->Flags & SYMFLAG_REGISTER) ? "register " : "",
185                (sym->Flags & SYMFLAG_REGREL) ? "regrel " : "",
186                (sym->Flags & SYMFLAG_PARAMETER) ? "param " : "",
187                (sym->Flags & SYMFLAG_LOCAL) ? "local " : "",
188                (sym->Flags & SYMFLAG_THUNK) ? "thunk " : "");
189
190     /* always keep the thunks at end of the array */
191     insp = sgv->num;
192     if (sgv->num_thunks && !(sym->Flags & SYMFLAG_THUNK))
193     {
194         insp -= sgv->num_thunks;
195         memmove(&sgv->syms[insp + 1], &sgv->syms[insp],
196                 sizeof(sgv->syms[0]) * sgv->num_thunks);
197     }
198     if (!fill_sym_lvalue(sym, sgv->frame_offset, &sgv->syms[insp].lvalue, tmp, sizeof(tmp)))
199     {
200         dbg_printf("%s: %s\n", sym->Name, tmp);
201         return TRUE;
202     }
203     sgv->syms[insp].flags              = sym->Flags;
204     sgv->syms[insp].sym_info           = sym->info;
205     sgv->num++;
206
207     return TRUE;
208 }
209
210 enum sym_get_lval symbol_picker_interactive(const char* name, const struct sgv_data* sgv,
211                                             struct dbg_lvalue* rtn)
212 {
213     char        buffer[512];
214     unsigned    i;
215
216     if (!dbg_interactiveP)
217     {
218         dbg_printf("More than one symbol named %s, picking the first one\n", name);
219         *rtn = sgv->syms[0].lvalue;
220         return sglv_found;
221     }
222
223     dbg_printf("Many symbols with name '%s', "
224                "choose the one you want (<cr> to abort):\n", name);
225     for (i = 0; i < sgv->num; i++)
226     {
227         if (sgv->num - sgv->num_thunks > 1 && (sgv->syms[i].flags & SYMFLAG_THUNK) && !DBG_IVAR(AlwaysShowThunks))
228             continue;
229         dbg_printf("[%d]: ", i + 1);
230         if (sgv->syms[i].flags & (SYMFLAG_LOCAL | SYMFLAG_PARAMETER))
231         {
232             dbg_printf("%s %sof %s\n",
233                        sgv->syms[i].flags & SYMFLAG_PARAMETER ? "Parameter" : "Local variable",
234                        sgv->syms[i].flags & (SYMFLAG_REGISTER|SYMFLAG_REGREL) ? "(in a register) " : "",
235                        name);
236         }
237         else if (sgv->syms[i].flags & SYMFLAG_THUNK)
238         {
239             print_address(&sgv->syms[i].lvalue.addr, TRUE);
240             /* FIXME: should display where the thunks points to */
241             dbg_printf(" thunk %s\n", name);
242         }
243         else
244         {
245             print_address(&sgv->syms[i].lvalue.addr, TRUE);
246             dbg_printf("\n");
247         }
248     }
249     do
250     {
251         i = 0;
252         if (input_read_line("=> ", buffer, sizeof(buffer)))
253         {
254             if (buffer[0] == '\0') return sglv_aborted;
255             i = atoi(buffer);
256             if (i < 1 || i > sgv->num)
257                 dbg_printf("Invalid choice %d\n", i);
258         }
259         else return sglv_aborted;
260     } while (i < 1 || i > sgv->num);
261
262     /* The array is 0-based, but the choices are 1..n,
263      * so we have to subtract one before returning.
264      */
265     *rtn = sgv->syms[i - 1].lvalue;
266     return sglv_found;
267 }
268
269 enum sym_get_lval symbol_picker_scoped(const char* name, const struct sgv_data* sgv,
270                                        struct dbg_lvalue* rtn)
271 {
272     unsigned i;
273     int local = -1;
274
275     for (i = 0; i < sgv->num; i++)
276     {
277         if (sgv->num - sgv->num_thunks > 1 && (sgv->syms[i].flags & SYMFLAG_THUNK) && !DBG_IVAR(AlwaysShowThunks))
278             continue;
279         if (sgv->syms[i].flags & (SYMFLAG_LOCAL | SYMFLAG_PARAMETER))
280         {
281             if (local == -1)
282                 local = i;
283             else
284             {
285                 /* FIXME: several locals with same name... which one to pick ?? */
286                 dbg_printf("Several local variables/parameters for %s, aborting\n", name);
287                 return sglv_aborted;
288             }
289         }
290     }
291     if (local != -1)
292     {
293         *rtn = sgv->syms[local].lvalue;
294         return sglv_found;
295     }
296     /* no locals found, multiple globals... abort for now */
297     dbg_printf("Several global variables for %s, aborting\n", name);
298     return sglv_aborted;
299 }
300
301 symbol_picker_t symbol_current_picker = symbol_picker_interactive;
302
303 /***********************************************************************
304  *           symbol_get_lvalue
305  *
306  * Get the address of a named symbol.
307  * Return values:
308  *      sglv_found:   if the symbol is found
309  *      sglv_unknown: if the symbol isn't found
310  *      sglv_aborted: some error occurred (likely, many symbols of same name exist,
311  *          and user didn't pick one of them)
312  */
313 enum sym_get_lval symbol_get_lvalue(const char* name, const int lineno,
314                                     struct dbg_lvalue* rtn, BOOL bp_disp)
315 {
316     struct sgv_data             sgv;
317     int                         i;
318     char                        buffer[512];
319     DWORD                       opt;
320     IMAGEHLP_STACK_FRAME        ihsf;
321
322     if (strlen(name) + 4 > sizeof(buffer))
323     {
324         WINE_WARN("Too long symbol (%s)\n", name);
325         return sglv_unknown;
326     }
327
328     sgv.num        = 0;
329     sgv.num_thunks = 0;
330     sgv.name       = &buffer[2];
331     sgv.do_thunks  = DBG_IVAR(AlwaysShowThunks);
332
333     if (strchr(name, '!'))
334     {
335         strcpy(buffer, name);
336     }
337     else
338     {
339         buffer[0] = '*';
340         buffer[1] = '!';
341         strcpy(&buffer[2], name);
342     }
343
344     /* this is a wine specific options to return also ELF modules in the
345      * enumeration
346      */
347     SymSetOptions((opt = SymGetOptions()) | 0x40000000);
348     SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv);
349
350     if (!sgv.num)
351     {
352         const char*   ptr = strchr(name, '!');
353         if ((ptr && ptr[1] != '_') || (!ptr && *name != '_'))
354         {
355             if (ptr)
356             {
357                 int offset = ptr - name;
358                 memcpy(buffer, name, offset + 1);
359                 buffer[offset + 1] = '_';
360                 strcpy(&buffer[offset + 2], ptr + 1);
361             }
362             else
363             {
364                 buffer[0] = '*';
365                 buffer[1] = '!';
366                 buffer[2] = '_';
367                 strcpy(&buffer[3], name);
368             }
369             SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv);
370         }
371     }
372     SymSetOptions(opt);
373
374     /* now grab local symbols */
375     if (stack_get_current_frame(&ihsf) && sgv.num < NUMDBGV)
376     {
377         sgv.frame_offset = ihsf.FrameOffset;
378         SymEnumSymbols(dbg_curr_process->handle, 0, name, sgv_cb, (void*)&sgv);
379     }
380
381     if (!sgv.num)
382     {
383         dbg_printf("No symbols found for %s\n", name);
384         return sglv_unknown;
385     }
386
387     /* recompute potential offsets for functions (linenumber, skip prolog) */
388     for (i = 0; i < sgv.num; i++)
389     {
390         if (sgv.syms[i].flags & (SYMFLAG_REGISTER|SYMFLAG_REGREL|SYMFLAG_LOCAL|SYMFLAG_THUNK))
391             continue;
392
393         if (lineno == -1)
394         {
395             struct dbg_type     type;
396             ULONG64             addr;
397
398             type.module = sgv.syms[i].lvalue.type.module;
399             type.id     = sgv.syms[i].sym_info;
400             if (bp_disp && symbol_get_debug_start(&type, &addr))
401                 sgv.syms[i].lvalue.addr.Offset = addr;
402         }
403         else
404         {
405             DWORD               disp;
406             IMAGEHLP_LINE64     il;
407             BOOL                found = FALSE;
408
409             il.SizeOfStruct = sizeof(il);
410             SymGetLineFromAddr64(dbg_curr_process->handle,
411                                  (DWORD_PTR)memory_to_linear_addr(&sgv.syms[i].lvalue.addr),
412                                  &disp, &il);
413             do
414             {
415                 if (lineno == il.LineNumber)
416                 {
417                     sgv.syms[i].lvalue.addr.Offset = il.Address;
418                     found = TRUE;
419                     break;
420                 }
421             } while (SymGetLineNext64(dbg_curr_process->handle, &il));
422             if (!found)
423                 WINE_FIXME("No line (%d) found for %s (setting to symbol start)\n",
424                            lineno, name);
425         }
426     }
427
428     if (sgv.num - sgv.num_thunks > 1 || /* many symbols non thunks (and showing only non thunks) */
429         (sgv.num > 1 && DBG_IVAR(AlwaysShowThunks)) || /* many symbols (showing symbols & thunks) */
430         (sgv.num == sgv.num_thunks && sgv.num_thunks > 1))
431     {
432         return symbol_current_picker(name, &sgv, rtn);
433     }
434     /* first symbol is the one we want:
435      * - only one symbol found,
436      * - or many symbols but only one non thunk when AlwaysShowThunks is FALSE
437      */
438     *rtn = sgv.syms[0].lvalue;
439     return sglv_found;
440 }
441
442 BOOL symbol_is_local(const char* name)
443 {
444     struct sgv_data             sgv;
445     IMAGEHLP_STACK_FRAME        ihsf;
446
447     sgv.num        = 0;
448     sgv.num_thunks = 0;
449     sgv.name       = name;
450     sgv.do_thunks  = FALSE;
451
452     if (stack_get_current_frame(&ihsf))
453     {
454         sgv.frame_offset = ihsf.FrameOffset;
455         SymEnumSymbols(dbg_curr_process->handle, 0, name, sgv_cb, (void*)&sgv);
456     }
457     return sgv.num > 0;
458 }
459
460 /***********************************************************************
461  *           symbol_read_symtable
462  *
463  * Read a symbol file into the hash table.
464  */
465 void symbol_read_symtable(const char* filename, unsigned long offset)
466 {
467     dbg_printf("No longer supported\n");
468
469 #if 0
470 /* FIXME: have to implement SymAddSymbol in dbghelp, but likely we'll need to link
471  * this with an already loaded module !! 
472  */
473     FILE*       symbolfile;
474     unsigned    addr;
475     char        type;
476     char*       cpnt;
477     char        buffer[256];
478     char        name[256];
479
480     if (!(symbolfile = fopen(filename, "r")))
481     {
482         WINE_WARN("Unable to open symbol table %s\n", filename);
483         return;
484     }
485
486     dbg_printf("Reading symbols from file %s\n", filename);
487
488     while (1)
489     {
490         fgets(buffer, sizeof(buffer), symbolfile);
491         if (feof(symbolfile)) break;
492
493         /* Strip any text after a # sign (i.e. comments) */
494         cpnt = strchr(buffer, '#');
495         if (cpnt) *cpnt = '\0';
496
497         /* Quietly ignore any lines that have just whitespace */
498         for (cpnt = buffer; *cpnt; cpnt++)
499         {
500             if (*cpnt != ' ' && *cpnt != '\t') break;
501         }
502         if (!*cpnt || *cpnt == '\n') continue;
503
504         if (sscanf(buffer, "%lx %c %s", &addr, &type, name) == 3)
505         {
506             if (value.addr.off + offset < value.addr.off)
507                 WINE_WARN("Address wrap around\n");
508             value.addr.off += offset;
509             SymAddSymbol(current_process->handle, BaseOfDll,
510                          name, addr, 0, 0);
511         }
512     }
513     fclose(symbolfile);
514 #endif
515 }
516
517 /***********************************************************************
518  *           symbol_get_function_line_status
519  *
520  * Find the symbol nearest to a given address.
521  */
522 enum dbg_line_status symbol_get_function_line_status(const ADDRESS64* addr)
523 {
524     IMAGEHLP_LINE64     il;
525     DWORD               disp;
526     ULONG64             disp64, start;
527     DWORD_PTR           lin = (DWORD_PTR)memory_to_linear_addr(addr);
528     char                buffer[sizeof(SYMBOL_INFO) + 256];
529     SYMBOL_INFO*        sym = (SYMBOL_INFO*)buffer;
530     struct dbg_type     func;
531
532     il.SizeOfStruct = sizeof(il);
533     sym->SizeOfStruct = sizeof(SYMBOL_INFO);
534     sym->MaxNameLen = sizeof(buffer) - sizeof(SYMBOL_INFO);
535
536     /* do we have some info for lin address ? */
537     if (!SymFromAddr(dbg_curr_process->handle, lin, &disp64, sym))
538         return dbg_no_line_info;
539
540     switch (sym->Tag)
541     {
542     case SymTagThunk:
543         /* FIXME: so far dbghelp doesn't return the 16 <=> 32 thunks
544          * and furthermore, we no longer take care of them !!!
545          */
546         return dbg_in_a_thunk;
547     case SymTagFunction:
548     case SymTagPublicSymbol: break;
549     default:
550         WINE_FIXME("Unexpected sym-tag 0x%08x\n", sym->Tag);
551     case SymTagData:
552         return dbg_no_line_info;
553     }
554     /* we should have a function now */
555     if (!SymGetLineFromAddr64(dbg_curr_process->handle, lin, &disp, &il))
556         return dbg_no_line_info;
557
558     func.module = sym->ModBase;
559     func.id     = sym->info;
560
561     if (symbol_get_debug_start(&func, &start) && lin < start)
562         return dbg_not_on_a_line_number;
563
564     if (!sym->Size) sym->Size = 0x100000;
565     if (il.FileName && il.FileName[0] && disp < sym->Size)
566         return (disp == 0) ? dbg_on_a_line_number : dbg_not_on_a_line_number;
567
568     return dbg_no_line_info;
569 }
570
571 /***********************************************************************
572  *           symbol_get_line
573  *
574  * Find the symbol nearest to a given address.
575  * Returns sourcefile name and line number in a format that the listing
576  * handler can deal with.
577  */
578 BOOL symbol_get_line(const char* filename, const char* name,
579                      IMAGEHLP_LINE64* line)
580 {
581     struct sgv_data     sgv;
582     char                buffer[512];
583     DWORD               opt, disp;
584     unsigned            i, found = FALSE;
585     IMAGEHLP_LINE64     il;
586
587     sgv.num        = 0;
588     sgv.num_thunks = 0;
589     sgv.name       = &buffer[2];
590     sgv.do_thunks  = FALSE;
591
592     buffer[0] = '*';
593     buffer[1] = '!';
594     strcpy(&buffer[2], name);
595
596     /* this is a wine specific options to return also ELF modules in the
597      * enumeration
598      */
599     SymSetOptions((opt = SymGetOptions()) | 0x40000000);
600     if (!SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv))
601     {
602         SymSetOptions(opt);
603         return FALSE;
604     }
605
606     if (!sgv.num && (name[0] != '_'))
607     {
608         buffer[2] = '_';
609         strcpy(&buffer[3], name);
610         if (!SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv))
611         {
612             SymSetOptions(opt);
613             return FALSE;
614         }
615     }
616     SymSetOptions(opt);
617
618     for (i = 0; i < sgv.num; i++)
619     {
620         DWORD_PTR linear = (DWORD_PTR)memory_to_linear_addr(&sgv.syms[i].lvalue.addr);
621
622         il.SizeOfStruct = sizeof(il);
623         if (!SymGetLineFromAddr64(dbg_curr_process->handle, linear, &disp, &il))
624             continue;
625         if (filename && strcmp(il.FileName, filename)) continue;
626         if (found)
627         {
628             WINE_FIXME("Several found, returning first (may not be what you want)...\n");
629             break;
630         }
631         found = TRUE;
632         *line = il;
633     }
634     if (!found)
635     {
636         if (filename)   dbg_printf("No such function %s in %s\n", name, filename);
637         else            dbg_printf("No such function %s\n", name);
638         return FALSE;
639     }
640     return TRUE;
641 }
642
643 /******************************************************************
644  *              symbol_print_local
645  *
646  * Overall format is:
647  * <name>=<value>                       in non detailed form
648  * <name>=<value> (local|pmt <where>)   in detailed form
649  * Note <value> can be an error message in case of error
650  */
651 void symbol_print_local(const SYMBOL_INFO* sym, DWORD_PTR base, BOOL detailed)
652 {
653     struct dbg_lvalue   lvalue;
654     char                buffer[64];
655
656     dbg_printf("%s=", sym->Name);
657
658     if (fill_sym_lvalue(sym, base, &lvalue, buffer, sizeof(buffer)))
659     {
660         print_value(&lvalue, 0, 1);
661         if (detailed)
662             dbg_printf(" (%s%s)",
663                        (sym->Flags & SYMFLAG_PARAMETER) ? "parameter" : "local",
664                        buffer);
665     }
666     else
667     {
668         dbg_printf("%s", buffer);
669         if (detailed)
670             dbg_printf(" (%s)",
671                        (sym->Flags & SYMFLAG_PARAMETER) ? "parameter" : "local");
672     }
673 }
674
675 static BOOL CALLBACK info_locals_cb(PSYMBOL_INFO sym, ULONG size, PVOID ctx)
676 {
677     struct dbg_type     type;
678
679     dbg_printf("\t");
680     type.module = sym->ModBase;
681     type.id = sym->TypeIndex;
682     types_print_type(&type, FALSE);
683
684     dbg_printf(" ");
685     symbol_print_local(sym, (DWORD_PTR)ctx, TRUE);
686     dbg_printf("\n");
687
688     return TRUE;
689 }
690
691 int symbol_info_locals(void)
692 {
693     IMAGEHLP_STACK_FRAME        ihsf;
694     ADDRESS64                   addr;
695
696     stack_get_current_frame(&ihsf);
697     addr.Mode = AddrModeFlat;
698     addr.Offset = ihsf.InstructionOffset;
699     print_address(&addr, FALSE);
700     dbg_printf(": (%08lx)\n", (DWORD_PTR)ihsf.FrameOffset);
701     SymEnumSymbols(dbg_curr_process->handle, 0, NULL, info_locals_cb, (void*)(DWORD_PTR)ihsf.FrameOffset);
702
703     return TRUE;
704
705 }
706
707 static BOOL CALLBACK symbols_info_cb(PSYMBOL_INFO sym, ULONG size, PVOID ctx)
708 {
709     struct dbg_type     type;
710     IMAGEHLP_MODULE     mi;
711
712     mi.SizeOfStruct = sizeof(mi);
713
714     if (!SymGetModuleInfo(dbg_curr_process->handle, sym->ModBase, &mi))
715         mi.ModuleName[0] = '\0';
716     else
717     {
718         size_t  len = strlen(mi.ModuleName);
719         if (len > 5 && !strcmp(mi.ModuleName + len - 5, "<elf>"))
720             mi.ModuleName[len - 5] = '\0';
721     }
722
723     dbg_printf("%08lx: %s!%s", (ULONG_PTR)sym->Address, mi.ModuleName, sym->Name);
724     type.id = sym->TypeIndex;
725     type.module = sym->ModBase;
726
727     if (sym->TypeIndex != dbg_itype_none && sym->TypeIndex != 0)
728     {
729         dbg_printf(" ");
730         types_print_type(&type, FALSE);
731     }
732     dbg_printf("\n");
733     return TRUE;
734 }
735
736 void symbol_info(const char* str)
737 {
738     char        buffer[512];
739     DWORD       opt;
740
741     if (strlen(str) + 3 >= sizeof(buffer))
742     {
743         dbg_printf("Symbol too long (%s)\n", str);
744         return;
745     }
746     buffer[0] = '*';
747     buffer[1] = '!';
748     strcpy(&buffer[2], str);
749     /* this is a wine specific options to return also ELF modules in the
750      * enumeration
751      */
752     SymSetOptions((opt = SymGetOptions()) | 0x40000000);
753     SymEnumSymbols(dbg_curr_process->handle, 0, buffer, symbols_info_cb, NULL);
754     SymSetOptions(opt);
755 }