Release 951105
[wine] / debugger / hash.c
1 /*
2  * File hash.c - generate hash tables for Wine debugger symbols
3  *
4  * Copyright (C) 1993, Eric Youngdale.
5  */
6
7
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <sys/types.h>
12 #include <neexe.h>
13 #include "module.h"
14 #include "selectors.h"
15 #include "debugger.h"
16 #include "toolhelp.h"
17 #include "xmalloc.h"
18
19 struct name_hash
20 {
21     struct name_hash * next;
22     char *             name;
23     DBG_ADDR           addr;
24 };
25
26 #define NR_NAME_HASH 128
27
28 static struct name_hash * name_hash_table[NR_NAME_HASH] = {0,};
29
30 static unsigned int name_hash( const char * name )
31 {
32     unsigned int hash = 0;
33     const char * p;
34
35     p = name;
36
37     while (*p) hash = (hash << 15) + (hash << 3) + (hash >> 3) + *p++;
38     return hash % NR_NAME_HASH;
39 }
40
41
42 /***********************************************************************
43  *           DEBUG_AddSymbol
44  *
45  * Add a symbol to the table.
46  */
47 void DEBUG_AddSymbol( const char * name, const DBG_ADDR *addr )
48 {
49     struct name_hash  * new;
50     int hash;
51
52     new = (struct name_hash *) xmalloc(sizeof(struct name_hash));
53     new->addr = *addr;
54     new->name = strdup(name);
55     new->next = NULL;
56     hash = name_hash(name);
57
58     /* Now insert into the hash table */
59     new->next = name_hash_table[hash];
60     name_hash_table[hash] = new;
61 }
62
63
64 /***********************************************************************
65  *           DEBUG_GetSymbolValue
66  *
67  * Get the address of a named symbol.
68  */
69 BOOL DEBUG_GetSymbolValue( const char * name, DBG_ADDR *addr )
70 {
71     char buffer[256];
72     struct name_hash *nh;
73
74     for(nh = name_hash_table[name_hash(name)]; nh; nh = nh->next)
75         if (!strcmp(nh->name, name)) break;
76
77     if (!nh && (name[0] != '_'))
78     {
79         buffer[0] = '_';
80         strcpy(buffer+1, name);
81         for(nh = name_hash_table[name_hash(buffer)]; nh; nh = nh->next)
82             if (!strcmp(nh->name, buffer)) break;
83     }
84
85     if (!nh) return FALSE;
86     *addr = nh->addr;
87     return TRUE;
88 }
89
90
91 /***********************************************************************
92  *           DEBUG_SetSymbolValue
93  *
94  * Set the address of a named symbol.
95  */
96 BOOL DEBUG_SetSymbolValue( const char * name, const DBG_ADDR *addr )
97 {
98     char buffer[256];
99     struct name_hash *nh;
100
101     for(nh = name_hash_table[name_hash(name)]; nh; nh = nh->next)
102         if (!strcmp(nh->name, name)) break;
103
104     if (!nh && (name[0] != '_'))
105     {
106         buffer[0] = '_';
107         strcpy(buffer+1, name);
108         for(nh = name_hash_table[name_hash(buffer)]; nh; nh = nh->next)
109             if (!strcmp(nh->name, buffer)) break;
110     }
111
112     if (!nh) return FALSE;
113     nh->addr = *addr;
114     DBG_FIX_ADDR_SEG( &nh->addr, DS_reg(DEBUG_context) );
115     return TRUE;
116 }
117
118
119 /***********************************************************************
120  *           DEBUG_FindNearestSymbol
121  *
122  * Find the symbol nearest to a given address.
123  */
124 const char * DEBUG_FindNearestSymbol( const DBG_ADDR *addr )
125 {
126     static char name_buffer[256];
127     struct name_hash * nearest = NULL;
128     struct name_hash * nh;
129     unsigned int nearest_address = 0;
130     int i;
131
132     for(i=0; i<NR_NAME_HASH; i++)
133     {
134         for (nh = name_hash_table[i]; nh; nh = nh->next)
135             if (nh->addr.seg == addr->seg &&
136                 nh->addr.off <= addr->off &&
137                 nh->addr.off >= nearest_address)
138             {
139                 nearest_address = nh->addr.off;
140                 nearest = nh;
141             }
142     }
143     if (!nearest) return NULL;
144
145     if (addr->off == nearest->addr.off)
146         sprintf( name_buffer, "%s", nearest->name );
147     else
148         sprintf( name_buffer, "%s+0x%lx", nearest->name,
149                 addr->off - nearest->addr.off );
150     return name_buffer;
151 }
152
153
154 /***********************************************************************
155  *           DEBUG_ReadSymbolTable
156  *
157  * Read a symbol file into the hash table.
158  */
159 void DEBUG_ReadSymbolTable( const char * filename )
160 {
161     FILE * symbolfile;
162     DBG_ADDR addr = { 0, 0 };
163     int nargs;
164     char type;
165     char * cpnt;
166     char buffer[256];
167     char name[256];
168
169     if (!(symbolfile = fopen(filename, "r")))
170     {
171         fprintf( stderr, "Unable to open symbol table %s\n", filename );
172         return;
173     }
174
175     fprintf( stderr, "Reading symbols from file %s\n", filename );
176
177     while (1)
178     {
179         fgets( buffer, sizeof(buffer), symbolfile );
180         if (feof(symbolfile)) break;
181                 
182         /* Strip any text after a # sign (i.e. comments) */
183         cpnt = buffer;
184         while (*cpnt)
185             if(*cpnt++ == '#') { *cpnt = 0; break; }
186                 
187         /* Quietly ignore any lines that have just whitespace */
188         cpnt = buffer;
189         while(*cpnt)
190         {
191             if(*cpnt != ' ' && *cpnt != '\t') break;
192             cpnt++;
193         }
194         if (!(*cpnt) || *cpnt == '\n') continue;
195                 
196         nargs = sscanf(buffer, "%lx %c %s", &addr.off, &type, name);
197         DEBUG_AddSymbol( name, &addr );
198     }
199     fclose(symbolfile);
200 }
201
202
203 /***********************************************************************
204  *           DEBUG_LoadEntryPoints
205  *
206  * Load the entry points of all the modules into the hash table.
207  */
208 void DEBUG_LoadEntryPoints(void)
209 {
210     MODULEENTRY entry;
211     NE_MODULE *pModule;
212     DBG_ADDR addr;
213     char buffer[256];
214     unsigned char *cpnt, *name;
215     unsigned int address;
216     BOOL ok;
217
218     fprintf( stderr, "Adding symbols from loaded modules\n" );
219     for (ok = ModuleFirst(&entry); ok; ok = ModuleNext(&entry))
220     {
221         if (!(pModule = (NE_MODULE *)GlobalLock( entry.hModule ))) continue;
222
223         name = (unsigned char *)pModule + pModule->name_table;
224
225         /* First search the resident names */
226
227         cpnt = (unsigned char *)pModule + pModule->name_table;
228         while (*cpnt)
229         {
230             cpnt += *cpnt + 1 + sizeof(WORD);
231             sprintf( buffer, "%*.*s.%*.*s", *name, *name, name + 1,
232                      *cpnt, *cpnt, cpnt + 1 );
233             if ((address = MODULE_GetEntryPoint( entry.hModule,
234                                             *(WORD *)(cpnt + *cpnt + 1) )))
235             {
236                 addr.seg = HIWORD(address);
237                 addr.off = LOWORD(address);
238                 DEBUG_AddSymbol( buffer, &addr );
239             }
240         }
241
242         /* Now search the non-resident names table */
243
244         if (!pModule->nrname_handle) continue;  /* No non-resident table */
245         cpnt = (char *)GlobalLock( pModule->nrname_handle );
246         while (*cpnt)
247         {
248             cpnt += *cpnt + 1 + sizeof(WORD);
249             sprintf( buffer, "%*.*s.%*.*s", *name, *name, name + 1,
250                      *cpnt, *cpnt, cpnt + 1 );
251             if ((address = MODULE_GetEntryPoint( entry.hModule,
252                                                 *(WORD *)(cpnt + *cpnt + 1) )))
253             {
254                 addr.seg = HIWORD(address);
255                 addr.off = LOWORD(address);
256                 DEBUG_AddSymbol( buffer, &addr );
257             }
258         }
259     }
260 }