dbghelp: Better support for OOM conditions when creating source file table.
[wine] / dlls / dbghelp / source.c
1 /*
2  * File source.c - source files management
3  *
4  * Copyright (C) 2004,      Eric Pouech.
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  */
21 #include "config.h"
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <assert.h>
26
27 #include "dbghelp_private.h"
28 #include "wine/debug.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
31
32 /******************************************************************
33  *              source_find
34  *
35  * check whether a source file has already been stored
36  */
37 static unsigned source_find(const struct module* module, const char* name)
38 {
39     char*       ptr = module->sources;
40
41     while (*ptr)
42     {
43         if (strcmp(ptr, name) == 0) return ptr - module->sources;
44         ptr += strlen(ptr) + 1;
45     }
46     return (unsigned)-1;
47 }
48
49 /******************************************************************
50  *              source_new
51  *
52  * checks if source exists. if not, add it
53  */
54 unsigned source_new(struct module* module, const char* base, const char* name)
55 {
56     unsigned    ret;
57     const char* full;
58     char*       tmp = NULL;
59
60     if (!name) return (unsigned)-1;
61     if (!base || *name == '/')
62         full = name;
63     else
64     {
65         unsigned bsz = strlen(base);
66
67         tmp = HeapAlloc(GetProcessHeap(), 0, bsz + 1 + strlen(name) + 1);
68         if (!tmp) return (unsigned)-1;
69         full = tmp;
70         strcpy(tmp, base);
71         if (tmp[bsz - 1] != '/') tmp[bsz++] = '/';
72         strcpy(&tmp[bsz], name);
73     }
74     if (!module->sources || (ret = source_find(module, full)) == (unsigned)-1)
75     {
76         char* new;
77         int len = strlen(full) + 1;
78         if (module->sources_used + len + 1 > module->sources_alloc)
79         {
80             if (!module->sources)
81             {
82                 module->sources_alloc = (module->sources_used + len + 1 + 255) & ~255;
83                 new = HeapAlloc(GetProcessHeap(), 0, module->sources_alloc);
84             }
85             else
86             {
87                 module->sources_alloc = max( module->sources_alloc * 2,
88                                              (module->sources_used + len + 1 + 255) & ~255 );
89                 new = HeapReAlloc(GetProcessHeap(), 0, module->sources,
90                                   module->sources_alloc);
91             }
92             if (!new) goto done;
93             module->sources = new;
94         }
95         ret = module->sources_used;
96         memcpy(module->sources + module->sources_used, full, len);
97         module->sources_used += len;
98         module->sources[module->sources_used] = '\0';
99     }
100 done:
101     HeapFree(GetProcessHeap(), 0, tmp);
102     return ret;
103 }
104
105 /******************************************************************
106  *              source_get
107  *
108  * returns a stored source file name
109  */
110 const char* source_get(const struct module* module, unsigned idx)
111 {
112     if (idx == -1) return "";
113     assert(module->sources);
114     return module->sources + idx;
115 }
116
117 /******************************************************************
118  *              SymEnumSourceFiles (DBGHELP.@)
119  *
120  */
121 BOOL WINAPI SymEnumSourceFiles(HANDLE hProcess, ULONG64 ModBase, PCSTR Mask,
122                                PSYM_ENUMSOURCEFILES_CALLBACK cbSrcFiles,
123                                PVOID UserContext)
124 {
125     struct module_pair  pair;
126     SOURCEFILE          sf;
127     char*               ptr;
128     
129     if (!cbSrcFiles) return FALSE;
130     pair.pcs = process_find_by_handle(hProcess);
131     if (!pair.pcs) return FALSE;
132          
133     if (ModBase)
134     {
135         pair.requested = module_find_by_addr(pair.pcs, ModBase, DMT_UNKNOWN);
136         if (!module_get_debug(&pair)) return FALSE;
137     }
138     else
139     {
140         if (Mask[0] == '!')
141         {
142             pair.requested = module_find_by_nameA(pair.pcs, Mask + 1);
143             if (!module_get_debug(&pair)) return FALSE;
144         }
145         else
146         {
147             FIXME("Unsupported yet (should get info from current context)\n");
148             return FALSE;
149         }
150     }
151     if (!pair.effective->sources) return FALSE;
152     for (ptr = pair.effective->sources; *ptr; ptr += strlen(ptr) + 1)
153     {
154         /* FIXME: not using Mask */
155         sf.ModBase = ModBase;
156         sf.FileName = ptr;
157         if (!cbSrcFiles(&sf, UserContext)) break;
158     }
159
160     return TRUE;
161 }
162
163 /******************************************************************
164  *              SymGetSourceFileToken (DBGHELP.@)
165  *
166  */
167 BOOL WINAPI SymGetSourceFileToken(HANDLE hProcess, ULONG64 base,
168                                   PCSTR src, PVOID* token, DWORD* size)
169 {
170     FIXME("%p %s %s %p %p: stub!\n",
171           hProcess, wine_dbgstr_longlong(base), debugstr_a(src), token, size);
172     SetLastError(ERROR_NOT_SUPPORTED);
173     return FALSE;
174 }
175
176 /******************************************************************
177  *              SymGetSourceFileTokenW (DBGHELP.@)
178  *
179  */
180 BOOL WINAPI SymGetSourceFileTokenW(HANDLE hProcess, ULONG64 base,
181                                    PCWSTR src, PVOID* token, DWORD* size)
182 {
183     FIXME("%p %s %s %p %p: stub!\n",
184           hProcess, wine_dbgstr_longlong(base), debugstr_w(src), token, size);
185     SetLastError(ERROR_NOT_SUPPORTED);
186     return FALSE;
187 }