RetrieveSymbols.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. // Symbol downloading demonstration code.
  5. // For more information see ReadMe.txt and this blog post:
  6. // https://randomascii.wordpress.com/2013/03/09/symbols-the-microsoft-way/
  7. #include <stdio.h>
  8. #include <Windows.h>
  9. #include <DbgHelp.h>
  10. #include <string>
  11. // Link with the dbghelp import library
  12. #pragma comment(lib, "dbghelp.lib")
  13. // Uncomment this line to test with known-good parameters.
  14. //#define TESTING
  15. int main(int argc, char* argv[])
  16. {
  17. // Tell dbghelp to print diagnostics to the debugger output.
  18. SymSetOptions(SYMOPT_DEBUG);
  19. // Initialize dbghelp
  20. const HANDLE fakeProcess = (HANDLE)1;
  21. BOOL result = SymInitialize(fakeProcess, NULL, FALSE);
  22. #ifdef TESTING
  23. // Set a search path and cache directory. If this isn't set
  24. // then _NT_SYMBOL_PATH will be used instead.
  25. // Force setting it here to make sure that the test succeeds.
  26. SymSetSearchPath(fakeProcess,
  27. "SRV*c:\\symbolstest*http://msdl.microsoft.com/download/symbols");
  28. // Valid PDB data to test the code.
  29. std::string gTextArg = "072FF0EB54D24DFAAE9D13885486EE09";
  30. const char* ageText = "2";
  31. const char* fileName = "kernel32.pdb";
  32. // Valid PE data to test the code
  33. fileName = "crypt32.dll";
  34. const char* dateStampText = "4802A0D7";
  35. const char* sizeText = "95000";
  36. //fileName = "chrome_child.dll";
  37. //const char* dateStampText = "5420D824";
  38. //const char* sizeText = "20a6000";
  39. #else
  40. if (argc < 4)
  41. {
  42. printf("Error: insufficient arguments.\n");
  43. printf("Usage: %s guid age pdbname\n", argv[0]);
  44. printf("Usage: %s dateStamp size pename\n", argv[0]);
  45. printf("Example: %s 6720c31f4ac24f3ab0243e0641a4412f 1 "
  46. "chrome_child.dll.pdb\n", argv[0]);
  47. printf("Example: %s 4802A0D7 95000 crypt32.dll\n", argv[0]);
  48. return 0;
  49. }
  50. std::string gTextArg = argv[1];
  51. const char* dateStampText = argv[1];
  52. const char* ageText = argv[2];
  53. const char* sizeText = argv[2];
  54. const char* fileName = argv[3];
  55. #endif
  56. // Parse the GUID and age from the text
  57. GUID g = {};
  58. DWORD age = 0;
  59. DWORD dateStamp = 0;
  60. DWORD size = 0;
  61. // Settings for SymFindFileInPath
  62. void* id = nullptr;
  63. DWORD flags = 0;
  64. DWORD two = 0;
  65. const char* ext = strrchr(fileName, '.');
  66. if (!ext)
  67. {
  68. printf("No extension found on %s. Fatal error.\n", fileName);
  69. return 0;
  70. }
  71. if (_stricmp(ext, ".pdb") == 0)
  72. {
  73. std::string gText;
  74. // Scan the GUID argument and remove all non-hex characters. This allows
  75. // passing GUIDs with '-', '{', and '}' characters.
  76. for (auto c : gTextArg)
  77. {
  78. if (isxdigit(c))
  79. {
  80. gText.push_back(c);
  81. }
  82. }
  83. printf("Parsing symbol data for a PDB file.\n");
  84. if (gText.size() != 32)
  85. {
  86. printf("Error: GUIDs must be exactly 32 characters"
  87. " (%s was stripped to %s).\n", gTextArg.c_str(), gText.c_str());
  88. return 10;
  89. }
  90. int count = sscanf_s(gText.substr(0, 8).c_str(), "%x", &g.Data1);
  91. DWORD temp;
  92. count += sscanf_s(gText.substr(8, 4).c_str(), "%x", &temp);
  93. g.Data2 = (unsigned short)temp;
  94. count += sscanf_s(gText.substr(12, 4).c_str(), "%x", &temp);
  95. g.Data3 = (unsigned short)temp;
  96. for (auto i = 0; i < ARRAYSIZE(g.Data4); ++i)
  97. {
  98. count += sscanf_s(gText.substr(16 + i * 2, 2).c_str(), "%x", &temp);
  99. g.Data4[i] = (unsigned char)temp;
  100. }
  101. count += sscanf_s(ageText, "%x", &age);
  102. if (count != 12)
  103. {
  104. printf("Error: couldn't parse the GUID/age string. Sorry.\n");
  105. return 10;
  106. }
  107. flags = SSRVOPT_GUIDPTR;
  108. id = &g;
  109. two = age;
  110. printf("Looking for %s %s %s.\n", gText.c_str(), ageText, fileName);
  111. }
  112. else
  113. {
  114. printf("Parsing symbol data for a PE (.dll or .exe) file.\n");
  115. if (strlen(dateStampText) != 8)
  116. printf("Warning!!! The datestamp (%s) is not eight characters long. "
  117. "This is usually wrong.\n", dateStampText);
  118. int count = sscanf_s(dateStampText, "%x", &dateStamp);
  119. count += sscanf_s(sizeText, "%x", &size);
  120. flags = SSRVOPT_DWORDPTR;
  121. id = &dateStamp;
  122. two = size;
  123. printf("Looking for %s %x %x.\n", fileName, dateStamp, two);
  124. }
  125. char filePath[MAX_PATH] = {};
  126. DWORD three = 0;
  127. if (SymFindFileInPath(fakeProcess, NULL, fileName, id, two, three,
  128. flags, filePath, NULL, NULL))
  129. {
  130. printf("Found symbol file - placed it in %s.\n", filePath);
  131. }
  132. else
  133. {
  134. printf("Error: symbols not found - error %u. Are dbghelp.dll and "
  135. "symsrv.dll in the same directory as this executable?\n",
  136. GetLastError());
  137. printf("Note that symbol server lookups sometimes fail randomly. "
  138. "Try again?\n");
  139. }
  140. SymCleanup(fakeProcess);
  141. return 0;
  142. }