/* * File hash.c - generate hash tables for Wine debugger symbols * * Copyright (C) 1993, Eric Youngdale. */ #include #include #include #include #include #include "module.h" #include "selectors.h" #include "debugger.h" #include "toolhelp.h" #include "xmalloc.h" #define NR_NAME_HASH 128 static struct name_hash * name_hash_table[NR_NAME_HASH]; static unsigned int name_hash( const char * name ) { unsigned int hash = 0; const char * p; p = name; while (*p) hash = (hash << 15) + (hash << 3) + (hash >> 3) + *p++; return hash % NR_NAME_HASH; } /*********************************************************************** * DEBUG_AddSymbol * * Add a symbol to the table. */ struct name_hash * DEBUG_AddSymbol( const char * name, const DBG_ADDR *addr, const char * source ) { struct name_hash * new; int hash; new = (struct name_hash *) xmalloc(sizeof(struct name_hash)); new->addr = *addr; new->name = xstrdup(name); if( source != NULL ) { new->sourcefile = xstrdup(source); } else { new->sourcefile = NULL; } new->n_lines = 0; new->lines_alloc = 0; new->linetab = NULL; new->n_locals = 0; new->locals_alloc = 0; new->local_vars = NULL; new->next = NULL; hash = name_hash(name); /* Now insert into the hash table */ new->next = name_hash_table[hash]; name_hash_table[hash] = new; return new; } /*********************************************************************** * DEBUG_GetSymbolValue * * Get the address of a named symbol. */ BOOL32 DEBUG_GetSymbolValue( const char * name, const int lineno, DBG_ADDR *addr ) { char buffer[256]; int i; struct name_hash *nh; for(nh = name_hash_table[name_hash(name)]; nh; nh = nh->next) if (!strcmp(nh->name, name)) break; if (!nh && (name[0] != '_')) { buffer[0] = '_'; strcpy(buffer+1, name); for(nh = name_hash_table[name_hash(buffer)]; nh; nh = nh->next) if (!strcmp(nh->name, buffer)) break; } /* * If we don't have anything here, then try and see if this * is a local symbol to the current stack frame. No matter * what, we have nothing more to do, so we let that function * decide what we ultimately return. */ if (!nh) return DEBUG_GetStackSymbolValue(name, addr); if( lineno == -1 ) { *addr = nh->addr; } else { /* * Search for the specific line number. If we don't find it, * then return FALSE. */ if( nh->linetab == NULL ) { return FALSE; } for(i=0; i < nh->n_lines; i++ ) { if( nh->linetab[i].line_number == lineno ) { *addr = nh->linetab[i].pc_offset; return TRUE; } } /* * This specific line number not found. */ return FALSE; } return TRUE; } /*********************************************************************** * DEBUG_SetSymbolValue * * Set the address of a named symbol. */ BOOL32 DEBUG_SetSymbolValue( const char * name, const DBG_ADDR *addr ) { char buffer[256]; struct name_hash *nh; for(nh = name_hash_table[name_hash(name)]; nh; nh = nh->next) if (!strcmp(nh->name, name)) break; if (!nh && (name[0] != '_')) { buffer[0] = '_'; strcpy(buffer+1, name); for(nh = name_hash_table[name_hash(buffer)]; nh; nh = nh->next) if (!strcmp(nh->name, buffer)) break; } if (!nh) return FALSE; nh->addr = *addr; DBG_FIX_ADDR_SEG( &nh->addr, DS_reg(DEBUG_context) ); return TRUE; } /*********************************************************************** * DEBUG_FindNearestSymbol * * Find the symbol nearest to a given address. * If ebp is specified as non-zero, it means we should dump the argument * list into the string we return as well. */ const char * DEBUG_FindNearestSymbol( const DBG_ADDR *addr, int flag, struct name_hash ** rtn, unsigned int ebp) { static char name_buffer[MAX_PATH + 256]; static char arglist[1024]; static char argtmp[256]; struct name_hash * nearest = NULL; struct name_hash * nh; unsigned int nearest_address = 0; unsigned int * ptr; int lineno; char * lineinfo, *sourcefile; int i; char linebuff[16]; *rtn = NULL; for(i=0; inext) if (nh->addr.seg == addr->seg && nh->addr.off <= addr->off && nh->addr.off >= nearest_address) { nearest_address = nh->addr.off; nearest = nh; } } if (!nearest) return NULL; *rtn = nearest; lineinfo = ""; lineno = -1; memset(arglist, '\0', sizeof(arglist)); if( ebp != 0 ) { for(i=0; i < nearest->n_locals; i++ ) { /* * If this is a register (offset == 0) or a local * variable, we don't want to know about it. */ if( nearest->local_vars[i].offset <= 0 ) { continue; } ptr = (unsigned int *) (ebp + nearest->local_vars[i].offset); if( arglist[0] == '\0' ) { arglist[0] = '('; } else { strcat(arglist, ", "); } sprintf(argtmp, "%s=0x%x", nearest->local_vars[i].name, *ptr); strcat(arglist, argtmp); } if( arglist[0] == '(' ) { strcat(arglist, ")"); } } if( (nearest->sourcefile != NULL) && (flag == TRUE) && (addr->off - nearest->addr.off < 0x100000) ) { /* * Try and find the nearest line number to the current offset. */ if( nearest->linetab != NULL ) { /* * FIXME - this is an inefficient linear search. A binary * search would be better if this gets to be a performance * bottleneck. */ for(i=0; i < nearest->n_lines; i++) { if( addr->off < nearest->linetab[i].pc_offset.off ) { break; } lineno = nearest->linetab[i].line_number; } } if( lineno != -1 ) { sprintf(linebuff, ":%d", lineno); lineinfo = linebuff; } /* Remove the path from the file name */ sourcefile = strrchr( nearest->sourcefile, '/' ); if (!sourcefile) sourcefile = nearest->sourcefile; else sourcefile++; if (addr->off == nearest->addr.off) sprintf( name_buffer, "%s%s [%s%s]", nearest->name, arglist, sourcefile, lineinfo); else sprintf( name_buffer, "%s+0x%lx%s [%s%s]", nearest->name, addr->off - nearest->addr.off, arglist, sourcefile, lineinfo ); } else { if (addr->off == nearest->addr.off) sprintf( name_buffer, "%s%s", nearest->name, arglist); else sprintf( name_buffer, "%s+0x%lx%s", nearest->name, addr->off - nearest->addr.off, arglist); } return name_buffer; } /*********************************************************************** * DEBUG_ReadSymbolTable * * Read a symbol file into the hash table. */ void DEBUG_ReadSymbolTable( const char * filename ) { FILE * symbolfile; DBG_ADDR addr = { 0, 0 }; int nargs; char type; char * cpnt; char buffer[256]; char name[256]; if (!(symbolfile = fopen(filename, "r"))) { fprintf( stderr, "Unable to open symbol table %s\n", filename ); return; } fprintf( stderr, "Reading symbols from file %s\n", filename ); while (1) { fgets( buffer, sizeof(buffer), symbolfile ); if (feof(symbolfile)) break; /* Strip any text after a # sign (i.e. comments) */ cpnt = buffer; while (*cpnt) if(*cpnt++ == '#') { *cpnt = 0; break; } /* Quietly ignore any lines that have just whitespace */ cpnt = buffer; while(*cpnt) { if(*cpnt != ' ' && *cpnt != '\t') break; cpnt++; } if (!(*cpnt) || *cpnt == '\n') continue; nargs = sscanf(buffer, "%lx %c %s", &addr.off, &type, name); DEBUG_AddSymbol( name, &addr, NULL ); } fclose(symbolfile); } /*********************************************************************** * DEBUG_LoadEntryPoints * * Load the entry points of all the modules into the hash table. */ void DEBUG_LoadEntryPoints(void) { MODULEENTRY entry; NE_MODULE *pModule; DBG_ADDR addr; char buffer[256]; unsigned char *cpnt, *name; FARPROC16 address; BOOL32 ok; for (ok = ModuleFirst(&entry); ok; ok = ModuleNext(&entry)) { if (!(pModule = MODULE_GetPtr( entry.hModule ))) continue; name = (unsigned char *)pModule + pModule->name_table; /* First search the resident names */ cpnt = (unsigned char *)pModule + pModule->name_table; while (*cpnt) { cpnt += *cpnt + 1 + sizeof(WORD); sprintf( buffer, "%*.*s.%*.*s", *name, *name, name + 1, *cpnt, *cpnt, cpnt + 1 ); if ((address = MODULE_GetEntryPoint( entry.hModule, *(WORD *)(cpnt + *cpnt + 1) ))) { addr.seg = HIWORD(address); addr.off = LOWORD(address); DEBUG_AddSymbol( buffer, &addr, NULL ); } } /* Now search the non-resident names table */ if (!pModule->nrname_handle) continue; /* No non-resident table */ cpnt = (char *)GlobalLock16( pModule->nrname_handle ); while (*cpnt) { cpnt += *cpnt + 1 + sizeof(WORD); sprintf( buffer, "%*.*s.%*.*s", *name, *name, name + 1, *cpnt, *cpnt, cpnt + 1 ); if ((address = MODULE_GetEntryPoint( entry.hModule, *(WORD *)(cpnt + *cpnt + 1) ))) { addr.seg = HIWORD(address); addr.off = LOWORD(address); DEBUG_AddSymbol( buffer, &addr, NULL); } } } } void DEBUG_AddLineNumber( struct name_hash * func, int line_num, unsigned long offset ) { if( func == NULL ) { return; } if( func->n_lines + 1 >= func->lines_alloc ) { func->lines_alloc += 32; func->linetab = realloc(func->linetab, func->lines_alloc * sizeof(WineLineNo)); } func->linetab[func->n_lines].line_number = line_num; func->linetab[func->n_lines].pc_offset.seg = func->addr.seg; func->linetab[func->n_lines].pc_offset.off = func->addr.off + offset; func->n_lines++; } void DEBUG_AddLocal( struct name_hash * func, int regno, int offset, int pc_start, int pc_end, char * name) { if( func == NULL ) { return; } if( func->n_locals + 1 >= func->locals_alloc ) { func->locals_alloc += 32; func->local_vars = realloc(func->local_vars, func->locals_alloc * sizeof(WineLocals)); } func->local_vars[func->n_locals].regno = regno; func->local_vars[func->n_locals].offset = offset; func->local_vars[func->n_locals].pc_start = pc_start; func->local_vars[func->n_locals].pc_end = pc_end; func->local_vars[func->n_locals].name = xstrdup(name); func->n_locals++; }