1 /* 2 * File path.c - managing path in debugging environments 3 * 4 * Copyright (C) 2004,2008, Eric Pouech 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include "config.h" 22 #include <stdlib.h> 23 #include <stdio.h> 24 #include <string.h> 25 26 #include "dbghelp_private.h" 27 #include "winnls.h" 28 #include "winternl.h" 29 #include "wine/debug.h" 30 31 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); 32 33 static inline BOOL is_sep(char ch) {return ch == '/' || ch == '\\';} 34 static inline BOOL is_sepW(WCHAR ch) {return ch == '/' || ch == '\\';} 35 36 static inline const char* file_name(const char* str) 37 { 38 const char* p; 39 40 for (p = str + strlen(str) - 1; p >= str && !is_sep(*p); p--); 41 return p + 1; 42 } 43 44 static inline const WCHAR* file_nameW(const WCHAR* str) 45 { 46 const WCHAR* p; 47 48 for (p = str + strlenW(str) - 1; p >= str && !is_sepW(*p); p--); 49 return p + 1; 50 } 51 52 static inline void file_pathW(const WCHAR* srcFileNameW, 53 WCHAR* dstFilePathW) 54 { 55 int len; 56 57 for (len = strlenW(srcFileNameW) - 1; (len > 0) && (!is_sepW(srcFileNameW[len])); len--); 58 59 strncpyW(dstFilePathW, srcFileNameW, len); 60 dstFilePathW[len] = L'\0'; 61 } 62 63 /****************************************************************** 64 * FindDebugInfoFile (DBGHELP.@) 65 * 66 */ 67 HANDLE WINAPI FindDebugInfoFile(PCSTR FileName, PCSTR SymbolPath, PSTR DebugFilePath) 68 { 69 HANDLE h; 70 71 h = CreateFileA(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, 72 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 73 if (h == INVALID_HANDLE_VALUE) 74 { 75 if (!SearchPathA(SymbolPath, file_name(FileName), NULL, MAX_PATH, DebugFilePath, NULL)) 76 return NULL; 77 h = CreateFileA(DebugFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, 78 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 79 } 80 return (h == INVALID_HANDLE_VALUE) ? NULL : h; 81 } 82 83 /****************************************************************** 84 * FindDebugInfoFileEx (DBGHELP.@) 85 * 86 */ 87 HANDLE WINAPI FindDebugInfoFileEx(PCSTR FileName, PCSTR SymbolPath, 88 PSTR DebugFilePath, 89 PFIND_DEBUG_FILE_CALLBACK Callback, 90 PVOID CallerData) 91 { 92 FIXME("(%s %s %s %p %p): stub\n", debugstr_a(FileName), debugstr_a(SymbolPath), 93 debugstr_a(DebugFilePath), Callback, CallerData); 94 return NULL; 95 } 96 97 /****************************************************************** 98 * FindExecutableImageExW (DBGHELP.@) 99 * 100 */ 101 HANDLE WINAPI FindExecutableImageExW(PCWSTR FileName, PCWSTR SymbolPath, PWSTR ImageFilePath, 102 PFIND_EXE_FILE_CALLBACKW Callback, PVOID user) 103 { 104 HANDLE h; 105 106 if (Callback) FIXME("Unsupported callback yet\n"); 107 if (!SearchPathW(SymbolPath, FileName, NULL, MAX_PATH, ImageFilePath, NULL)) 108 return NULL; 109 h = CreateFileW(ImageFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, 110 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 111 return (h == INVALID_HANDLE_VALUE) ? NULL : h; 112 } 113 114 /****************************************************************** 115 * FindExecutableImageEx (DBGHELP.@) 116 * 117 */ 118 HANDLE WINAPI FindExecutableImageEx(PCSTR FileName, PCSTR SymbolPath, PSTR ImageFilePath, 119 PFIND_EXE_FILE_CALLBACK Callback, PVOID user) 120 { 121 HANDLE h; 122 123 if (Callback) FIXME("Unsupported callback yet\n"); 124 if (!SearchPathA(SymbolPath, FileName, NULL, MAX_PATH, ImageFilePath, NULL)) 125 return NULL; 126 h = CreateFileA(ImageFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, 127 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 128 return (h == INVALID_HANDLE_VALUE) ? NULL : h; 129 } 130 131 /****************************************************************** 132 * FindExecutableImage (DBGHELP.@) 133 * 134 */ 135 HANDLE WINAPI FindExecutableImage(PCSTR FileName, PCSTR SymbolPath, PSTR ImageFilePath) 136 { 137 return FindExecutableImageEx(FileName, SymbolPath, ImageFilePath, NULL, NULL); 138 } 139 140 /*********************************************************************** 141 * MakeSureDirectoryPathExists (DBGHELP.@) 142 */ 143 BOOL WINAPI MakeSureDirectoryPathExists(PCSTR DirPath) 144 { 145 char path[MAX_PATH]; 146 const char *p = DirPath; 147 int n; 148 149 if (p[0] && p[1] == ':') p += 2; 150 while (*p == '\\') p++; /* skip drive root */ 151 while ((p = strchr(p, '\\')) != NULL) 152 { 153 n = p - DirPath + 1; 154 memcpy(path, DirPath, n); 155 path[n] = '\0'; 156 if( !CreateDirectoryA(path, NULL) && 157 (GetLastError() != ERROR_ALREADY_EXISTS)) 158 return FALSE; 159 p++; 160 } 161 if (GetLastError() == ERROR_ALREADY_EXISTS) 162 SetLastError(ERROR_SUCCESS); 163 164 return TRUE; 165 } 166 167 /****************************************************************** 168 * SymMatchFileNameW (DBGHELP.@) 169 * 170 */ 171 BOOL WINAPI SymMatchFileNameW(PCWSTR file, PCWSTR match, 172 PWSTR* filestop, PWSTR* matchstop) 173 { 174 PCWSTR fptr; 175 PCWSTR mptr; 176 177 TRACE("(%s %s %p %p)\n", 178 debugstr_w(file), debugstr_w(match), filestop, matchstop); 179 180 fptr = file + strlenW(file) - 1; 181 mptr = match + strlenW(match) - 1; 182 183 while (fptr >= file && mptr >= match) 184 { 185 if (toupperW(*fptr) != toupperW(*mptr) && !(is_sepW(*fptr) && is_sepW(*mptr))) 186 break; 187 fptr--; mptr--; 188 } 189 if (filestop) *filestop = (PWSTR)fptr; 190 if (matchstop) *matchstop = (PWSTR)mptr; 191 192 return mptr == match - 1; 193 } 194 195 /****************************************************************** 196 * SymMatchFileName (DBGHELP.@) 197 * 198 */ 199 BOOL WINAPI SymMatchFileName(PCSTR file, PCSTR match, 200 PSTR* filestop, PSTR* matchstop) 201 { 202 PCSTR fptr; 203 PCSTR mptr; 204 205 TRACE("(%s %s %p %p)\n", debugstr_a(file), debugstr_a(match), filestop, matchstop); 206 207 fptr = file + strlen(file) - 1; 208 mptr = match + strlen(match) - 1; 209 210 while (fptr >= file && mptr >= match) 211 { 212 if (toupper(*fptr) != toupper(*mptr) && !(is_sep(*fptr) && is_sep(*mptr))) 213 break; 214 fptr--; mptr--; 215 } 216 if (filestop) *filestop = (PSTR)fptr; 217 if (matchstop) *matchstop = (PSTR)mptr; 218 219 return mptr == match - 1; 220 } 221 222 static BOOL do_searchW(PCWSTR file, PWSTR buffer, BOOL recurse, 223 PENUMDIRTREE_CALLBACKW cb, PVOID user) 224 { 225 HANDLE h; 226 WIN32_FIND_DATAW fd; 227 unsigned pos; 228 BOOL found = FALSE; 229 static const WCHAR S_AllW[] = {'*','.','*','\0'}; 230 static const WCHAR S_DotW[] = {'.','\0'}; 231 static const WCHAR S_DotDotW[] = {'.','.','\0'}; 232 233 pos = strlenW(buffer); 234 if (buffer[pos - 1] != '\\') buffer[pos++] = '\\'; 235 strcpyW(buffer + pos, S_AllW); 236 if ((h = FindFirstFileW(buffer, &fd)) == INVALID_HANDLE_VALUE) 237 return FALSE; 238 /* doc doesn't specify how the tree is enumerated... 239 * doing a depth first based on, but may be wrong 240 */ 241 do 242 { 243 if (!strcmpW(fd.cFileName, S_DotW) || !strcmpW(fd.cFileName, S_DotDotW)) continue; 244 245 strcpyW(buffer + pos, fd.cFileName); 246 if (recurse && (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) 247 found = do_searchW(file, buffer, TRUE, cb, user); 248 else if (SymMatchFileNameW(buffer, file, NULL, NULL)) 249 { 250 if (!cb || cb(buffer, user)) found = TRUE; 251 } 252 } while (!found && FindNextFileW(h, &fd)); 253 if (!found) buffer[--pos] = '\0'; 254 FindClose(h); 255 256 return found; 257 } 258 259 /*********************************************************************** 260 * SearchTreeForFileW (DBGHELP.@) 261 */ 262 BOOL WINAPI SearchTreeForFileW(PCWSTR root, PCWSTR file, PWSTR buffer) 263 { 264 TRACE("(%s, %s, %p)\n", 265 debugstr_w(root), debugstr_w(file), buffer); 266 strcpyW(buffer, root); 267 return do_searchW(file, buffer, TRUE, NULL, NULL); 268 } 269 270 /*********************************************************************** 271 * SearchTreeForFile (DBGHELP.@) 272 */ 273 BOOL WINAPI SearchTreeForFile(PCSTR root, PCSTR file, PSTR buffer) 274 { 275 WCHAR rootW[MAX_PATH]; 276 WCHAR fileW[MAX_PATH]; 277 WCHAR bufferW[MAX_PATH]; 278 BOOL ret; 279 280 MultiByteToWideChar(CP_ACP, 0, root, -1, rootW, MAX_PATH); 281 MultiByteToWideChar(CP_ACP, 0, file, -1, fileW, MAX_PATH); 282 ret = SearchTreeForFileW(rootW, fileW, bufferW); 283 if (ret) 284 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL); 285 return ret; 286 } 287 288 /****************************************************************** 289 * EnumDirTreeW (DBGHELP.@) 290 * 291 * 292 */ 293 BOOL WINAPI EnumDirTreeW(HANDLE hProcess, PCWSTR root, PCWSTR file, 294 PWSTR buffer, PENUMDIRTREE_CALLBACKW cb, PVOID user) 295 { 296 TRACE("(%p %s %s %p %p %p)\n", 297 hProcess, debugstr_w(root), debugstr_w(file), buffer, cb, user); 298 299 strcpyW(buffer, root); 300 return do_searchW(file, buffer, TRUE, cb, user); 301 } 302 303 /****************************************************************** 304 * EnumDirTree (DBGHELP.@) 305 * 306 * 307 */ 308 struct enum_dir_treeWA 309 { 310 PENUMDIRTREE_CALLBACK cb; 311 void* user; 312 char name[MAX_PATH]; 313 }; 314 315 static BOOL CALLBACK enum_dir_treeWA(PCWSTR name, PVOID user) 316 { 317 struct enum_dir_treeWA* edt = user; 318 319 WideCharToMultiByte(CP_ACP, 0, name, -1, edt->name, MAX_PATH, NULL, NULL); 320 return edt->cb(edt->name, edt->user); 321 } 322 323 BOOL WINAPI EnumDirTree(HANDLE hProcess, PCSTR root, PCSTR file, 324 PSTR buffer, PENUMDIRTREE_CALLBACK cb, PVOID user) 325 { 326 WCHAR rootW[MAX_PATH]; 327 WCHAR fileW[MAX_PATH]; 328 WCHAR bufferW[MAX_PATH]; 329 struct enum_dir_treeWA edt; 330 BOOL ret; 331 332 edt.cb = cb; 333 edt.user = user; 334 MultiByteToWideChar(CP_ACP, 0, root, -1, rootW, MAX_PATH); 335 MultiByteToWideChar(CP_ACP, 0, file, -1, fileW, MAX_PATH); 336 if ((ret = EnumDirTreeW(hProcess, rootW, fileW, bufferW, enum_dir_treeWA, &edt))) 337 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL); 338 return ret; 339 } 340 341 struct sffip 342 { 343 PFINDFILEINPATHCALLBACKW cb; 344 void* user; 345 }; 346 347 /* checks that buffer (as found by matching the name) matches the info 348 * (information is based on file type) 349 * returns TRUE when file is found, FALSE to continue searching 350 * (NB this is the opposite convention of SymFindFileInPathProc) 351 */ 352 static BOOL CALLBACK sffip_cb(PCWSTR buffer, PVOID user) 353 { 354 struct sffip* s = user; 355 356 if (!s->cb) return TRUE; 357 /* yes, EnumDirTree/do_search and SymFindFileInPath callbacks use the opposite 358 * convention to stop/continue enumeration. sigh. 359 */ 360 return !(s->cb)(buffer, s->user); 361 } 362 363 /****************************************************************** 364 * SymFindFileInPathW (DBGHELP.@) 365 * 366 */ 367 BOOL WINAPI SymFindFileInPathW(HANDLE hProcess, PCWSTR searchPath, PCWSTR full_path, 368 PVOID id, DWORD two, DWORD three, DWORD flags, 369 PWSTR buffer, PFINDFILEINPATHCALLBACKW cb, 370 PVOID user) 371 { 372 struct sffip s; 373 struct process* pcs = process_find_by_handle(hProcess); 374 WCHAR tmp[MAX_PATH]; 375 WCHAR* ptr; 376 const WCHAR* filename; 377 378 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", 379 hProcess, debugstr_w(searchPath), debugstr_w(full_path), 380 id, two, three, flags, buffer, cb, user); 381 382 if (!pcs) return FALSE; 383 if (!searchPath) searchPath = pcs->search_path; 384 385 s.cb = cb; 386 s.user = user; 387 388 filename = file_nameW(full_path); 389 390 /* first check full path to file */ 391 if (sffip_cb(full_path, &s)) 392 { 393 strcpyW(buffer, full_path); 394 return TRUE; 395 } 396 397 while (searchPath) 398 { 399 ptr = strchrW(searchPath, ';'); 400 if (ptr) 401 { 402 memcpy(tmp, searchPath, (ptr - searchPath) * sizeof(WCHAR)); 403 tmp[ptr - searchPath] = 0; 404 searchPath = ptr + 1; 405 } 406 else 407 { 408 strcpyW(tmp, searchPath); 409 searchPath = NULL; 410 } 411 if (do_searchW(filename, tmp, FALSE, sffip_cb, &s)) 412 { 413 strcpyW(buffer, tmp); 414 return TRUE; 415 } 416 } 417 return FALSE; 418 } 419 420 /****************************************************************** 421 * SymFindFileInPath (DBGHELP.@) 422 * 423 */ 424 BOOL WINAPI SymFindFileInPath(HANDLE hProcess, PCSTR searchPath, PCSTR full_path, 425 PVOID id, DWORD two, DWORD three, DWORD flags, 426 PSTR buffer, PFINDFILEINPATHCALLBACK cb, 427 PVOID user) 428 { 429 WCHAR searchPathW[MAX_PATH]; 430 WCHAR full_pathW[MAX_PATH]; 431 WCHAR bufferW[MAX_PATH]; 432 struct enum_dir_treeWA edt; 433 BOOL ret; 434 435 /* a PFINDFILEINPATHCALLBACK and a PENUMDIRTREE_CALLBACK have actually the 436 * same signature & semantics, hence we can reuse the EnumDirTree W->A 437 * conversion helper 438 */ 439 edt.cb = cb; 440 edt.user = user; 441 if (searchPath) 442 MultiByteToWideChar(CP_ACP, 0, searchPath, -1, searchPathW, MAX_PATH); 443 MultiByteToWideChar(CP_ACP, 0, full_path, -1, full_pathW, MAX_PATH); 444 if ((ret = SymFindFileInPathW(hProcess, searchPath ? searchPathW : NULL, full_pathW, 445 id, two, three, flags, 446 bufferW, enum_dir_treeWA, &edt))) 447 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL); 448 return ret; 449 } 450 451 struct module_find 452 { 453 enum module_type kind; 454 /* pe: dw1 DWORD:timestamp 455 * dw2 size of image (from PE header) 456 * pdb: guid PDB guid (if DS PDB file) 457 * or dw1 PDB timestamp (if JG PDB file) 458 * dw2 PDB age 459 * elf: dw1 DWORD:CRC 32 of ELF image (Wine only) 460 */ 461 const GUID* guid; 462 DWORD dw1; 463 DWORD dw2; 464 WCHAR filename[MAX_PATH]; 465 unsigned matched; 466 }; 467 468 /* checks that buffer (as found by matching the name) matches the info 469 * (information is based on file type) 470 * returns TRUE when file is found, FALSE to continue searching 471 * (NB this is the opposite convention of SymFindFileInPathProc) 472 */ 473 static BOOL CALLBACK module_find_cb(PCWSTR buffer, PVOID user) 474 { 475 struct module_find* mf = user; 476 DWORD size, checksum, timestamp; 477 unsigned matched = 0; 478 479 /* the matching weights: 480 * +1 if a file with same name is found and is a decent file of expected type 481 * +1 if first parameter and second parameter match 482 */ 483 484 /* FIXME: should check that id/two match the file pointed 485 * by buffer 486 */ 487 switch (mf->kind) 488 { 489 case DMT_PE: 490 { 491 HANDLE hFile, hMap; 492 void* mapping; 493 494 timestamp = ~mf->dw1; 495 size = ~mf->dw2; 496 hFile = CreateFileW(buffer, GENERIC_READ, FILE_SHARE_READ, NULL, 497 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 498 if (hFile == INVALID_HANDLE_VALUE) return FALSE; 499 if ((hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != NULL) 500 { 501 if ((mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL) 502 { 503 IMAGE_NT_HEADERS* nth = RtlImageNtHeader(mapping); 504 if (!nth) 505 { 506 UnmapViewOfFile(mapping); 507 CloseHandle(hMap); 508 CloseHandle(hFile); 509 return FALSE; 510 } 511 matched++; 512 timestamp = nth->FileHeader.TimeDateStamp; 513 size = nth->OptionalHeader.SizeOfImage; 514 UnmapViewOfFile(mapping); 515 } 516 CloseHandle(hMap); 517 } 518 CloseHandle(hFile); 519 if (timestamp != mf->dw1) 520 WARN("Found %s, but wrong timestamp\n", debugstr_w(buffer)); 521 if (size != mf->dw2) 522 WARN("Found %s, but wrong size\n", debugstr_w(buffer)); 523 if (timestamp == mf->dw1 && size == mf->dw2) matched++; 524 } 525 break; 526 case DMT_ELF: 527 if (elf_fetch_file_info(buffer, 0, &size, &checksum)) 528 { 529 matched++; 530 if (checksum == mf->dw1) matched++; 531 else 532 WARN("Found %s, but wrong checksums: %08x %08x\n", 533 debugstr_w(buffer), checksum, mf->dw1); 534 } 535 else 536 { 537 WARN("Couldn't read %s\n", debugstr_w(buffer)); 538 return FALSE; 539 } 540 break; 541 case DMT_MACHO: 542 if (macho_fetch_file_info(NULL, buffer, 0, 0, &size, &checksum)) 543 { 544 matched++; 545 if (checksum == mf->dw1) matched++; 546 else 547 WARN("Found %s, but wrong checksums: %08x %08x\n", 548 debugstr_w(buffer), checksum, mf->dw1); 549 } 550 else 551 { 552 WARN("Couldn't read %s\n", debugstr_w(buffer)); 553 return FALSE; 554 } 555 break; 556 case DMT_PDB: 557 { 558 struct pdb_lookup pdb_lookup; 559 char fn[MAX_PATH]; 560 561 WideCharToMultiByte(CP_ACP, 0, buffer, -1, fn, MAX_PATH, NULL, NULL); 562 pdb_lookup.filename = fn; 563 564 if (mf->guid) 565 { 566 pdb_lookup.kind = PDB_DS; 567 pdb_lookup.timestamp = 0; 568 pdb_lookup.guid = *mf->guid; 569 } 570 else 571 { 572 pdb_lookup.kind = PDB_JG; 573 pdb_lookup.timestamp = mf->dw1; 574 /* pdb_loopkup.guid = */ 575 } 576 pdb_lookup.age = mf->dw2; 577 578 if (!pdb_fetch_file_info(&pdb_lookup, &matched)) return FALSE; 579 } 580 break; 581 case DMT_DBG: 582 { 583 HANDLE hFile, hMap; 584 void* mapping; 585 586 timestamp = ~mf->dw1; 587 hFile = CreateFileW(buffer, GENERIC_READ, FILE_SHARE_READ, NULL, 588 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 589 if (hFile == INVALID_HANDLE_VALUE) return FALSE; 590 if ((hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != NULL) 591 { 592 if ((mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL) 593 { 594 const IMAGE_SEPARATE_DEBUG_HEADER* hdr; 595 hdr = mapping; 596 597 if (hdr->Signature == IMAGE_SEPARATE_DEBUG_SIGNATURE) 598 { 599 matched++; 600 timestamp = hdr->TimeDateStamp; 601 } 602 UnmapViewOfFile(mapping); 603 } 604 CloseHandle(hMap); 605 } 606 CloseHandle(hFile); 607 if (timestamp == mf->dw1) matched++; 608 else WARN("Found %s, but wrong timestamp\n", debugstr_w(buffer)); 609 } 610 break; 611 default: 612 FIXME("What the heck??\n"); 613 return FALSE; 614 } 615 if (matched > mf->matched) 616 { 617 strcpyW(mf->filename, buffer); 618 mf->matched = matched; 619 } 620 /* yes, EnumDirTree/do_search and SymFindFileInPath callbacks use the opposite 621 * convention to stop/continue enumeration. sigh. 622 */ 623 return mf->matched == 2; 624 } 625 626 BOOL path_find_symbol_file(const struct process* pcs, const struct module* module, 627 PCSTR full_path, const GUID* guid, DWORD dw1, DWORD dw2, 628 PSTR buffer, BOOL* is_unmatched) 629 { 630 struct module_find mf; 631 WCHAR full_pathW[MAX_PATH]; 632 WCHAR tmp[MAX_PATH]; 633 WCHAR* ptr; 634 const WCHAR* filename; 635 WCHAR* searchPath = pcs->search_path; 636 637 TRACE("(pcs = %p, full_path = %s, guid = %s, dw1 = 0x%08x, dw2 = 0x%08x, buffer = %p)\n", 638 pcs, debugstr_a(full_path), debugstr_guid(guid), dw1, dw2, buffer); 639 640 mf.guid = guid; 641 mf.dw1 = dw1; 642 mf.dw2 = dw2; 643 mf.matched = 0; 644 645 MultiByteToWideChar(CP_ACP, 0, full_path, -1, full_pathW, MAX_PATH); 646 filename = file_nameW(full_pathW); 647 mf.kind = module_get_type_by_name(filename); 648 *is_unmatched = FALSE; 649 650 /* first check full path to file */ 651 if (module_find_cb(full_pathW, &mf)) 652 { 653 WideCharToMultiByte(CP_ACP, 0, full_pathW, -1, buffer, MAX_PATH, NULL, NULL); 654 return TRUE; 655 } 656 657 /* FIXME: Use Environment-Variables (see MS docs) 658 _NT_SYMBOL_PATH and _NT_ALT_SYMBOL_PATH 659 FIXME: Implement "Standard Path Elements" (Path) ... (see MS docs) 660 do a search for (every?) path-element like this ... 661 <path> 662 <path>\dll 663 <path>\symbols\dll 664 (dll may be exe, or sys depending on the file extension) */ 665 666 /* 2. check module-path */ 667 file_pathW(module->module.LoadedImageName, tmp); 668 if (do_searchW(filename, tmp, FALSE, module_find_cb, &mf)) 669 { 670 WideCharToMultiByte(CP_ACP, 0, tmp, -1, buffer, MAX_PATH, NULL, NULL); 671 return TRUE; 672 } 673 674 /* 3. check search-path */ 675 while (searchPath) 676 { 677 ptr = strchrW(searchPath, ';'); 678 if (ptr) 679 { 680 memcpy(tmp, searchPath, (ptr - searchPath) * sizeof(WCHAR)); 681 tmp[ptr - searchPath] = '\0'; 682 searchPath = ptr + 1; 683 } 684 else 685 { 686 strcpyW(tmp, searchPath); 687 searchPath = NULL; 688 } 689 if (do_searchW(filename, tmp, FALSE, module_find_cb, &mf)) 690 { 691 /* return first fully matched file */ 692 WideCharToMultiByte(CP_ACP, 0, tmp, -1, buffer, MAX_PATH, NULL, NULL); 693 return TRUE; 694 } 695 } 696 /* if no fully matching file is found, return the best matching file if any */ 697 if ((dbghelp_options & SYMOPT_LOAD_ANYTHING) && mf.matched) 698 { 699 WideCharToMultiByte(CP_ACP, 0, mf.filename, -1, buffer, MAX_PATH, NULL, NULL); 700 *is_unmatched = TRUE; 701 return TRUE; 702 } 703 return FALSE; 704 } 705