/*
* File path.c - managing path in debugging environments
*
- * Copyright (C) 2004, Eric Pouech
+ * Copyright (C) 2004,2008, Eric Pouech
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
{
HANDLE h;
- h = CreateFileA(DebugFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
+ h = CreateFileA(FileName, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (h == INVALID_HANDLE_VALUE)
{
PVOID CallerData)
{
FIXME("(%s %s %p %p %p): stub\n",
- FileName, SymbolPath, DebugFilePath, Callback, CallerData);
+ debugstr_a(FileName), debugstr_a(SymbolPath), debugstr_a(DebugFilePath), Callback, CallerData);
return NULL;
}
PCSTR fptr;
PCSTR mptr;
- TRACE("(%s %s %p %p)\n", file, match, filestop, matchstop);
+ TRACE("(%s %s %p %p)\n", debugstr_a(file), debugstr_a(match), filestop, matchstop);
fptr = file + strlen(file) - 1;
mptr = match + strlen(match) - 1;
BOOL found = FALSE;
static const WCHAR S_AllW[] = {'*','.','*','\0'};
static const WCHAR S_DotW[] = {'.','\0'};
- static const WCHAR S_DotDotW[] = {'.','\0'};
+ static const WCHAR S_DotDotW[] = {'.','.','\0'};
pos = strlenW(buffer);
if (buffer[pos - 1] != '\\') buffer[pos++] = '\\';
strcpyW(buffer + pos, fd.cFileName);
if (recurse && (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
found = do_searchW(file, buffer, TRUE, cb, user);
- else if (SymMatchFileNameW(buffer, (WCHAR*)file, NULL, NULL))
+ else if (SymMatchFileNameW(buffer, file, NULL, NULL))
{
if (!cb || cb(buffer, user)) found = TRUE;
}
struct sffip
{
- enum module_type kind;
- /* pe: id -> DWORD:timestamp
- * two -> size of image (from PE header)
- * pdb: id -> PDB signature
- * I think either DWORD:timestamp or GUID:guid depending on PDB version
- * two -> PDB age ???
- * elf: id -> DWORD:CRC 32 of ELF image (Wine only)
- */
- PVOID id;
- DWORD two;
- DWORD three;
- DWORD flags;
PFINDFILEINPATHCALLBACKW cb;
void* user;
};
*/
static BOOL CALLBACK sffip_cb(PCWSTR buffer, PVOID user)
{
- struct sffip* s = (struct sffip*)user;
- DWORD size, checksum;
+ struct sffip* s = user;
+
+ if (!s->cb) return TRUE;
+ /* yes, EnumDirTree/do_search and SymFindFileInPath callbacks use the opposite
+ * convention to stop/continue enumeration. sigh.
+ */
+ return !(s->cb)(buffer, s->user);
+}
+
+/******************************************************************
+ * SymFindFileInPathW (DBGHELP.@)
+ *
+ */
+BOOL WINAPI SymFindFileInPathW(HANDLE hProcess, PCWSTR searchPath, PCWSTR full_path,
+ PVOID id, DWORD two, DWORD three, DWORD flags,
+ PWSTR buffer, PFINDFILEINPATHCALLBACKW cb,
+ PVOID user)
+{
+ struct sffip s;
+ struct process* pcs = process_find_by_handle(hProcess);
+ WCHAR tmp[MAX_PATH];
+ WCHAR* ptr;
+ const WCHAR* filename;
+
+ TRACE("(hProcess = %p, searchPath = %s, full_path = %s, id = %p, two = 0x%08x, three = 0x%08x, flags = 0x%08x, buffer = %p, cb = %p, user = %p)\n",
+ hProcess, debugstr_w(searchPath), debugstr_w(full_path),
+ id, two, three, flags, buffer, cb, user);
+
+ if (!pcs) return FALSE;
+ if (!searchPath) searchPath = pcs->search_path;
+
+ s.cb = cb;
+ s.user = user;
+
+ filename = file_nameW(full_path);
+
+ /* first check full path to file */
+ if (sffip_cb(full_path, &s))
+ {
+ strcpyW(buffer, full_path);
+ return TRUE;
+ }
+
+ while (searchPath)
+ {
+ ptr = strchrW(searchPath, ';');
+ if (ptr)
+ {
+ memcpy(tmp, searchPath, (ptr - searchPath) * sizeof(WCHAR));
+ tmp[ptr - searchPath] = 0;
+ searchPath = ptr + 1;
+ }
+ else
+ {
+ strcpyW(tmp, searchPath);
+ searchPath = NULL;
+ }
+ if (do_searchW(filename, tmp, FALSE, sffip_cb, &s))
+ {
+ strcpyW(buffer, tmp);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/******************************************************************
+ * SymFindFileInPath (DBGHELP.@)
+ *
+ */
+BOOL WINAPI SymFindFileInPath(HANDLE hProcess, PCSTR searchPath, PCSTR full_path,
+ PVOID id, DWORD two, DWORD three, DWORD flags,
+ PSTR buffer, PFINDFILEINPATHCALLBACK cb,
+ PVOID user)
+{
+ WCHAR searchPathW[MAX_PATH];
+ WCHAR full_pathW[MAX_PATH];
+ WCHAR bufferW[MAX_PATH];
+ struct enum_dir_treeWA edt;
+ BOOL ret;
- /* FIXME: should check that id/two/three match the file pointed
+ /* a PFINDFILEINPATHCALLBACK and a PENUMDIRTREE_CALLBACK have actually the
+ * same signature & semantics, hence we can reuse the EnumDirTree W->A
+ * conversion helper
+ */
+ edt.cb = cb;
+ edt.user = user;
+ if (searchPath)
+ MultiByteToWideChar(CP_ACP, 0, searchPath, -1, searchPathW, MAX_PATH);
+ MultiByteToWideChar(CP_ACP, 0, full_path, -1, full_pathW, MAX_PATH);
+ if ((ret = SymFindFileInPathW(hProcess, searchPath ? searchPathW : NULL, full_pathW,
+ id, two, three, flags,
+ bufferW, enum_dir_treeWA, &edt)))
+ WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
+ return ret;
+}
+
+struct module_find
+{
+ enum module_type kind;
+ /* pe: dw1 DWORD:timestamp
+ * dw2 size of image (from PE header)
+ * pdb: guid PDB guid (if DS PDB file)
+ * or dw1 PDB timestamp (if JG PDB file)
+ * dw2 PDB age
+ * elf: dw1 DWORD:CRC 32 of ELF image (Wine only)
+ */
+ const GUID* guid;
+ DWORD dw1;
+ DWORD dw2;
+ WCHAR filename[MAX_PATH];
+ unsigned matched;
+};
+
+/* checks that buffer (as found by matching the name) matches the info
+ * (information is based on file type)
+ * returns TRUE when file is found, FALSE to continue searching
+ * (NB this is the opposite convention of SymFindFileInPathProc)
+ */
+static BOOL CALLBACK module_find_cb(PCWSTR buffer, PVOID user)
+{
+ struct module_find* mf = user;
+ DWORD size, checksum, timestamp;
+ unsigned matched = 0;
+
+ /* the matching weights:
+ * +1 if a file with same name is found and is a decent file of expected type
+ * +1 if first parameter and second parameter match
+ */
+
+ /* FIXME: should check that id/two match the file pointed
* by buffer
*/
- switch (s->kind)
+ switch (mf->kind)
{
case DMT_PE:
{
void* mapping;
DWORD timestamp;
- timestamp = ~(DWORD_PTR)s->id;
- size = ~s->two;
+ timestamp = ~mf->dw1;
+ size = ~mf->dw2;
hFile = CreateFileW(buffer, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) return FALSE;
if ((mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL)
{
IMAGE_NT_HEADERS* nth = RtlImageNtHeader(mapping);
+
+ matched++;
timestamp = nth->FileHeader.TimeDateStamp;
size = nth->OptionalHeader.SizeOfImage;
UnmapViewOfFile(mapping);
CloseHandle(hMap);
}
CloseHandle(hFile);
- if (timestamp != (DWORD_PTR)s->id || size != s->two)
- {
- WARN("Found %s, but wrong size or timestamp\n", debugstr_w(buffer));
- return FALSE;
- }
+ if (timestamp != mf->dw1)
+ WARN("Found %s, but wrong timestamp\n", debugstr_w(buffer));
+ if (size != mf->dw2)
+ WARN("Found %s, but wrong size\n", debugstr_w(buffer));
+ if (timestamp == mf->dw1 && size == mf->dw2) matched++;
}
break;
case DMT_ELF:
if (elf_fetch_file_info(buffer, 0, &size, &checksum))
{
- if (checksum != (DWORD_PTR)s->id)
- {
- WARN("Found %s, but wrong checksums: %08x %08lx\n",
- debugstr_w(buffer), checksum, (DWORD_PTR)s->id);
- return FALSE;
- }
+ matched++;
+ if (checksum == mf->dw1) matched++;
+ else
+ WARN("Found %s, but wrong checksums: %08x %08x\n",
+ debugstr_w(buffer), checksum, mf->dw1);
+ }
+ else
+ {
+ WARN("Couldn't read %s\n", debugstr_w(buffer));
+ return FALSE;
+ }
+ break;
+ case DMT_MACHO:
+ if (macho_fetch_file_info(buffer, 0, &size, &checksum))
+ {
+ matched++;
+ if (checksum == mf->dw1) matched++;
+ else
+ WARN("Found %s, but wrong checksums: %08x %08x\n",
+ debugstr_w(buffer), checksum, mf->dw1);
}
else
{
pdb_lookup.filename = fn;
if (!pdb_fetch_file_info(&pdb_lookup)) return FALSE;
+ matched++;
switch (pdb_lookup.kind)
{
case PDB_JG:
- if (s->flags & SSRVOPT_GUIDPTR)
+ if (mf->guid)
{
WARN("Found %s, but wrong PDB version\n", debugstr_w(buffer));
- return FALSE;
- }
- if (pdb_lookup.u.jg.timestamp != (DWORD_PTR)s->id)
- {
- WARN("Found %s, but wrong signature: %08x %08lx\n",
- debugstr_w(buffer), pdb_lookup.u.jg.timestamp, (DWORD_PTR)s->id);
- return FALSE;
}
+ else if (pdb_lookup.u.jg.timestamp == mf->dw1)
+ matched++;
+ else
+ WARN("Found %s, but wrong signature: %08x %08x\n",
+ debugstr_w(buffer), pdb_lookup.u.jg.timestamp, mf->dw1);
break;
case PDB_DS:
- if (!(s->flags & SSRVOPT_GUIDPTR))
+ if (!mf->guid)
{
WARN("Found %s, but wrong PDB version\n", debugstr_w(buffer));
- return FALSE;
}
- if (memcmp(&pdb_lookup.u.ds.guid, (GUID*)s->id, sizeof(GUID)))
- {
+ else if (!memcmp(&pdb_lookup.u.ds.guid, mf->guid, sizeof(GUID)))
+ matched++;
+ else
WARN("Found %s, but wrong GUID: %s %s\n",
debugstr_w(buffer), debugstr_guid(&pdb_lookup.u.ds.guid),
- debugstr_guid((GUID*)s->id));
- return FALSE;
- }
+ debugstr_guid(mf->guid));
break;
}
- if (pdb_lookup.age != s->two)
+ if (pdb_lookup.age != mf->dw2)
{
+ matched--;
WARN("Found %s, but wrong age: %08x %08x\n",
- debugstr_w(buffer), pdb_lookup.age, s->two);
- return FALSE;
+ debugstr_w(buffer), pdb_lookup.age, mf->dw2);
}
}
break;
+ case DMT_DBG:
+ {
+ HANDLE hFile, hMap;
+ void* mapping;
+
+ timestamp = ~mf->dw1;
+ hFile = CreateFileW(buffer, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hFile == INVALID_HANDLE_VALUE) return FALSE;
+ if ((hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != NULL)
+ {
+ if ((mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL)
+ {
+ const IMAGE_SEPARATE_DEBUG_HEADER* hdr;
+ hdr = mapping;
+
+ if (hdr->Signature == IMAGE_SEPARATE_DEBUG_SIGNATURE)
+ {
+ matched++;
+ timestamp = hdr->TimeDateStamp;
+ }
+ UnmapViewOfFile(mapping);
+ }
+ CloseHandle(hMap);
+ }
+ CloseHandle(hFile);
+ if (timestamp == mf->dw1) matched++;
+ else WARN("Found %s, but wrong timestamp\n", debugstr_w(buffer));
+ }
+ break;
default:
FIXME("What the heck??\n");
return FALSE;
}
+ if (matched > mf->matched)
+ {
+ strcpyW(mf->filename, buffer);
+ mf->matched = matched;
+ }
/* yes, EnumDirTree/do_search and SymFindFileInPath callbacks use the opposite
* convention to stop/continue enumeration. sigh.
*/
- return !(s->cb)((WCHAR*)buffer, s->user);
+ return mf->matched == 2;
}
-/******************************************************************
- * SymFindFileInPathW (DBGHELP.@)
- *
- */
-BOOL WINAPI SymFindFileInPathW(HANDLE hProcess, PCWSTR searchPath, PCWSTR full_path,
- PVOID id, DWORD two, DWORD three, DWORD flags,
- PWSTR buffer, PFINDFILEINPATHCALLBACKW cb,
- PVOID user)
+BOOL path_find_symbol_file(const struct process* pcs, PCSTR full_path,
+ const GUID* guid, DWORD dw1, DWORD dw2, PSTR buffer,
+ BOOL* is_unmatched)
{
- struct sffip s;
- struct process* pcs = process_find_by_handle(hProcess);
+ struct module_find mf;
+ WCHAR full_pathW[MAX_PATH];
WCHAR tmp[MAX_PATH];
WCHAR* ptr;
const WCHAR* filename;
+ WCHAR* searchPath = pcs->search_path;
- TRACE("(%p %s %s %p %08x %08x %08x %p %p %p)\n",
- hProcess, debugstr_w(searchPath), debugstr_w(full_path),
- id, two, three, flags, buffer, cb, user);
+ TRACE("(pcs = %p, full_path = %s, guid = %s, dw1 = 0x%08x, dw2 = 0x%08x, buffer = %p)\n",
+ pcs, debugstr_a(full_path), debugstr_guid(guid), dw1, dw2, buffer);
- if (!pcs) return FALSE;
- if (!searchPath) searchPath = pcs->search_path;
+ mf.guid = guid;
+ mf.dw1 = dw1;
+ mf.dw2 = dw2;
+ mf.matched = 0;
- s.id = id;
- s.two = two;
- s.three = three;
- s.flags = flags;
- s.cb = cb;
- s.user = user;
-
- filename = file_nameW(full_path);
- s.kind = module_get_type_by_name(filename);
+ MultiByteToWideChar(CP_ACP, 0, full_path, -1, full_pathW, MAX_PATH);
+ filename = file_nameW(full_pathW);
+ mf.kind = module_get_type_by_name(filename);
+ *is_unmatched = FALSE;
/* first check full path to file */
- if (sffip_cb(full_path, &s))
+ if (module_find_cb(full_pathW, &mf))
{
- strcpyW(buffer, full_path);
+ WideCharToMultiByte(CP_ACP, 0, full_pathW, -1, buffer, MAX_PATH, NULL, NULL);
return TRUE;
}
if (ptr)
{
memcpy(tmp, searchPath, (ptr - searchPath) * sizeof(WCHAR));
- tmp[ptr - searchPath] = 0;
+ tmp[ptr - searchPath] = '\0';
searchPath = ptr + 1;
}
else
strcpyW(tmp, searchPath);
searchPath = NULL;
}
- if (do_searchW(filename, tmp, FALSE, sffip_cb, &s))
+ if (do_searchW(filename, tmp, FALSE, module_find_cb, &mf))
{
- strcpyW(buffer, tmp);
+ /* return first fully matched file */
+ WideCharToMultiByte(CP_ACP, 0, tmp, -1, buffer, MAX_PATH, NULL, NULL);
return TRUE;
}
}
+ /* if no fully matching file is found, return the best matching file if any */
+ if ((dbghelp_options & SYMOPT_LOAD_ANYTHING) && mf.matched)
+ {
+ WideCharToMultiByte(CP_ACP, 0, mf.filename, -1, buffer, MAX_PATH, NULL, NULL);
+ *is_unmatched = TRUE;
+ return TRUE;
+ }
return FALSE;
}
-
-/******************************************************************
- * SymFindFileInPath (DBGHELP.@)
- *
- */
-BOOL WINAPI SymFindFileInPath(HANDLE hProcess, PCSTR searchPath, PCSTR full_path,
- PVOID id, DWORD two, DWORD three, DWORD flags,
- PSTR buffer, PFINDFILEINPATHCALLBACK cb,
- PVOID user)
-{
- WCHAR searchPathW[MAX_PATH];
- WCHAR full_pathW[MAX_PATH];
- WCHAR bufferW[MAX_PATH];
- struct enum_dir_treeWA edt;
- BOOL ret;
-
- /* a PFINDFILEINPATHCALLBACK and a PENUMDIRTREE_CALLBACK have actually the
- * same signature & semantics, hence we can reuse the EnumDirTree W->A
- * conversion helper
- */
- edt.cb = cb;
- edt.user = user;
- if (searchPath)
- MultiByteToWideChar(CP_ACP, 0, searchPath, -1, searchPathW, MAX_PATH);
- MultiByteToWideChar(CP_ACP, 0, full_path, -1, full_pathW, MAX_PATH);
- if ((ret = SymFindFileInPathW(hProcess, searchPath ? searchPathW : NULL, full_pathW,
- id, two, three, flags,
- bufferW, enum_dir_treeWA, &edt)))
- WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
- return ret;
-}