strmbase: do not lock in BaseOutputPinImpl_GetDeliveryBuffer the MemInputPin will...
[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 if (sym->Flags & SYMFLAG_TLSREL)
134     {
135         PROCESS_BASIC_INFORMATION pbi;
136         THREAD_BASIC_INFORMATION  tbi;
137         DWORD_PTR                 addr;
138         PEB                       peb;
139         PEB_LDR_DATA              ldr_data;
140         PLIST_ENTRY               head, current;
141         LDR_MODULE                ldr_module;
142         unsigned                  tlsindex = -1;
143
144         if (NtQueryInformationProcess(dbg_curr_process->handle, ProcessBasicInformation,
145                                       &pbi, sizeof(pbi), NULL) ||
146             NtQueryInformationThread(dbg_curr_thread->handle, ThreadBasicInformation,
147                                      &tbi, sizeof(tbi), NULL))
148         {
149         tls_error:
150             if (buffer) snprintf(buffer, sz, "Cannot read TLS address\n");
151             return FALSE;
152         }
153         addr = (DWORD_PTR)&(((TEB*)tbi.TebBaseAddress)->ThreadLocalStoragePointer);
154         if (!dbg_read_memory((void*)addr, &addr, sizeof(addr)) ||
155             !dbg_read_memory(pbi.PebBaseAddress, &peb, sizeof(peb)) ||
156             !dbg_read_memory(peb.LdrData, &ldr_data, sizeof(ldr_data)))
157             goto tls_error;
158         current = ldr_data.InLoadOrderModuleList.Flink;
159         head = &((PEB_LDR_DATA*)peb.LdrData)->InLoadOrderModuleList;
160         do
161         {
162             if (!dbg_read_memory(CONTAINING_RECORD(current, LDR_MODULE, InLoadOrderModuleList),
163                                  &ldr_module, sizeof(ldr_module))) goto tls_error;
164             if ((DWORD_PTR)ldr_module.BaseAddress == sym->ModBase)
165             {
166                 tlsindex = ldr_module.TlsIndex;
167                 break;
168             }
169             current = ldr_module.InLoadOrderModuleList.Flink;
170         } while (current != head);
171
172         addr += tlsindex * sizeof(DWORD_PTR);
173         if (!dbg_read_memory((void*)addr, &addr, sizeof(addr))) goto tls_error;
174         lvalue->cookie = DLV_TARGET;
175         lvalue->addr.Offset = addr + sym->Address;
176     }
177     else
178     {
179         lvalue->cookie = DLV_TARGET;
180         lvalue->addr.Offset = sym->Address;
181     }
182     lvalue->addr.Mode = AddrModeFlat;
183     lvalue->type.module = sym->ModBase;
184     lvalue->type.id = sym->TypeIndex;
185
186     return TRUE;
187 }
188
189 struct sgv_data
190 {
191 #define NUMDBGV                 100
192     struct
193     {
194         /* FIXME: NUMDBGV should be made variable */
195         struct dbg_lvalue               lvalue;
196         DWORD                           flags;
197         DWORD                           sym_info;
198     }                           syms[NUMDBGV];  /* out     : will be filled in with various found symbols */
199     int                         num;            /* out     : number of found symbols */
200     int                         num_thunks;     /* out     : number of thunks found */
201     const char*                 name;           /* in      : name of symbol to look up */
202     unsigned                    do_thunks : 1;  /* in      : whether we return thunks tags */
203     ULONG64                     frame_offset;   /* in      : frame for local & parameter variables look up */
204 };
205
206 static BOOL CALLBACK sgv_cb(PSYMBOL_INFO sym, ULONG size, PVOID ctx)
207 {
208     struct sgv_data*    sgv = ctx;
209     unsigned            insp;
210     char                tmp[64];
211
212     if (sym->Flags & SYMFLAG_THUNK)
213     {
214         if (!sgv->do_thunks) return TRUE;
215         sgv->num_thunks++;
216     }
217
218     if (sgv->num >= NUMDBGV)
219     {
220         dbg_printf("Too many addresses for symbol '%s', limiting the first %d\n",
221                    sgv->name, NUMDBGV);
222         return FALSE;
223     }
224     WINE_TRACE("==> %s %s%s%s%s%s%s%s%s\n",
225                sym->Name,
226                (sym->Flags & SYMFLAG_FUNCTION) ? "func " : "",
227                (sym->Flags & SYMFLAG_FRAMEREL) ? "framerel " : "",
228                (sym->Flags & SYMFLAG_TLSREL) ? "tlsrel " : "",
229                (sym->Flags & SYMFLAG_REGISTER) ? "register " : "",
230                (sym->Flags & SYMFLAG_REGREL) ? "regrel " : "",
231                (sym->Flags & SYMFLAG_PARAMETER) ? "param " : "",
232                (sym->Flags & SYMFLAG_LOCAL) ? "local " : "",
233                (sym->Flags & SYMFLAG_THUNK) ? "thunk " : "");
234
235     /* always keep the thunks at end of the array */
236     insp = sgv->num;
237     if (sgv->num_thunks && !(sym->Flags & SYMFLAG_THUNK))
238     {
239         insp -= sgv->num_thunks;
240         memmove(&sgv->syms[insp + 1], &sgv->syms[insp],
241                 sizeof(sgv->syms[0]) * sgv->num_thunks);
242     }
243     if (!fill_sym_lvalue(sym, sgv->frame_offset, &sgv->syms[insp].lvalue, tmp, sizeof(tmp)))
244     {
245         dbg_printf("%s: %s\n", sym->Name, tmp);
246         return TRUE;
247     }
248     sgv->syms[insp].flags              = sym->Flags;
249     sgv->syms[insp].sym_info           = sym->info;
250     sgv->num++;
251
252     return TRUE;
253 }
254
255 enum sym_get_lval symbol_picker_interactive(const char* name, const struct sgv_data* sgv,
256                                             struct dbg_lvalue* rtn)
257 {
258     char        buffer[512];
259     unsigned    i;
260
261     if (!dbg_interactiveP)
262     {
263         dbg_printf("More than one symbol named %s, picking the first one\n", name);
264         *rtn = sgv->syms[0].lvalue;
265         return sglv_found;
266     }
267
268     dbg_printf("Many symbols with name '%s', "
269                "choose the one you want (<cr> to abort):\n", name);
270     for (i = 0; i < sgv->num; i++)
271     {
272         if (sgv->num - sgv->num_thunks > 1 && (sgv->syms[i].flags & SYMFLAG_THUNK) && !DBG_IVAR(AlwaysShowThunks))
273             continue;
274         dbg_printf("[%d]: ", i + 1);
275         if (sgv->syms[i].flags & (SYMFLAG_LOCAL | SYMFLAG_PARAMETER))
276         {
277             dbg_printf("%s %sof %s\n",
278                        sgv->syms[i].flags & SYMFLAG_PARAMETER ? "Parameter" : "Local variable",
279                        sgv->syms[i].flags & (SYMFLAG_REGISTER|SYMFLAG_REGREL) ? "(in a register) " : "",
280                        name);
281         }
282         else if (sgv->syms[i].flags & SYMFLAG_THUNK)
283         {
284             print_address(&sgv->syms[i].lvalue.addr, TRUE);
285             /* FIXME: should display where the thunks points to */
286             dbg_printf(" thunk %s\n", name);
287         }
288         else
289         {
290             print_address(&sgv->syms[i].lvalue.addr, TRUE);
291             dbg_printf("\n");
292         }
293     }
294     do
295     {
296         if (input_read_line("=> ", buffer, sizeof(buffer)))
297         {
298             if (buffer[0] == '\0') return sglv_aborted;
299             i = atoi(buffer);
300             if (i < 1 || i > sgv->num)
301                 dbg_printf("Invalid choice %d\n", i);
302         }
303         else return sglv_aborted;
304     } while (i < 1 || i > sgv->num);
305
306     /* The array is 0-based, but the choices are 1..n,
307      * so we have to subtract one before returning.
308      */
309     *rtn = sgv->syms[i - 1].lvalue;
310     return sglv_found;
311 }
312
313 enum sym_get_lval symbol_picker_scoped(const char* name, const struct sgv_data* sgv,
314                                        struct dbg_lvalue* rtn)
315 {
316     unsigned i;
317     int local = -1;
318
319     for (i = 0; i < sgv->num; i++)
320     {
321         if (sgv->num - sgv->num_thunks > 1 && (sgv->syms[i].flags & SYMFLAG_THUNK) && !DBG_IVAR(AlwaysShowThunks))
322             continue;
323         if (sgv->syms[i].flags & (SYMFLAG_LOCAL | SYMFLAG_PARAMETER))
324         {
325             if (local == -1)
326                 local = i;
327             else
328             {
329                 /* FIXME: several locals with same name... which one to pick ?? */
330                 dbg_printf("Several local variables/parameters for %s, aborting\n", name);
331                 return sglv_aborted;
332             }
333         }
334     }
335     if (local != -1)
336     {
337         *rtn = sgv->syms[local].lvalue;
338         return sglv_found;
339     }
340     /* no locals found, multiple globals... abort for now */
341     dbg_printf("Several global variables for %s, aborting\n", name);
342     return sglv_aborted;
343 }
344
345 symbol_picker_t symbol_current_picker = symbol_picker_interactive;
346
347 /***********************************************************************
348  *           symbol_get_lvalue
349  *
350  * Get the address of a named symbol.
351  * Return values:
352  *      sglv_found:   if the symbol is found
353  *      sglv_unknown: if the symbol isn't found
354  *      sglv_aborted: some error occurred (likely, many symbols of same name exist,
355  *          and user didn't pick one of them)
356  */
357 enum sym_get_lval symbol_get_lvalue(const char* name, const int lineno,
358                                     struct dbg_lvalue* rtn, BOOL bp_disp)
359 {
360     struct sgv_data             sgv;
361     int                         i;
362     char                        buffer[512];
363     DWORD                       opt;
364     IMAGEHLP_STACK_FRAME        ihsf;
365
366     if (strlen(name) + 4 > sizeof(buffer))
367     {
368         WINE_WARN("Too long symbol (%s)\n", name);
369         return sglv_unknown;
370     }
371
372     sgv.num        = 0;
373     sgv.num_thunks = 0;
374     sgv.name       = &buffer[2];
375     sgv.do_thunks  = DBG_IVAR(AlwaysShowThunks);
376
377     if (strchr(name, '!'))
378     {
379         strcpy(buffer, name);
380     }
381     else
382     {
383         buffer[0] = '*';
384         buffer[1] = '!';
385         strcpy(&buffer[2], name);
386     }
387
388     /* this is a wine specific options to return also ELF modules in the
389      * enumeration
390      */
391     SymSetOptions((opt = SymGetOptions()) | 0x40000000);
392     SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv);
393
394     if (!sgv.num)
395     {
396         const char*   ptr = strchr(name, '!');
397         if ((ptr && ptr[1] != '_') || (!ptr && *name != '_'))
398         {
399             if (ptr)
400             {
401                 int offset = ptr - name;
402                 memcpy(buffer, name, offset + 1);
403                 buffer[offset + 1] = '_';
404                 strcpy(&buffer[offset + 2], ptr + 1);
405             }
406             else
407             {
408                 buffer[0] = '*';
409                 buffer[1] = '!';
410                 buffer[2] = '_';
411                 strcpy(&buffer[3], name);
412             }
413             SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv);
414         }
415     }
416     SymSetOptions(opt);
417
418     /* now grab local symbols */
419     if (stack_get_current_frame(&ihsf) && sgv.num < NUMDBGV)
420     {
421         sgv.frame_offset = ihsf.FrameOffset;
422         SymEnumSymbols(dbg_curr_process->handle, 0, name, sgv_cb, (void*)&sgv);
423     }
424
425     if (!sgv.num)
426     {
427         dbg_printf("No symbols found for %s\n", name);
428         return sglv_unknown;
429     }
430
431     /* recompute potential offsets for functions (linenumber, skip prolog) */
432     for (i = 0; i < sgv.num; i++)
433     {
434         if (sgv.syms[i].flags & (SYMFLAG_REGISTER|SYMFLAG_REGREL|SYMFLAG_LOCAL|SYMFLAG_THUNK))
435             continue;
436
437         if (lineno == -1)
438         {
439             struct dbg_type     type;
440             ULONG64             addr;
441
442             type.module = sgv.syms[i].lvalue.type.module;
443             type.id     = sgv.syms[i].sym_info;
444             if (bp_disp && symbol_get_debug_start(&type, &addr))
445                 sgv.syms[i].lvalue.addr.Offset = addr;
446         }
447         else
448         {
449             DWORD               disp;
450             IMAGEHLP_LINE64     il;
451             BOOL                found = FALSE;
452
453             il.SizeOfStruct = sizeof(il);
454             SymGetLineFromAddr64(dbg_curr_process->handle,
455                                  (DWORD_PTR)memory_to_linear_addr(&sgv.syms[i].lvalue.addr),
456                                  &disp, &il);
457             do
458             {
459                 if (lineno == il.LineNumber)
460                 {
461                     sgv.syms[i].lvalue.addr.Offset = il.Address;
462                     found = TRUE;
463                     break;
464                 }
465             } while (SymGetLineNext64(dbg_curr_process->handle, &il));
466             if (!found)
467                 WINE_FIXME("No line (%d) found for %s (setting to symbol start)\n",
468                            lineno, name);
469         }
470     }
471
472     if (sgv.num - sgv.num_thunks > 1 || /* many symbols non thunks (and showing only non thunks) */
473         (sgv.num > 1 && DBG_IVAR(AlwaysShowThunks)) || /* many symbols (showing symbols & thunks) */
474         (sgv.num == sgv.num_thunks && sgv.num_thunks > 1))
475     {
476         return symbol_current_picker(name, &sgv, rtn);
477     }
478     /* first symbol is the one we want:
479      * - only one symbol found,
480      * - or many symbols but only one non thunk when AlwaysShowThunks is FALSE
481      */
482     *rtn = sgv.syms[0].lvalue;
483     return sglv_found;
484 }
485
486 BOOL symbol_is_local(const char* name)
487 {
488     struct sgv_data             sgv;
489     IMAGEHLP_STACK_FRAME        ihsf;
490
491     sgv.num        = 0;
492     sgv.num_thunks = 0;
493     sgv.name       = name;
494     sgv.do_thunks  = FALSE;
495
496     if (stack_get_current_frame(&ihsf))
497     {
498         sgv.frame_offset = ihsf.FrameOffset;
499         SymEnumSymbols(dbg_curr_process->handle, 0, name, sgv_cb, (void*)&sgv);
500     }
501     return sgv.num > 0;
502 }
503
504 /***********************************************************************
505  *           symbol_read_symtable
506  *
507  * Read a symbol file into the hash table.
508  */
509 void symbol_read_symtable(const char* filename, unsigned long offset)
510 {
511     dbg_printf("No longer supported\n");
512
513 #if 0
514 /* FIXME: have to implement SymAddSymbol in dbghelp, but likely we'll need to link
515  * this with an already loaded module !! 
516  */
517     FILE*       symbolfile;
518     unsigned    addr;
519     char        type;
520     char*       cpnt;
521     char        buffer[256];
522     char        name[256];
523
524     if (!(symbolfile = fopen(filename, "r")))
525     {
526         WINE_WARN("Unable to open symbol table %s\n", filename);
527         return;
528     }
529
530     dbg_printf("Reading symbols from file %s\n", filename);
531
532     while (1)
533     {
534         fgets(buffer, sizeof(buffer), symbolfile);
535         if (feof(symbolfile)) break;
536
537         /* Strip any text after a # sign (i.e. comments) */
538         cpnt = strchr(buffer, '#');
539         if (cpnt) *cpnt = '\0';
540
541         /* Quietly ignore any lines that have just whitespace */
542         for (cpnt = buffer; *cpnt; cpnt++)
543         {
544             if (*cpnt != ' ' && *cpnt != '\t') break;
545         }
546         if (!*cpnt || *cpnt == '\n') continue;
547
548         if (sscanf(buffer, "%lx %c %s", &addr, &type, name) == 3)
549         {
550             if (value.addr.off + offset < value.addr.off)
551                 WINE_WARN("Address wrap around\n");
552             value.addr.off += offset;
553             SymAddSymbol(current_process->handle, BaseOfDll,
554                          name, addr, 0, 0);
555         }
556     }
557     fclose(symbolfile);
558 #endif
559 }
560
561 /***********************************************************************
562  *           symbol_get_function_line_status
563  *
564  * Find the symbol nearest to a given address.
565  */
566 enum dbg_line_status symbol_get_function_line_status(const ADDRESS64* addr)
567 {
568     IMAGEHLP_LINE64     il;
569     DWORD               disp;
570     ULONG64             disp64, start;
571     DWORD_PTR           lin = (DWORD_PTR)memory_to_linear_addr(addr);
572     char                buffer[sizeof(SYMBOL_INFO) + 256];
573     SYMBOL_INFO*        sym = (SYMBOL_INFO*)buffer;
574     struct dbg_type     func;
575
576     il.SizeOfStruct = sizeof(il);
577     sym->SizeOfStruct = sizeof(SYMBOL_INFO);
578     sym->MaxNameLen = sizeof(buffer) - sizeof(SYMBOL_INFO);
579
580     /* do we have some info for lin address ? */
581     if (!SymFromAddr(dbg_curr_process->handle, lin, &disp64, sym))
582     {
583         ADDRESS64   jumpee;
584         /* some compilers insert thunks in their code without debug info associated
585          * take care of this situation
586          */
587         if (be_cpu->is_jump((void*)lin, &jumpee))
588             return symbol_get_function_line_status(&jumpee);
589         return dbg_no_line_info;
590     }
591
592     switch (sym->Tag)
593     {
594     case SymTagThunk:
595         /* FIXME: so far dbghelp doesn't return the 16 <=> 32 thunks
596          * and furthermore, we no longer take care of them !!!
597          */
598         return dbg_in_a_thunk;
599     case SymTagFunction:
600     case SymTagPublicSymbol: break;
601     default:
602         WINE_FIXME("Unexpected sym-tag 0x%08x\n", sym->Tag);
603     case SymTagData:
604         return dbg_no_line_info;
605     }
606     /* we should have a function now */
607     if (!SymGetLineFromAddr64(dbg_curr_process->handle, lin, &disp, &il))
608         return dbg_no_line_info;
609
610     func.module = sym->ModBase;
611     func.id     = sym->info;
612
613     if (symbol_get_debug_start(&func, &start) && lin < start)
614         return dbg_not_on_a_line_number;
615
616     if (!sym->Size) sym->Size = 0x100000;
617     if (il.FileName && il.FileName[0] && disp < sym->Size)
618         return (disp == 0) ? dbg_on_a_line_number : dbg_not_on_a_line_number;
619
620     return dbg_no_line_info;
621 }
622
623 /***********************************************************************
624  *           symbol_get_line
625  *
626  * Find the symbol nearest to a given address.
627  * Returns sourcefile name and line number in a format that the listing
628  * handler can deal with.
629  */
630 BOOL symbol_get_line(const char* filename, const char* name,
631                      IMAGEHLP_LINE64* line)
632 {
633     struct sgv_data     sgv;
634     char                buffer[512];
635     DWORD               opt, disp;
636     unsigned            i, found = FALSE;
637     IMAGEHLP_LINE64     il;
638
639     sgv.num        = 0;
640     sgv.num_thunks = 0;
641     sgv.name       = &buffer[2];
642     sgv.do_thunks  = FALSE;
643
644     buffer[0] = '*';
645     buffer[1] = '!';
646     strcpy(&buffer[2], name);
647
648     /* this is a wine specific options to return also ELF modules in the
649      * enumeration
650      */
651     SymSetOptions((opt = SymGetOptions()) | 0x40000000);
652     if (!SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv))
653     {
654         SymSetOptions(opt);
655         return FALSE;
656     }
657
658     if (!sgv.num && (name[0] != '_'))
659     {
660         buffer[2] = '_';
661         strcpy(&buffer[3], name);
662         if (!SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv))
663         {
664             SymSetOptions(opt);
665             return FALSE;
666         }
667     }
668     SymSetOptions(opt);
669
670     for (i = 0; i < sgv.num; i++)
671     {
672         DWORD_PTR linear = (DWORD_PTR)memory_to_linear_addr(&sgv.syms[i].lvalue.addr);
673
674         il.SizeOfStruct = sizeof(il);
675         if (!SymGetLineFromAddr64(dbg_curr_process->handle, linear, &disp, &il))
676             continue;
677         if (filename && strcmp(il.FileName, filename)) continue;
678         if (found)
679         {
680             WINE_FIXME("Several found, returning first (may not be what you want)...\n");
681             break;
682         }
683         found = TRUE;
684         *line = il;
685     }
686     if (!found)
687     {
688         if (filename)   dbg_printf("No such function %s in %s\n", name, filename);
689         else            dbg_printf("No such function %s\n", name);
690         return FALSE;
691     }
692     return TRUE;
693 }
694
695 /******************************************************************
696  *              symbol_print_local
697  *
698  * Overall format is:
699  * <name>=<value>                       in non detailed form
700  * <name>=<value> (local|pmt <where>)   in detailed form
701  * Note <value> can be an error message in case of error
702  */
703 void symbol_print_local(const SYMBOL_INFO* sym, DWORD_PTR base, BOOL detailed)
704 {
705     struct dbg_lvalue   lvalue;
706     char                buffer[64];
707
708     dbg_printf("%s=", sym->Name);
709
710     if (fill_sym_lvalue(sym, base, &lvalue, buffer, sizeof(buffer)))
711     {
712         print_value(&lvalue, 0, 1);
713         if (detailed)
714             dbg_printf(" (%s%s)",
715                        (sym->Flags & SYMFLAG_PARAMETER) ? "parameter" : "local",
716                        buffer);
717     }
718     else
719     {
720         dbg_printf("%s", buffer);
721         if (detailed)
722             dbg_printf(" (%s)",
723                        (sym->Flags & SYMFLAG_PARAMETER) ? "parameter" : "local");
724     }
725 }
726
727 static BOOL CALLBACK info_locals_cb(PSYMBOL_INFO sym, ULONG size, PVOID ctx)
728 {
729     struct dbg_type     type;
730
731     dbg_printf("\t");
732     type.module = sym->ModBase;
733     type.id = sym->TypeIndex;
734     types_print_type(&type, FALSE);
735
736     dbg_printf(" ");
737     symbol_print_local(sym, (DWORD_PTR)ctx, TRUE);
738     dbg_printf("\n");
739
740     return TRUE;
741 }
742
743 int symbol_info_locals(void)
744 {
745     IMAGEHLP_STACK_FRAME        ihsf;
746     ADDRESS64                   addr;
747
748     stack_get_current_frame(&ihsf);
749     addr.Mode = AddrModeFlat;
750     addr.Offset = ihsf.InstructionOffset;
751     print_address(&addr, FALSE);
752     dbg_printf(": (%08lx)\n", (DWORD_PTR)ihsf.FrameOffset);
753     SymEnumSymbols(dbg_curr_process->handle, 0, NULL, info_locals_cb, (void*)(DWORD_PTR)ihsf.FrameOffset);
754
755     return TRUE;
756
757 }
758
759 static BOOL CALLBACK symbols_info_cb(PSYMBOL_INFO sym, ULONG size, PVOID ctx)
760 {
761     struct dbg_type     type;
762     IMAGEHLP_MODULE     mi;
763
764     mi.SizeOfStruct = sizeof(mi);
765
766     if (!SymGetModuleInfo(dbg_curr_process->handle, sym->ModBase, &mi))
767         mi.ModuleName[0] = '\0';
768     else
769     {
770         size_t  len = strlen(mi.ModuleName);
771         if (len > 5 && !strcmp(mi.ModuleName + len - 5, "<elf>"))
772             mi.ModuleName[len - 5] = '\0';
773     }
774
775     dbg_printf("%08lx: %s!%s", (ULONG_PTR)sym->Address, mi.ModuleName, sym->Name);
776     type.id = sym->TypeIndex;
777     type.module = sym->ModBase;
778
779     if (sym->TypeIndex != dbg_itype_none && sym->TypeIndex != 0)
780     {
781         dbg_printf(" ");
782         types_print_type(&type, FALSE);
783     }
784     dbg_printf("\n");
785     return TRUE;
786 }
787
788 void symbol_info(const char* str)
789 {
790     char        buffer[512];
791     DWORD       opt;
792
793     if (strlen(str) + 3 >= sizeof(buffer))
794     {
795         dbg_printf("Symbol too long (%s)\n", str);
796         return;
797     }
798     buffer[0] = '*';
799     buffer[1] = '!';
800     strcpy(&buffer[2], str);
801     /* this is a wine specific options to return also ELF modules in the
802      * enumeration
803      */
804     SymSetOptions((opt = SymGetOptions()) | 0x40000000);
805     SymEnumSymbols(dbg_curr_process->handle, 0, buffer, symbols_info_cb, NULL);
806     SymSetOptions(opt);
807 }