winedbg: Win64 printf format fixes.
[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 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* 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* pval;
84
85         if (!memory_get_register(sym->Register, &pval, buffer, sz))
86             return FALSE;
87         lvalue->cookie = DLV_TARGET;
88         lvalue->addr.Offset = (ULONG)((ULONG64)*pval + sym->Address);
89     }
90     else if (sym->Flags & SYMFLAG_VALUEPRESENT)
91     {
92         struct dbg_type type;
93         VARIANT         v;
94         DWORD*          pdw;
95
96         type.module = sym->ModBase;
97         type.id = sym->info;
98
99         /* FIXME: this won't work for pointers, as we always for the
100          * dereference to be in debuggee address space while here
101          * it's in debugger address space
102          */
103         if (!types_get_info(&type, TI_GET_VALUE, &v) || (v.n1.n2.vt & VT_BYREF))
104         {
105             snprintf(buffer, sz, "Couldn't dereference pointer for const value");
106             return FALSE;
107         }
108         pdw = (DWORD*)lexeme_alloc_size(sizeof(*pdw));
109         lvalue->cookie = DLV_HOST;
110         lvalue->addr.Offset = (ULONG)(DWORD_PTR)pdw;
111         *pdw = sym->Value;
112     }
113     else if (sym->Flags & SYMFLAG_LOCAL)
114     {
115         lvalue->cookie = DLV_TARGET;
116         lvalue->addr.Offset = base + sym->Address;
117     }
118     else
119     {
120         lvalue->cookie = DLV_TARGET;
121         lvalue->addr.Offset = sym->Address;
122     }
123     lvalue->addr.Mode = AddrModeFlat;
124     lvalue->type.module = sym->ModBase;
125     lvalue->type.id = sym->TypeIndex;
126
127     return TRUE;
128 }
129
130 struct sgv_data
131 {
132 #define NUMDBGV                 100
133     struct
134     {
135         /* FIXME: NUMDBGV should be made variable */
136         struct dbg_lvalue               lvalue;
137         DWORD                           flags;
138         DWORD                           sym_info;
139     }                           syms[NUMDBGV];  /* out     : will be filled in with various found symbols */
140     int                         num;            /* out     : number of found symbols */
141     int                         num_thunks;     /* out     : number of thunks found */
142     const char*                 name;           /* in      : name of symbol to look up */
143     unsigned                    do_thunks : 1;  /* in      : whether we return thunks tags */
144     ULONG64                     frame_offset;   /* in      : frame for local & parameter variables look up */
145 };
146
147 static BOOL CALLBACK sgv_cb(SYMBOL_INFO* sym, ULONG size, void* ctx)
148 {
149     struct sgv_data*    sgv = (struct sgv_data*)ctx;
150     unsigned            insp;
151     char                tmp[64];
152
153     if (sym->Flags & SYMFLAG_THUNK)
154     {
155         if (!sgv->do_thunks) return TRUE;
156         sgv->num_thunks++;
157     }
158
159     if (sgv->num >= NUMDBGV)
160     {
161         dbg_printf("Too many addresses for symbol '%s', limiting the first %d\n",
162                    sgv->name, NUMDBGV);
163         return FALSE;
164     }
165     WINE_TRACE("==> %s %s%s%s%s%s%s%s\n", 
166                sym->Name, 
167                (sym->Flags & SYMFLAG_FUNCTION) ? "func " : "",
168                (sym->Flags & SYMFLAG_FRAMEREL) ? "framerel " : "",
169                (sym->Flags & SYMFLAG_REGISTER) ? "register " : "",
170                (sym->Flags & SYMFLAG_REGREL) ? "regrel " : "",
171                (sym->Flags & SYMFLAG_PARAMETER) ? "param " : "",
172                (sym->Flags & SYMFLAG_LOCAL) ? "local " : "",
173                (sym->Flags & SYMFLAG_THUNK) ? "thunk " : "");
174
175     /* always keep the thunks at end of the array */
176     insp = sgv->num;
177     if (sgv->num_thunks && !(sym->Flags & SYMFLAG_THUNK))
178     {
179         insp -= sgv->num_thunks;
180         memmove(&sgv->syms[insp + 1], &sgv->syms[insp],
181                 sizeof(sgv->syms[0]) * sgv->num_thunks);
182     }
183     if (!fill_sym_lvalue(sym, sgv->frame_offset, &sgv->syms[insp].lvalue, tmp, sizeof(tmp)))
184     {
185         dbg_printf("%s: %s\n", sym->Name, tmp);
186         return TRUE;
187     }
188     sgv->syms[insp].flags              = sym->Flags;
189     sgv->syms[insp].sym_info           = sym->info;
190     sgv->num++;
191
192     return TRUE;
193 }
194
195 /***********************************************************************
196  *           symbol_get_lvalue
197  *
198  * Get the address of a named symbol.
199  * Return values:
200  *      sglv_found:   if the symbol is found
201  *      sglv_unknown: if the symbol isn't found
202  *      sglv_aborted: some error occurred (likely, many symbols of same name exist,
203  *          and user didn't pick one of them)
204  */
205 enum sym_get_lval symbol_get_lvalue(const char* name, const int lineno,
206                                     struct dbg_lvalue* rtn, BOOL bp_disp)
207 {
208     struct sgv_data             sgv;
209     int                         i;
210     char                        buffer[512];
211     DWORD                       opt;
212     IMAGEHLP_STACK_FRAME        ihsf;
213
214     if (strlen(name) + 4 > sizeof(buffer))
215     {
216         WINE_WARN("Too long symbol (%s)\n", name);
217         return sglv_unknown;
218     }
219
220     sgv.num        = 0;
221     sgv.num_thunks = 0;
222     sgv.name       = &buffer[2];
223     sgv.do_thunks  = DBG_IVAR(AlwaysShowThunks);
224
225     if (strchr(name, '!'))
226     {
227         strcpy(buffer, name);
228     }
229     else
230     {
231         buffer[0] = '*';
232         buffer[1] = '!';
233         strcpy(&buffer[2], name);
234     }
235
236     /* this is a wine specific options to return also ELF modules in the
237      * enumeration
238      */
239     SymSetOptions((opt = SymGetOptions()) | 0x40000000);
240     SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv);
241
242     if (!sgv.num && (name[0] != '_'))
243     {
244         char*   ptr = strchr(name, '!');
245
246         if (ptr++)
247         {
248             memmove(ptr + 1, ptr, strlen(ptr));
249             *ptr = '_';
250         }
251         else
252         {
253             buffer[0] = '*';
254             buffer[1] = '!';
255             buffer[2] = '_';
256             strcpy(&buffer[3], name);
257         }
258         SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv);
259     }
260     SymSetOptions(opt);
261
262     /* now grab local symbols */
263     if (stack_get_current_frame(&ihsf) && sgv.num < NUMDBGV)
264     {
265         sgv.frame_offset = ihsf.FrameOffset;
266         SymEnumSymbols(dbg_curr_process->handle, 0, name, sgv_cb, (void*)&sgv);
267     }
268
269     if (!sgv.num)
270     {
271         dbg_printf("No symbols found for %s\n", name);
272         return sglv_unknown;
273     }
274
275     /* recompute potential offsets for functions (linenumber, skip prolog) */
276     for (i = 0; i < sgv.num; i++)
277     {
278         if (sgv.syms[i].flags & (SYMFLAG_REGISTER|SYMFLAG_REGREL|SYMFLAG_LOCAL|SYMFLAG_THUNK))
279             continue;
280
281         if (lineno == -1)
282         {
283             struct dbg_type     type;
284             ULONG64             addr;
285
286             type.module = sgv.syms[i].lvalue.type.module;
287             type.id     = sgv.syms[i].sym_info;
288             if (bp_disp && symbol_get_debug_start(&type, &addr))
289                 sgv.syms[i].lvalue.addr.Offset = addr;
290         }
291         else
292         {
293             DWORD               disp;
294             IMAGEHLP_LINE       il;
295             BOOL                found = FALSE;
296
297             il.SizeOfStruct = sizeof(il);
298             SymGetLineFromAddr(dbg_curr_process->handle,
299                                (DWORD)memory_to_linear_addr(&sgv.syms[i].lvalue.addr),
300                                &disp, &il);
301             do
302             {
303                 if (lineno == il.LineNumber)
304                 {
305                     sgv.syms[i].lvalue.addr.Offset = il.Address;
306                     found = TRUE;
307                     break;
308                 }
309             } while (SymGetLineNext(dbg_curr_process->handle, &il));
310             if (!found)
311                 WINE_FIXME("No line (%d) found for %s (setting to symbol start)\n",
312                            lineno, name);
313         }
314     }
315
316     i = 0;
317     if (dbg_interactiveP)
318     {
319         if (sgv.num - sgv.num_thunks > 1 || /* many symbols non thunks (and showing only non thunks) */
320             (sgv.num > 1 && DBG_IVAR(AlwaysShowThunks)) || /* many symbols (showing symbols & thunks) */
321             (sgv.num == sgv.num_thunks && sgv.num_thunks > 1))
322         {
323             dbg_printf("Many symbols with name '%s', "
324                        "choose the one you want (<cr> to abort):\n", name);
325             for (i = 0; i < sgv.num; i++) 
326             {
327                 if (sgv.num - sgv.num_thunks > 1 && (sgv.syms[i].flags & SYMFLAG_THUNK) && !DBG_IVAR(AlwaysShowThunks))
328                     continue;
329                 dbg_printf("[%d]: ", i + 1);
330                 if (sgv.syms[i].flags & SYMFLAG_LOCAL)
331                 {
332                     dbg_printf("%s %sof %s\n",
333                                sgv.syms[i].flags & SYMFLAG_PARAMETER ? "Parameter" : "Local variable",
334                                sgv.syms[i].flags & (SYMFLAG_REGISTER|SYMFLAG_REGREL) ? "(in a register) " : "",
335                                name);
336                 }
337                 else if (sgv.syms[i].flags & SYMFLAG_THUNK) 
338                 {
339                     print_address(&sgv.syms[i].lvalue.addr, TRUE);
340                     /* FIXME: should display where the thunks points to */
341                     dbg_printf(" thunk %s\n", name);
342                 }
343                 else
344                 {
345                     print_address(&sgv.syms[i].lvalue.addr, TRUE);
346                     dbg_printf("\n");
347                 }
348             }
349             do
350             {
351                 i = 0;
352                 if (input_read_line("=> ", buffer, sizeof(buffer)))
353                 {
354                     if (buffer[0] == '\0') return sglv_aborted;
355                     i = atoi(buffer);
356                     if (i < 1 || i > sgv.num)
357                         dbg_printf("Invalid choice %d\n", i);
358                 }
359             } while (i < 1 || i > sgv.num);
360
361             /* The array is 0-based, but the choices are 1..n, 
362              * so we have to subtract one before returning.
363              */
364             i--;
365         }
366     }
367     else
368     {
369         /* FIXME: could display the list of non-picked up symbols */
370         if (sgv.num > 1)
371             dbg_printf("More than one symbol named %s, picking the first one\n", name);
372     }
373     *rtn = sgv.syms[i].lvalue;
374     return sglv_found;
375 }
376
377 BOOL symbol_is_local(const char* name)
378 {
379     struct sgv_data             sgv;
380     IMAGEHLP_STACK_FRAME        ihsf;
381
382     sgv.num        = 0;
383     sgv.num_thunks = 0;
384     sgv.name       = name;
385     sgv.do_thunks  = FALSE;
386
387     if (stack_get_current_frame(&ihsf))
388     {
389         sgv.frame_offset = ihsf.FrameOffset;
390         SymEnumSymbols(dbg_curr_process->handle, 0, name, sgv_cb, (void*)&sgv);
391     }
392     return sgv.num > 0;
393 }
394
395 /***********************************************************************
396  *           symbol_read_symtable
397  *
398  * Read a symbol file into the hash table.
399  */
400 void symbol_read_symtable(const char* filename, unsigned long offset)
401 {
402     dbg_printf("No longer supported\n");
403
404 #if 0
405 /* FIXME: have to implement SymAddSymbol in dbghelp, but likely we'll need to link
406  * this with an already loaded module !! 
407  */
408     FILE*       symbolfile;
409     unsigned    addr;
410     char        type;
411     char*       cpnt;
412     char        buffer[256];
413     char        name[256];
414
415     if (!(symbolfile = fopen(filename, "r")))
416     {
417         WINE_WARN("Unable to open symbol table %s\n", filename);
418         return;
419     }
420
421     dbg_printf("Reading symbols from file %s\n", filename);
422
423     while (1)
424     {
425         fgets(buffer, sizeof(buffer), symbolfile);
426         if (feof(symbolfile)) break;
427
428         /* Strip any text after a # sign (i.e. comments) */
429         cpnt = strchr(buffer, '#');
430         if (cpnt) *cpnt = '\0';
431
432         /* Quietly ignore any lines that have just whitespace */
433         for (cpnt = buffer; *cpnt; cpnt++)
434         {
435             if (*cpnt != ' ' && *cpnt != '\t') break;
436         }
437         if (!*cpnt || *cpnt == '\n') continue;
438
439         if (sscanf(buffer, "%lx %c %s", &addr, &type, name) == 3)
440         {
441             if (value.addr.off + offset < value.addr.off)
442                 WINE_WARN("Address wrap around\n");
443             value.addr.off += offset;
444             SymAddSymbol(current_process->handle, BaseOfDll,
445                          name, addr, 0, 0);
446         }
447     }
448     fclose(symbolfile);
449 #endif
450 }
451
452 /***********************************************************************
453  *           symbol_get_function_line_status
454  *
455  * Find the symbol nearest to a given address.
456  */
457 enum dbg_line_status symbol_get_function_line_status(const ADDRESS64* addr)
458 {
459     IMAGEHLP_LINE       il;
460     DWORD               disp;
461     ULONG64             disp64, start;
462     DWORD               lin = (DWORD)memory_to_linear_addr(addr);
463     char                buffer[sizeof(SYMBOL_INFO) + 256];
464     SYMBOL_INFO*        sym = (SYMBOL_INFO*)buffer;
465     struct dbg_type     func;
466
467     il.SizeOfStruct = sizeof(il);
468     sym->SizeOfStruct = sizeof(SYMBOL_INFO);
469     sym->MaxNameLen = sizeof(buffer) - sizeof(SYMBOL_INFO);
470
471     /* do we have some info for lin address ? */
472     if (!SymFromAddr(dbg_curr_process->handle, lin, &disp64, sym))
473         return dbg_no_line_info;
474
475     switch (sym->Tag)
476     {
477     case SymTagThunk:
478         /* FIXME: so far dbghelp doesn't return the 16 <=> 32 thunks
479          * and furthermore, we no longer take care of them !!!
480          */
481         return dbg_in_a_thunk;
482     case SymTagFunction:
483     case SymTagPublicSymbol: break;
484     default:
485         WINE_FIXME("Unexpected sym-tag 0x%08x\n", sym->Tag);
486     case SymTagData:
487         return dbg_no_line_info;
488     }
489     /* we should have a function now */
490     if (!SymGetLineFromAddr(dbg_curr_process->handle, lin, &disp, &il))
491         return dbg_no_line_info;
492
493     func.module = sym->ModBase;
494     func.id     = sym->info;
495
496     if (symbol_get_debug_start(&func, &start) && lin < start)
497         return dbg_not_on_a_line_number;
498
499     if (!sym->Size) sym->Size = 0x100000;
500     if (il.FileName && il.FileName[0] && disp < sym->Size)
501         return (disp == 0) ? dbg_on_a_line_number : dbg_not_on_a_line_number;
502
503     return dbg_no_line_info;
504 }
505
506 /***********************************************************************
507  *           symbol_get_line
508  *
509  * Find the symbol nearest to a given address.
510  * Returns sourcefile name and line number in a format that the listing
511  * handler can deal with.
512  */
513 BOOL symbol_get_line(const char* filename, const char* name, IMAGEHLP_LINE* line)
514 {
515     struct sgv_data     sgv;
516     char                buffer[512];
517     DWORD               opt, disp, linear;
518     unsigned            i, found = FALSE;
519     IMAGEHLP_LINE       il;
520
521     sgv.num        = 0;
522     sgv.num_thunks = 0;
523     sgv.name       = &buffer[2];
524     sgv.do_thunks  = FALSE;
525
526     buffer[0] = '*';
527     buffer[1] = '!';
528     strcpy(&buffer[2], name);
529
530     /* this is a wine specific options to return also ELF modules in the
531      * enumeration
532      */
533     SymSetOptions((opt = SymGetOptions()) | 0x40000000);
534     if (!SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv))
535     {
536         SymSetOptions(opt);
537         return FALSE;
538     }
539
540     if (!sgv.num && (name[0] != '_'))
541     {
542         buffer[2] = '_';
543         strcpy(&buffer[3], name);
544         if (!SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv))
545         {
546             SymSetOptions(opt);
547             return FALSE;
548         }
549     }
550     SymSetOptions(opt);
551
552     for (i = 0; i < sgv.num; i++)
553     {
554         linear = (DWORD)memory_to_linear_addr(&sgv.syms[i].lvalue.addr);
555
556         il.SizeOfStruct = sizeof(il);
557         if (!SymGetLineFromAddr(dbg_curr_process->handle, linear, &disp, &il))
558             continue;
559         if (filename && strcmp(line->FileName, filename)) continue;
560         if (found)
561         {
562             WINE_FIXME("Several found, returning first (may not be what you want)...\n");
563             break;
564         }
565         found = TRUE;
566         *line = il;
567     }
568     if (!found)
569     {
570         if (filename)   dbg_printf("No such function %s in %s\n", name, filename);
571         else            dbg_printf("No such function %s\n", name);
572         return FALSE;
573     }
574     return TRUE;
575 }
576
577 /******************************************************************
578  *              symbol_print_local
579  *
580  * Overall format is:
581  * <name>=<value>                       in non detailed form
582  * <name>=<value> (local|pmt <where>)   in detailed form
583  * Note <value> can be an error message in case of error
584  */
585 void symbol_print_local(const SYMBOL_INFO* sym, ULONG base, 
586                         BOOL detailed)
587 {
588     struct dbg_lvalue   lvalue;
589     char                buffer[64];
590
591     dbg_printf("%s=", sym->Name);
592
593     if (fill_sym_lvalue(sym, base, &lvalue, buffer, sizeof(buffer)))
594     {
595         print_value(&lvalue, 'x', 1);
596         if (detailed)
597             dbg_printf(" (%s%s)",
598                        (sym->Flags & SYMFLAG_PARAMETER) ? "parameter" : "local",
599                        buffer);
600     }
601     else
602     {
603         dbg_printf(buffer);
604         if (detailed)
605             dbg_printf(" (%s)",
606                        (sym->Flags & SYMFLAG_PARAMETER) ? "parameter" : "local");
607     }
608 }
609
610 static BOOL CALLBACK info_locals_cb(SYMBOL_INFO* sym, ULONG size, void* ctx)
611 {
612     struct dbg_type     type;
613
614     dbg_printf("\t");
615     type.module = sym->ModBase;
616     type.id = sym->TypeIndex;
617     types_print_type(&type, FALSE);
618
619     dbg_printf(" ");
620     symbol_print_local(sym, (ULONG)ctx, TRUE);
621     dbg_printf("\n");
622
623     return TRUE;
624 }
625
626 int symbol_info_locals(void)
627 {
628     IMAGEHLP_STACK_FRAME        ihsf;
629     ADDRESS64                   addr;
630
631     stack_get_current_frame(&ihsf);
632     addr.Mode = AddrModeFlat;
633     addr.Offset = ihsf.InstructionOffset;
634     print_address(&addr, FALSE);
635     dbg_printf(": (%08lx)\n", (DWORD_PTR)ihsf.FrameOffset);
636     SymEnumSymbols(dbg_curr_process->handle, 0, NULL, info_locals_cb, (void*)(DWORD_PTR)ihsf.FrameOffset);
637
638     return TRUE;
639
640 }
641
642 static BOOL CALLBACK symbols_info_cb(SYMBOL_INFO* sym, ULONG size, void* ctx)
643 {
644     struct dbg_type     type;
645     IMAGEHLP_MODULE     mi;
646
647     mi.SizeOfStruct = sizeof(mi);
648
649     if (!SymGetModuleInfo(dbg_curr_process->handle, sym->ModBase, &mi))
650         mi.ModuleName[0] = '\0';
651     else
652     {
653         size_t  len = strlen(mi.ModuleName);
654         if (len > 5 && !strcmp(mi.ModuleName + len - 5, "<elf>"))
655             mi.ModuleName[len - 5] = '\0';
656     }
657
658     dbg_printf("%08lx: %s!%s", (ULONG_PTR)sym->Address, mi.ModuleName, sym->Name);
659     type.id = sym->TypeIndex;
660     type.module = sym->ModBase;
661
662     if (sym->TypeIndex != dbg_itype_none && sym->TypeIndex != 0)
663     {
664         dbg_printf(" ");
665         types_print_type(&type, FALSE);
666     }
667     dbg_printf("\n");
668     return TRUE;
669 }
670
671 void symbol_info(const char* str)
672 {
673     char        buffer[512];
674     DWORD       opt;
675
676     if (strlen(str) + 3 >= sizeof(buffer))
677     {
678         dbg_printf("Symbol too long (%s)\n", str);
679         return;
680     }
681     buffer[0] = '*';
682     buffer[1] = '!';
683     strcpy(&buffer[2], str);
684     /* this is a wine specific options to return also ELF modules in the
685      * enumeration
686      */
687     SymSetOptions((opt = SymGetOptions()) | 0x40000000);
688     SymEnumSymbols(dbg_curr_process->handle, 0, buffer, symbols_info_cb, NULL);
689     SymSetOptions(opt);
690 }