- implemented EnumDirTree, SearchTreeForFile, SymFindFileInPath,
  SymMatchFileName
- made use of SymFindFileInPath to lookup .dbg and .pdb files
- fixed a crash in CodeView enum handling

diff --git a/dlls/dbghelp/dbghelp.spec b/dlls/dbghelp/dbghelp.spec
index 3ae7bc7..d954230 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 eee9c5c..92196c8 100644
--- a/dlls/dbghelp/msc.c
+++ b/dlls/dbghelp/msc.c
@@ -2676,12 +2676,10 @@
     }
 }
 
-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 @@
 
     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 7f7c0f6..c8a1a65 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 @@
                     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 @@
     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 091afb7..cf7ba11 100644
--- a/dlls/dbghelp/pe_module.c
+++ b/dlls/dbghelp/pe_module.c
@@ -72,6 +72,12 @@
     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 @@
                                  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 @@
 
     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 ee81af7..5595b9e 100644
--- a/dlls/dbghelp/type.c
+++ b/dlls/dbghelp/type.c
@@ -238,7 +238,7 @@
     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 a5b468f..110dad3 100644
--- a/include/dbghelp.h
+++ b/include/dbghelp.h
@@ -749,6 +749,10 @@
 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  *