src/hotspot/os/windows/symbolengine.cpp
changeset 47666 19219ec3f176
child 49039 0f81d08a578e
equal deleted inserted replaced
47665:74805fccc6ae 47666:19219ec3f176
       
     1 /*
       
     2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  *
       
    23  */
       
    24 
       
    25 #include "precompiled.hpp"
       
    26 #include "utilities/globalDefinitions.hpp"
       
    27 #include "symbolengine.hpp"
       
    28 #include "utilities/debug.hpp"
       
    29 #include "windbghelp.hpp"
       
    30 
       
    31 #include <windows.h>
       
    32 
       
    33 #include <imagehlp.h>
       
    34 #include <psapi.h>
       
    35 
       
    36 
       
    37 
       
    38 // This code may be invoked normally but also as part of error reporting
       
    39 // In the latter case, we may run under tight memory constraints (native oom)
       
    40 // or in a stack overflow situation or the C heap may be corrupted. We may
       
    41 // run very early before VM initialization or very late when C exit handlers
       
    42 // run. In all these cases, callstacks would still be nice, so lets be robust.
       
    43 //
       
    44 // We need a number of buffers - for the pdb search path, module handle
       
    45 // lists, for demangled symbols, etc.
       
    46 //
       
    47 // These buffers, while typically small, may need to be large for corner
       
    48 // cases (e.g. templatized C++ symbols, or many DLLs loaded). Where do we
       
    49 // allocate them?
       
    50 //
       
    51 // We may be in error handling for a stack overflow, so lets not put them on
       
    52 // the stack.
       
    53 //
       
    54 // Dynamically allocating them may fail if we are handling a native OOM. It
       
    55 // is also a bit dangerous, as the C heap may be corrupted already.
       
    56 //
       
    57 // That leaves pre-allocating them globally, which is safe and should always
       
    58 // work (if we synchronize access) but incurs an undesirable footprint for
       
    59 // non-error cases.
       
    60 //
       
    61 // We follow a two-way strategy: Allocate the buffers on the C heap in a
       
    62 // reasonable large size. Failing that, fall back to static preallocated
       
    63 // buffers. The size of the latter is large enough to handle common scenarios
       
    64 // but small enough not to drive up the footprint too much (several kb).
       
    65 //
       
    66 // We keep these buffers around once allocated, for subsequent requests. This
       
    67 // means that by running the initialization early at a safe time - before
       
    68 // any error happens - buffers can be pre-allocated. This increases the chance
       
    69 // of useful callstacks in error scenarios in exchange for a some cycles spent
       
    70 // at startup. This behavior can be controlled with -XX:+InitializeDbgHelpEarly
       
    71 // and is off by default.
       
    72 
       
    73 ///////
       
    74 
       
    75 // A simple buffer which attempts to allocate an optimal size but will
       
    76 // fall back to a static minimally sized array on allocation error.
       
    77 template <class T, int MINIMAL_CAPACITY, int OPTIMAL_CAPACITY>
       
    78 class SimpleBufferWithFallback {
       
    79   T _fallback_buffer[MINIMAL_CAPACITY];
       
    80   T* _p;
       
    81   int _capacity;
       
    82 
       
    83   // A sentinel at the end of the buffer to catch overflows.
       
    84   void imprint_sentinel() {
       
    85     assert(_p && _capacity > 0, "Buffer must be allocated");
       
    86     _p[_capacity - 1] = (T)'X';
       
    87     _capacity --;
       
    88   }
       
    89 
       
    90 public:
       
    91 
       
    92   SimpleBufferWithFallback<T, MINIMAL_CAPACITY, OPTIMAL_CAPACITY> ()
       
    93     : _p(NULL), _capacity(0)
       
    94   {}
       
    95 
       
    96   // Note: no destructor because these buffers should, once
       
    97   // allocated, live until process end.
       
    98   // ~SimpleBufferWithFallback()
       
    99 
       
   100   // Note: We use raw ::malloc/::free here instead of os::malloc()/os::free
       
   101   // to prevent circularities or secondary crashes during error reporting.
       
   102   virtual void initialize () {
       
   103     assert(_p == NULL && _capacity == 0, "Only call once.");
       
   104     const size_t bytes = OPTIMAL_CAPACITY * sizeof(T);
       
   105     T* q = (T*) ::malloc(bytes);
       
   106     if (q != NULL) {
       
   107       _p = q;
       
   108       _capacity = OPTIMAL_CAPACITY;
       
   109     } else {
       
   110       _p = _fallback_buffer;
       
   111       _capacity = (int)(sizeof(_fallback_buffer) / sizeof(T));
       
   112     }
       
   113     _p[0] = '\0';
       
   114     imprint_sentinel();
       
   115   }
       
   116 
       
   117   // We need a way to reset the buffer to fallback size for one special
       
   118   // case, where two buffers need to be of identical capacity.
       
   119   void reset_to_fallback_capacity() {
       
   120     if (_p != _fallback_buffer) {
       
   121       ::free(_p);
       
   122     }
       
   123     _p = _fallback_buffer;
       
   124     _capacity = (int)(sizeof(_fallback_buffer) / sizeof(T));
       
   125     _p[0] = '\0';
       
   126     imprint_sentinel();
       
   127   }
       
   128 
       
   129   T* ptr()                { return _p; }
       
   130   const T* ptr() const    { return _p; }
       
   131   int capacity() const    { return _capacity; }
       
   132 
       
   133 #ifdef ASSERT
       
   134   void check() const {
       
   135     assert(_p[_capacity] == (T)'X', "sentinel lost");
       
   136   }
       
   137 #else
       
   138   void check() const {}
       
   139 #endif
       
   140 
       
   141 };
       
   142 
       
   143 ////
       
   144 
       
   145 // ModuleHandleArray: a list holding module handles. Needs to be large enough
       
   146 // to hold one handle per loaded DLL.
       
   147 // Note: a standard OpenJDK loads normally ~30 libraries, including system
       
   148 // libraries, without third party libraries.
       
   149 
       
   150 typedef SimpleBufferWithFallback <HMODULE, 48, 512> ModuleHandleArrayBase;
       
   151 
       
   152 class ModuleHandleArray : public ModuleHandleArrayBase {
       
   153 
       
   154   int _num; // Number of handles in this array (may be < capacity).
       
   155 
       
   156 public:
       
   157 
       
   158   void initialize() {
       
   159     ModuleHandleArrayBase::initialize();
       
   160     _num = 0;
       
   161   }
       
   162 
       
   163   int num() const { return _num; }
       
   164   void set_num(int n) {
       
   165     assert(n <= capacity(), "Too large");
       
   166     _num = n;
       
   167   }
       
   168 
       
   169   // Compare with another list; returns true if all handles are equal (incl.
       
   170   // sort order)
       
   171   bool equals(const ModuleHandleArray& other) const {
       
   172     if (_num != other._num) {
       
   173       return false;
       
   174     }
       
   175     if (::memcmp(ptr(), other.ptr(), _num * sizeof(HMODULE)) != 0) {
       
   176       return false;
       
   177     }
       
   178     return true;
       
   179   }
       
   180 
       
   181   // Copy content from other list.
       
   182   void copy_content_from(ModuleHandleArray& other) {
       
   183     assert(capacity() == other.capacity(), "Different capacities.");
       
   184     memcpy(ptr(), other.ptr(), other._num * sizeof(HMODULE));
       
   185     _num = other._num;
       
   186   }
       
   187 
       
   188 };
       
   189 
       
   190 ////
       
   191 
       
   192 // PathBuffer: a buffer to hold and work with a pdb search PATH - a concatenation
       
   193 // of multiple directories separated by ';'.
       
   194 // A single directory name can be (NTFS) as long as 32K, but in reality is
       
   195 // seldom larger than the (historical) MAX_PATH of 260.
       
   196 
       
   197 #define MINIMUM_PDB_PATH_LENGTH  MAX_PATH * 4
       
   198 #define OPTIMAL_PDB_PATH_LENGTH  MAX_PATH * 64
       
   199 
       
   200 typedef SimpleBufferWithFallback<char, MINIMUM_PDB_PATH_LENGTH, OPTIMAL_PDB_PATH_LENGTH> PathBufferBase;
       
   201 
       
   202 class PathBuffer: public PathBufferBase {
       
   203 public:
       
   204 
       
   205   // Search PDB path for a directory. Search is case insensitive. Returns
       
   206   // true if directory was found in the path, false otherwise.
       
   207   bool contains_directory(const char* directory) {
       
   208     if (ptr() == NULL) {
       
   209       return false;
       
   210     }
       
   211     const size_t len = strlen(directory);
       
   212     if (len == 0) {
       
   213       return false;
       
   214     }
       
   215     char* p = ptr();
       
   216     for(;;) {
       
   217       char* q = strchr(p, ';');
       
   218       if (q != NULL) {
       
   219         if (len == (q - p)) {
       
   220           if (strnicmp(p, directory, len) == 0) {
       
   221             return true;
       
   222           }
       
   223         }
       
   224         p = q + 1;
       
   225       } else {
       
   226         // tail
       
   227         return stricmp(p, directory) == 0 ? true : false;
       
   228       }
       
   229     }
       
   230     return false;
       
   231   }
       
   232 
       
   233   // Appends the given directory to the path. Returns false if internal
       
   234   // buffer size was not sufficient.
       
   235   bool append_directory(const char* directory) {
       
   236     const size_t len = strlen(directory);
       
   237     if (len == 0) {
       
   238       return false;
       
   239     }
       
   240     char* p = ptr();
       
   241     const size_t len_now = strlen(p);
       
   242     const size_t needs_capacity = len_now + 1 + len + 1; // xxx;yy\0
       
   243     if (needs_capacity > (size_t)capacity()) {
       
   244       return false; // OOM
       
   245     }
       
   246     if (len_now > 0) { // Not the first path element.
       
   247       p += len_now;
       
   248       *p = ';';
       
   249       p ++;
       
   250     }
       
   251     strcpy(p, directory);
       
   252     return true;
       
   253   }
       
   254 
       
   255 };
       
   256 
       
   257 // A simple buffer to hold one single file name. A file name can be (NTFS) as
       
   258 // long as 32K, but in reality is seldom larger than MAX_PATH.
       
   259 typedef SimpleBufferWithFallback<char, MAX_PATH, 8 * K> FileNameBuffer;
       
   260 
       
   261 // A buffer to hold a C++ symbol. Usually small, but symbols may be larger for
       
   262 // templates.
       
   263 #define MINIMUM_SYMBOL_NAME_LEN 128
       
   264 #define OPTIMAL_SYMBOL_NAME_LEN 1024
       
   265 
       
   266 typedef SimpleBufferWithFallback<uint8_t,
       
   267         sizeof(IMAGEHLP_SYMBOL64) + MINIMUM_SYMBOL_NAME_LEN,
       
   268         sizeof(IMAGEHLP_SYMBOL64) + OPTIMAL_SYMBOL_NAME_LEN> SymbolBuffer;
       
   269 
       
   270 static struct {
       
   271 
       
   272   // Two buffers to hold lists of loaded modules. handles across invocations of
       
   273   // SymbolEngine::recalc_search_path().
       
   274   ModuleHandleArray loaded_modules;
       
   275   ModuleHandleArray last_loaded_modules;
       
   276   // Buffer to retrieve and assemble the pdb search path.
       
   277   PathBuffer search_path;
       
   278   // Buffer to retrieve directory names for loaded modules.
       
   279   FileNameBuffer dir_name;
       
   280   // Buffer to retrieve decoded symbol information (in SymbolEngine::decode)
       
   281   SymbolBuffer decode_buffer;
       
   282 
       
   283   void initialize() {
       
   284     search_path.initialize();
       
   285     dir_name.initialize();
       
   286     decode_buffer.initialize();
       
   287 
       
   288     loaded_modules.initialize();
       
   289     last_loaded_modules.initialize();
       
   290 
       
   291     // Note: both module lists must have the same capacity. If one allocation
       
   292     // did fail, let them both fall back to the fallback size.
       
   293     if (loaded_modules.capacity() != last_loaded_modules.capacity()) {
       
   294       loaded_modules.reset_to_fallback_capacity();
       
   295       last_loaded_modules.reset_to_fallback_capacity();
       
   296     }
       
   297 
       
   298     assert(search_path.capacity() > 0 && dir_name.capacity() > 0 &&
       
   299             decode_buffer.capacity() > 0 && loaded_modules.capacity() > 0 &&
       
   300             last_loaded_modules.capacity() > 0, "Init error.");
       
   301   }
       
   302 
       
   303 } g_buffers;
       
   304 
       
   305 
       
   306 // Scan the loaded modules.
       
   307 //
       
   308 // For each loaded module, add the directory it is located in to the pdb search
       
   309 // path, but avoid duplicates. Prior search path content is preserved.
       
   310 //
       
   311 // If p_search_path_was_updated is not NULL, points to a bool which, upon
       
   312 // successful return from the function, contains true if the search path
       
   313 // was updated, false if no update was needed because no new DLLs were
       
   314 // loaded or unloaded.
       
   315 //
       
   316 // Returns true for success, false for error.
       
   317 static bool recalc_search_path_locked(bool* p_search_path_was_updated) {
       
   318 
       
   319   if (p_search_path_was_updated) {
       
   320     *p_search_path_was_updated = false;
       
   321   }
       
   322 
       
   323   HANDLE hProcess = ::GetCurrentProcess();
       
   324 
       
   325   BOOL success = false;
       
   326 
       
   327   // 1) Retrieve current set search path.
       
   328   //    (PDB search path is a global setting and someone might have modified
       
   329   //     it, so take care not to remove directories, just to add our own).
       
   330 
       
   331   if (!WindowsDbgHelp::symGetSearchPath(hProcess, g_buffers.search_path.ptr(),
       
   332                                        (int)g_buffers.search_path.capacity())) {
       
   333     return false;
       
   334   }
       
   335   DEBUG_ONLY(g_buffers.search_path.check();)
       
   336 
       
   337   // 2) Retrieve list of modules handles of all currently loaded modules.
       
   338   DWORD bytes_needed = 0;
       
   339   const DWORD buffer_capacity_bytes = (DWORD)g_buffers.loaded_modules.capacity() * sizeof(HMODULE);
       
   340   success = ::EnumProcessModules(hProcess, g_buffers.loaded_modules.ptr(),
       
   341                                  buffer_capacity_bytes, &bytes_needed);
       
   342   DEBUG_ONLY(g_buffers.loaded_modules.check();)
       
   343 
       
   344   // Note: EnumProcessModules is sloppily defined in terms of whether a
       
   345   // too-small output buffer counts as error. Will it truncate but still
       
   346   // return TRUE? Nobody knows and the manpage is not telling. So we count
       
   347   // truncation it as error, disregarding the return value.
       
   348   if (!success || bytes_needed > buffer_capacity_bytes) {
       
   349     return false;
       
   350   } else {
       
   351     const int num_modules = bytes_needed / sizeof(HMODULE);
       
   352     g_buffers.loaded_modules.set_num(num_modules);
       
   353   }
       
   354 
       
   355   // Compare the list of module handles with the last list. If the lists are
       
   356   // identical, no additional dlls were loaded and we can stop.
       
   357   if (g_buffers.loaded_modules.equals(g_buffers.last_loaded_modules)) {
       
   358     return true;
       
   359   } else {
       
   360     // Remember the new set of module handles and continue.
       
   361     g_buffers.last_loaded_modules.copy_content_from(g_buffers.loaded_modules);
       
   362   }
       
   363 
       
   364   // 3) For each loaded module: retrieve directory from which it was loaded.
       
   365   //    Add directory to search path (but avoid duplicates).
       
   366 
       
   367   bool did_modify_searchpath = false;
       
   368 
       
   369   for (int i = 0; i < (int)g_buffers.loaded_modules.num(); i ++) {
       
   370 
       
   371     const HMODULE hMod = g_buffers.loaded_modules.ptr()[i];
       
   372     char* const filebuffer = g_buffers.dir_name.ptr();
       
   373     const int file_buffer_capacity = g_buffers.dir_name.capacity();
       
   374     const int len_returned = (int)::GetModuleFileName(hMod, filebuffer, (DWORD)file_buffer_capacity);
       
   375     DEBUG_ONLY(g_buffers.dir_name.check();)
       
   376     if (len_returned == 0) {
       
   377       // Error. This is suspicious - this may happen if a module has just been
       
   378       // unloaded concurrently after our call to EnumProcessModules and
       
   379       // GetModuleFileName, but probably just indicates a coding error.
       
   380       assert(false, "GetModuleFileName failed (%u)", ::GetLastError());
       
   381     } else if (len_returned == file_buffer_capacity) {
       
   382       // Truncation. Just skip this module and continue with the next module.
       
   383       continue;
       
   384     }
       
   385 
       
   386     // Cut file name part off.
       
   387     char* last_slash = ::strrchr(filebuffer, '\\');
       
   388     if (last_slash == NULL) {
       
   389       last_slash = ::strrchr(filebuffer, '/');
       
   390     }
       
   391     if (last_slash) {
       
   392       *last_slash = '\0';
       
   393     }
       
   394 
       
   395     // If this is already part of the search path, ignore it, otherwise
       
   396     // append to search path.
       
   397     if (!g_buffers.search_path.contains_directory(filebuffer)) {
       
   398       if (!g_buffers.search_path.append_directory(filebuffer)) {
       
   399         return false; // oom
       
   400       }
       
   401       DEBUG_ONLY(g_buffers.search_path.check();)
       
   402       did_modify_searchpath = true;
       
   403     }
       
   404 
       
   405   } // for each loaded module.
       
   406 
       
   407   // If we did not modify the search path, nothing further needs to be done.
       
   408   if (!did_modify_searchpath) {
       
   409     return true;
       
   410   }
       
   411 
       
   412   // Set the search path to its new value.
       
   413   if (!WindowsDbgHelp::symSetSearchPath(hProcess, g_buffers.search_path.ptr())) {
       
   414     return false;
       
   415   }
       
   416 
       
   417   if (p_search_path_was_updated) {
       
   418     *p_search_path_was_updated = true;
       
   419   }
       
   420 
       
   421   return true;
       
   422 
       
   423 }
       
   424 
       
   425 static bool demangle_locked(const char* symbol, char *buf, int buflen) {
       
   426 
       
   427   return WindowsDbgHelp::unDecorateSymbolName(symbol, buf, buflen, UNDNAME_COMPLETE) > 0;
       
   428 
       
   429 }
       
   430 
       
   431 static bool decode_locked(const void* addr, char* buf, int buflen, int* offset, bool do_demangle) {
       
   432 
       
   433   assert(g_buffers.decode_buffer.capacity() >= (sizeof(IMAGEHLP_SYMBOL64) + MINIMUM_SYMBOL_NAME_LEN),
       
   434          "Decode buffer too small.");
       
   435   assert(buf != NULL && buflen > 0 && offset != NULL, "invalid output buffer.");
       
   436 
       
   437   DWORD64 displacement;
       
   438   PIMAGEHLP_SYMBOL64 pSymbol = NULL;
       
   439   bool success = false;
       
   440 
       
   441   pSymbol = (PIMAGEHLP_SYMBOL64) g_buffers.decode_buffer.ptr();
       
   442   pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
       
   443   pSymbol->MaxNameLength = (DWORD)(g_buffers.decode_buffer.capacity() - sizeof(IMAGEHLP_SYMBOL64) - 1);
       
   444 
       
   445   // It is unclear how SymGetSymFromAddr64 handles truncation. Experiments
       
   446   // show it will return TRUE but not zero terminate (which is a really bad
       
   447   // combination). Lets be super careful.
       
   448   ::memset(pSymbol->Name, 0, pSymbol->MaxNameLength); // To catch truncation.
       
   449 
       
   450   if (WindowsDbgHelp::symGetSymFromAddr64(::GetCurrentProcess(), (DWORD64)addr, &displacement, pSymbol)) {
       
   451     success = true;
       
   452     if (pSymbol->Name[pSymbol->MaxNameLength - 1] != '\0') {
       
   453       // Symbol was truncated. Do not attempt to demangle. Instead, zero terminate the
       
   454       // truncated string. We still return success - the truncated string may still
       
   455       // be usable for the caller.
       
   456       pSymbol->Name[pSymbol->MaxNameLength - 1] = '\0';
       
   457       do_demangle = false;
       
   458     }
       
   459 
       
   460     // Attempt to demangle.
       
   461     if (do_demangle && demangle_locked(pSymbol->Name, buf, buflen)) {
       
   462       // ok.
       
   463     } else {
       
   464       ::strncpy(buf, pSymbol->Name, buflen - 1);
       
   465     }
       
   466     buf[buflen - 1] = '\0';
       
   467 
       
   468     *offset = (int)displacement;
       
   469   }
       
   470 
       
   471   DEBUG_ONLY(g_buffers.decode_buffer.check();)
       
   472 
       
   473   return success;
       
   474 }
       
   475 
       
   476 static enum {
       
   477   state_uninitialized = 0,
       
   478   state_ready = 1,
       
   479   state_error = 2
       
   480 } g_state = state_uninitialized;
       
   481 
       
   482 static void initialize() {
       
   483 
       
   484   assert(g_state == state_uninitialized, "wrong sequence");
       
   485   g_state = state_error;
       
   486 
       
   487   // 1) Initialize buffers.
       
   488   g_buffers.initialize();
       
   489 
       
   490   // 1) Call SymInitialize
       
   491   HANDLE hProcess = ::GetCurrentProcess();
       
   492   WindowsDbgHelp::symSetOptions(SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_DEFERRED_LOADS |
       
   493                         SYMOPT_EXACT_SYMBOLS | SYMOPT_LOAD_LINES);
       
   494   if (!WindowsDbgHelp::symInitialize(hProcess, NULL, TRUE)) {
       
   495     return;
       
   496   }
       
   497 
       
   498   // Note: we ignore any errors from this point on. The symbol engine may be
       
   499   // usable enough.
       
   500   g_state = state_ready;
       
   501 
       
   502   (void)recalc_search_path_locked(NULL);
       
   503 
       
   504 }
       
   505 
       
   506 ///////////////////// External functions //////////////////////////
       
   507 
       
   508 // All outside facing functions are synchronized. Also, we run
       
   509 // initialization on first touch.
       
   510 
       
   511 static CRITICAL_SECTION g_cs;
       
   512 
       
   513 namespace { // Do not export.
       
   514   class SymbolEngineEntry {
       
   515    public:
       
   516     SymbolEngineEntry() {
       
   517       ::EnterCriticalSection(&g_cs);
       
   518       if (g_state == state_uninitialized) {
       
   519         initialize();
       
   520       }
       
   521     }
       
   522     ~SymbolEngineEntry() {
       
   523       ::LeaveCriticalSection(&g_cs);
       
   524     }
       
   525   };
       
   526 }
       
   527 
       
   528 // Called at DLL_PROCESS_ATTACH.
       
   529 void SymbolEngine::pre_initialize() {
       
   530   ::InitializeCriticalSection(&g_cs);
       
   531 }
       
   532 
       
   533 bool SymbolEngine::decode(const void* addr, char* buf, int buflen, int* offset, bool do_demangle) {
       
   534 
       
   535   assert(buf != NULL && buflen > 0 && offset != NULL, "Argument error");
       
   536   buf[0] = '\0';
       
   537   *offset = -1;
       
   538 
       
   539   if (addr == NULL) {
       
   540     return false;
       
   541   }
       
   542 
       
   543   SymbolEngineEntry entry_guard;
       
   544 
       
   545   // Try decoding the symbol once. If we fail, attempt to rebuild the
       
   546   // symbol search path - maybe the pc points to a dll whose pdb file is
       
   547   // outside our search path. Then do attempt the decode again.
       
   548   bool success = decode_locked(addr, buf, buflen, offset, do_demangle);
       
   549   if (!success) {
       
   550     bool did_update_search_path = false;
       
   551     if (recalc_search_path_locked(&did_update_search_path)) {
       
   552       if (did_update_search_path) {
       
   553         success = decode_locked(addr, buf, buflen, offset, do_demangle);
       
   554       }
       
   555     }
       
   556   }
       
   557 
       
   558   return success;
       
   559 
       
   560 }
       
   561 
       
   562 bool SymbolEngine::demangle(const char* symbol, char *buf, int buflen) {
       
   563 
       
   564   SymbolEngineEntry entry_guard;
       
   565 
       
   566   return demangle_locked(symbol, buf, buflen);
       
   567 
       
   568 }
       
   569 
       
   570 bool SymbolEngine::recalc_search_path(bool* p_search_path_was_updated) {
       
   571 
       
   572   SymbolEngineEntry entry_guard;
       
   573 
       
   574   return recalc_search_path_locked(p_search_path_was_updated);
       
   575 
       
   576 }
       
   577 
       
   578 bool SymbolEngine::get_source_info(const void* addr, char* buf, size_t buflen,
       
   579                                    int* line_no)
       
   580 {
       
   581   assert(buf != NULL && buflen > 0 && line_no != NULL, "Argument error");
       
   582   buf[0] = '\0';
       
   583   *line_no = -1;
       
   584 
       
   585   if (addr == NULL) {
       
   586     return false;
       
   587   }
       
   588 
       
   589   SymbolEngineEntry entry_guard;
       
   590 
       
   591   IMAGEHLP_LINE64 lineinfo;
       
   592   memset(&lineinfo, 0, sizeof(lineinfo));
       
   593   lineinfo.SizeOfStruct = sizeof(lineinfo);
       
   594   DWORD displacement;
       
   595   if (WindowsDbgHelp::symGetLineFromAddr64(::GetCurrentProcess(), (DWORD64)addr,
       
   596                                            &displacement, &lineinfo)) {
       
   597     if (buf != NULL && buflen > 0 && lineinfo.FileName != NULL) {
       
   598       // We only return the file name, not the whole path.
       
   599       char* p = lineinfo.FileName;
       
   600       char* q = strrchr(lineinfo.FileName, '\\');
       
   601       if (q) {
       
   602         p = q + 1;
       
   603       }
       
   604       ::strncpy(buf, p, buflen - 1);
       
   605       buf[buflen - 1] = '\0';
       
   606     }
       
   607     if (line_no != 0) {
       
   608       *line_no = lineinfo.LineNumber;
       
   609     }
       
   610     return true;
       
   611   }
       
   612   return false;
       
   613 }
       
   614 
       
   615 // Print one liner describing state (if library loaded, which functions are
       
   616 // missing - if any, and the dbhelp API version)
       
   617 void SymbolEngine::print_state_on(outputStream* st) {
       
   618 
       
   619   SymbolEngineEntry entry_guard;
       
   620 
       
   621   st->print("symbol engine: ");
       
   622 
       
   623   if (g_state == state_uninitialized) {
       
   624     st->print("uninitialized.");
       
   625   } else if (g_state == state_error) {
       
   626     st->print("initialization error.");
       
   627   } else {
       
   628     st->print("initialized successfully");
       
   629     st->print(" - sym options: 0x%X", WindowsDbgHelp::symGetOptions());
       
   630     st->print(" - pdb path: ");
       
   631     if (WindowsDbgHelp::symGetSearchPath(::GetCurrentProcess(),
       
   632                                           g_buffers.search_path.ptr(),
       
   633                                           (int)g_buffers.search_path.capacity())) {
       
   634       st->print_raw(g_buffers.search_path.ptr());
       
   635     } else {
       
   636       st->print_raw("(cannot be retrieved)");
       
   637     }
       
   638   }
       
   639   st->cr();
       
   640 
       
   641 }