From eb25084eee0392f6a4cfb062e6638c7f52b40869 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Mon, 14 Jun 2004 17:58:31 +0000 Subject: [PATCH] - implemented EnumDirTree, SearchTreeForFile, SymFindFileInPath, SymMatchFileName - made use of SymFindFileInPath to lookup .dbg and .pdb files - fixed a crash in CodeView enum handling --- dlls/dbghelp/dbghelp.spec | 5 +- dlls/dbghelp/msc.c | 30 ++----- dlls/dbghelp/path.c | 171 ++++++++++++++++++++++++++++++++++++-- dlls/dbghelp/pe_module.c | 15 +++- dlls/dbghelp/type.c | 2 +- include/dbghelp.h | 4 + 6 files changed, 191 insertions(+), 36 deletions(-) diff --git a/dlls/dbghelp/dbghelp.spec b/dlls/dbghelp/dbghelp.spec index 3ae7bc7f220..d954230d7da 100644 --- a/dlls/dbghelp/dbghelp.spec +++ b/dlls/dbghelp/dbghelp.spec @@ -1,5 +1,6 @@ @ stub DbgHelpCreateUserDump @ stub DbgHelpCreateUserDumpW +@ stdcall EnumDirTree(long str str ptr ptr ptr) @ stdcall EnumerateLoadedModules(long ptr ptr) @ stub EnumerateLoadedModules64 @ stub ExtensionApiVersion @@ -35,7 +36,7 @@ @ stub SymEnumerateSymbols64 @ stub SymEnumerateSymbolsW @ stub SymEnumerateSymbolsW64 -@ stub SymFindFileInPath +@ stdcall SymFindFileInPath(long str str ptr long long long ptr ptr ptr) @ stdcall SymFromAddr(long long ptr ptr) @ stdcall SymFromName(long str ptr) @ stdcall SymFunctionTableAccess(long long) @@ -71,7 +72,7 @@ @ stdcall SymLoadModule(long long str str long long) @ stub SymLoadModule64 @ stub SymLoadModuleEx -@ stub SymMatchFileName +@ stdcall SymMatchFileName(str str ptr ptr) @ stub SymMatchString @ stdcall SymRegisterCallback(long ptr ptr) @ stub SymRegisterCallback64 diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c index eee9c5cce16..92196c89383 100644 --- a/dlls/dbghelp/msc.c +++ b/dlls/dbghelp/msc.c @@ -2676,12 +2676,10 @@ static void pdb_convert_symbols_header(PDB_SYMBOLS* symbols, } } -static const char* get_last_sep(const char* str) +static BOOL CALLBACK pdb_match(char* file, void* user) { - char* a; - - if ((a = strrchr(str, '/'))) str = a; - return (a = strrchr(str, '\\')) ? a : str; + /* accept first file */ + return FALSE; } static HANDLE open_pdb_file(const struct process* pcs, struct module* module, @@ -2692,23 +2690,13 @@ static HANDLE open_pdb_file(const struct process* pcs, struct module* module, h = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (h == INVALID_HANDLE_VALUE) + /* FIXME: should give more bits on the file to look at */ + if (h == INVALID_HANDLE_VALUE && + SymFindFileInPath(pcs->handle, NULL, (char*)filename, NULL, 0, 0, 0, + dbg_file_path, pdb_match, NULL)) { - h = FindDebugInfoFile((char*)filename, pcs->search_path, dbg_file_path); - if (h == NULL) - { - const char* p; - const char* q; - - strcpy(dbg_file_path, module->module.LoadedImageName); - if ((p = get_last_sep(dbg_file_path))) - { - if ((q = get_last_sep(filename))) q++; else q = filename; - strcpy((char*)p + 1, q); - h = CreateFileA(dbg_file_path, GENERIC_READ, FILE_SHARE_READ, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - } - } + h = CreateFileA(dbg_file_path, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); } return (h == INVALID_HANDLE_VALUE) ? NULL : h; } diff --git a/dlls/dbghelp/path.c b/dlls/dbghelp/path.c index 7f7c0f65d16..c8a1a6504ca 100644 --- a/dlls/dbghelp/path.c +++ b/dlls/dbghelp/path.c @@ -28,6 +28,16 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); +static inline BOOL is_sep(char ch) {return ch == '/' || ch == '\\';} + +static inline char* file_name(char* str) +{ + char* p; + + for (p = str + strlen(str) - 1; p >= str && !is_sep(*p); p--); + return p + 1; +} + /****************************************************************** * FindDebugInfoFile (DBGHELP.@) * @@ -40,9 +50,7 @@ HANDLE WINAPI FindDebugInfoFile(PSTR FileName, PSTR SymbolPath, PSTR DebugFilePa OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) { - const char* p = strrchr(FileName, '/'); - if (!p) p = FileName; - if (!SearchPathA(SymbolPath, p, NULL, MAX_PATH, DebugFilePath, NULL)) + if (!SearchPathA(SymbolPath, file_name(FileName), NULL, MAX_PATH, DebugFilePath, NULL)) return NULL; h = CreateFileA(DebugFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); @@ -92,15 +100,160 @@ BOOL WINAPI MakeSureDirectoryPathExists(LPCSTR DirPath) return FALSE; } +/****************************************************************** + * SymMatchFileName (DBGHELP.@) + * + */ +BOOL WINAPI SymMatchFileName(char* file, char* match, + char** filestop, char** matchstop) +{ + char* fptr; + char* mptr; + + TRACE("(%s %s %p %p)\n", file, match, filestop, matchstop); + + fptr = file + strlen(file) - 1; + mptr = match + strlen(match) - 1; + + while (fptr >= file && mptr >= match) + { + if (toupper(*fptr) != toupper(*mptr) && !(is_sep(*fptr) && is_sep(*mptr))) + break; + fptr--; mptr--; + } + if (filestop) *filestop = fptr; + if (matchstop) *matchstop = mptr; + + return mptr == match - 1; +} + +static BOOL do_search(const char* file, char* buffer, + PENUMDIRTREE_CALLBACK cb, void* user) +{ + HANDLE h; + WIN32_FIND_DATAA fd; + unsigned pos; + BOOL found = FALSE; + + pos = strlen(buffer); + if (buffer[pos - 1] != '\\') buffer[pos++] = '\\'; + strcpy(buffer + pos, "*.*"); + if ((h = FindFirstFileA(buffer, &fd)) == INVALID_HANDLE_VALUE) + return FALSE; + /* doc doesn't specify how the tree is enumerated... + * doing a depth first based on, but may be wrong + */ + do + { + if (!strcmp(fd.cFileName, ".") || !strcmp(fd.cFileName, "..")) continue; + + strcpy(buffer + pos, fd.cFileName); + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + found = do_search(file, buffer, cb, user); + else if (SymMatchFileName(buffer, (char*)file, NULL, NULL)) + { + if (!cb || cb(buffer, user)) found = TRUE; + } + } while (!found && FindNextFileA(h, &fd)); + if (!found) buffer[--pos] = '\0'; + FindClose(h); + + return found; +} + /*********************************************************************** * SearchTreeForFile (DBGHELP.@) */ -BOOL WINAPI SearchTreeForFile(LPSTR RootPath, LPSTR InputPathName, - LPSTR OutputPathBuffer) +BOOL WINAPI SearchTreeForFile(LPSTR root, LPSTR file, LPSTR buffer) { - FIXME("(%s, %s, %s): stub\n", - debugstr_a(RootPath), debugstr_a(InputPathName), - debugstr_a(OutputPathBuffer)); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + TRACE("(%s, %s, %p)\n", + debugstr_a(root), debugstr_a(file), buffer); + strcpy(buffer, root); + return do_search(file, buffer, NULL, NULL); +} + +/****************************************************************** + * EnumDirTree (DBGHELP.@) + * + * + */ +BOOL WINAPI EnumDirTree(HANDLE hProcess, PCSTR root, PCSTR file, + LPSTR buffer, PENUMDIRTREE_CALLBACK cb, void* user) +{ + TRACE("(%p %s %s %p %p %p)\n", hProcess, root, file, buffer, cb, user); + + strcpy(buffer, root); + return do_search(file, buffer, cb, user); +} + +struct sffip +{ + PVOID id; + DWORD two; + DWORD three; + DWORD flags; + PFINDFILEINPATHCALLBACK cb; + void* user; +}; + +static BOOL CALLBACK sffip_cb(LPCSTR buffer, void* user) +{ + struct sffip* s = (struct sffip*)user; + + /* FIXME: should check that id/two/three match the file pointed + * by buffer + */ + /* yes, EnumDirTree and SymFindFileInPath callbacks use the opposite + * convention to stop/continue enumeration. sigh. + */ + return !(s->cb)((char*)buffer, s->user); +} + +/****************************************************************** + * SymFindFileInPath (DBGHELP.@) + * + */ +BOOL WINAPI SymFindFileInPath(HANDLE hProcess, LPSTR searchPath, LPSTR file, + PVOID id, DWORD two, DWORD three, DWORD flags, + LPSTR buffer, PFINDFILEINPATHCALLBACK cb, + PVOID user) +{ + struct sffip s; + struct process* pcs = process_find_by_handle(hProcess); + char tmp[MAX_PATH]; + char* ptr; + + TRACE("(%p %s %s %p %08lx %08lx %08lx %p %p %p)\n", + hProcess, searchPath, file, id, two, three, flags, + buffer, cb, user); + + if (!pcs) return FALSE; + if (!searchPath) searchPath = pcs->search_path; + + s.id = id; + s.two = two; + s.three = three; + s.flags = flags; + s.cb = cb; + s.user = user; + + file = file_name(file); + + while (searchPath) + { + ptr = strchr(searchPath, ';'); + if (ptr) + { + memcpy(tmp, searchPath, ptr - searchPath); + tmp[ptr - searchPath] = 0; + searchPath = ptr + 1; + } + else + { + strcpy(tmp, searchPath); + searchPath = NULL; + } + if (EnumDirTree(hProcess, tmp, file, buffer, sffip_cb, &s)) return TRUE; + } return FALSE; } diff --git a/dlls/dbghelp/pe_module.c b/dlls/dbghelp/pe_module.c index 091afb7191f..cf7ba1193b6 100644 --- a/dlls/dbghelp/pe_module.c +++ b/dlls/dbghelp/pe_module.c @@ -72,6 +72,12 @@ static SYM_TYPE pe_load_stabs(const struct process* pcs, struct module* module, return sym_type; } +static BOOL CALLBACK dbg_match(char* file, void* user) +{ + /* accept first file */ + return FALSE; +} + /****************************************************************** * pe_load_dbg_file * @@ -81,7 +87,7 @@ static SYM_TYPE pe_load_dbg_file(const struct process* pcs, struct module* modul const char* dbg_name, DWORD timestamp) { char tmp[MAX_PATH]; - HANDLE hFile, hMap = 0; + HANDLE hFile = INVALID_HANDLE_VALUE, hMap = 0; const BYTE* dbg_mapping = NULL; const IMAGE_SEPARATE_DEBUG_HEADER* hdr; const IMAGE_DEBUG_DIRECTORY* dbg; @@ -89,8 +95,11 @@ static SYM_TYPE pe_load_dbg_file(const struct process* pcs, struct module* modul WINE_TRACE("Processing DBG file %s\n", dbg_name); - tmp[0] = '\0'; - if ((hFile = FindDebugInfoFile((char*)dbg_name, pcs->search_path, tmp)) != NULL && + if (SymFindFileInPath(pcs->handle, NULL, (char*)dbg_name, + NULL, 0, 0, 0, + tmp, dbg_match, NULL) && + (hFile = CreateFileA(tmp, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE && ((hMap = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != 0) && ((dbg_mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL)) { diff --git a/dlls/dbghelp/type.c b/dlls/dbghelp/type.c index ee81af7c0d6..5595b9e6f69 100644 --- a/dlls/dbghelp/type.c +++ b/dlls/dbghelp/type.c @@ -238,7 +238,7 @@ struct symt_enum* symt_new_enum(struct module* module, const char* typename) if ((sym = pool_alloc(&module->pool, sizeof(*sym)))) { sym->symt.tag = SymTagEnum; - sym->name = pool_strdup(&module->pool, typename); + sym->name = (typename) ? pool_strdup(&module->pool, typename) : NULL; vector_init(&sym->vchildren, sizeof(struct symt*), 8); } return sym; diff --git a/include/dbghelp.h b/include/dbghelp.h index a5b468f099f..110dad34068 100644 --- a/include/dbghelp.h +++ b/include/dbghelp.h @@ -749,6 +749,10 @@ BOOL WINAPI SymSetSearchPath(HANDLE,PSTR); DWORD WINAPI GetTimestampForLoadedLibrary(HMODULE); BOOL WINAPI MakeSureDirectoryPathExists(PCSTR); BOOL WINAPI SearchTreeForFile(PSTR,PSTR,PSTR); +typedef BOOL (CALLBACK *PENUMDIRTREE_CALLBACK)(LPCSTR path, PVOID user); +BOOL WINAPI EnumDirTree(HANDLE hProcess, PCSTR root, PCSTR file, + LPSTR buffer, PENUMDIRTREE_CALLBACK cb, void* user); +BOOL WINAPI SymMatchFileName(LPSTR file, LPSTR match, LPSTR* filestop, LPSTR* matchstop); /************************* * Context management *