GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/debug_utils.cc Lines: 2 69 2.9 %
Date: 2019-02-01 22:03:38 Branches: 1 26 3.8 %

Line Branch Exec Source
1
#include "debug_utils.h"
2
3
#ifdef __POSIX__
4
#if defined(__linux__)
5
#include <features.h>
6
#endif
7
8
#if defined(__linux__) && !defined(__GLIBC__) || \
9
    defined(__UCLIBC__) || \
10
    defined(_AIX)
11
#define HAVE_EXECINFO_H 0
12
#else
13
#define HAVE_EXECINFO_H 1
14
#endif
15
16
#if HAVE_EXECINFO_H
17
#include <cxxabi.h>
18
#include <dlfcn.h>
19
#include <execinfo.h>
20
#include <unistd.h>
21
#include <sys/mman.h>
22
#include <stdio.h>
23
#endif
24
25
#else  // __POSIX__
26
27
#include <windows.h>
28
#include <dbghelp.h>
29
30
#endif  // __POSIX__
31
32
#if defined(__linux__) || defined(__sun) || defined(__FreeBSD__)
33
#include <link.h>
34
#endif  // (__linux__) || defined(__sun) || defined(__FreeBSD__)
35
36
#ifdef __APPLE__
37
#include <mach-o/dyld.h>  // _dyld_get_image_name()
38
#endif                    // __APPLE__
39
40
#ifdef _AIX
41
#include <sys/ldr.h>  // ld_info structure
42
#endif                // _AIX
43
44
#ifdef _WIN32
45
#include <Lm.h>
46
#include <Windows.h>
47
#include <dbghelp.h>
48
#include <process.h>
49
#include <psapi.h>
50
#include <tchar.h>
51
#endif  // _WIN32
52
53
namespace node {
54
55
#ifdef __POSIX__
56
#if HAVE_EXECINFO_H
57
class PosixSymbolDebuggingContext final : public NativeSymbolDebuggingContext {
58
 public:
59
  PosixSymbolDebuggingContext() : pagesize_(getpagesize()) { }
60
61
  SymbolInfo LookupSymbol(void* address) override {
62
    Dl_info info;
63
    const bool have_info = dladdr(address, &info);
64
    SymbolInfo ret;
65
    if (!have_info)
66
      return ret;
67
68
    if (info.dli_sname != nullptr) {
69
      if (char* demangled = abi::__cxa_demangle(info.dli_sname, 0, 0, 0)) {
70
        ret.name = demangled;
71
        free(demangled);
72
      } else {
73
        ret.name = info.dli_sname;
74
      }
75
    }
76
77
    if (info.dli_fname != nullptr) {
78
      ret.filename = info.dli_fname;
79
    }
80
81
    return ret;
82
  }
83
84
  bool IsMapped(void* address) override {
85
    void* page_aligned = reinterpret_cast<void*>(
86
        reinterpret_cast<uintptr_t>(address) & ~(pagesize_ - 1));
87
    return msync(page_aligned, pagesize_, MS_ASYNC) == 0;
88
  }
89
90
  int GetStackTrace(void** frames, int count) override {
91
    return backtrace(frames, count);
92
  }
93
94
 private:
95
  uintptr_t pagesize_;
96
};
97
98
std::unique_ptr<NativeSymbolDebuggingContext>
99
NativeSymbolDebuggingContext::New() {
100
  return std::unique_ptr<NativeSymbolDebuggingContext>(
101
      new PosixSymbolDebuggingContext());
102
}
103
104
#else  // HAVE_EXECINFO_H
105
106
std::unique_ptr<NativeSymbolDebuggingContext>
107
NativeSymbolDebuggingContext::New() {
108
  return std::unique_ptr<NativeSymbolDebuggingContext>(
109
      new NativeSymbolDebuggingContext());
110
}
111
112
#endif  // HAVE_EXECINFO_H
113
114
#else  // __POSIX__
115
116
class Win32SymbolDebuggingContext final : public NativeSymbolDebuggingContext {
117
 public:
118
  Win32SymbolDebuggingContext() {
119
    current_process_ = GetCurrentProcess();
120
    USE(SymInitialize(current_process_, nullptr, true));
121
  }
122
123
  ~Win32SymbolDebuggingContext() override {
124
    USE(SymCleanup(current_process_));
125
  }
126
127
  using NameAndDisplacement = std::pair<std::string, DWORD64>;
128
  NameAndDisplacement WrappedSymFromAddr(DWORD64 dwAddress) const {
129
    // Refs: https://docs.microsoft.com/en-us/windows/desktop/Debug/retrieving-symbol-information-by-address
130
    // Patches:
131
    // Use `fprintf(stderr, ` instead of `printf`
132
    // `sym.filename = pSymbol->Name` on success
133
    // `current_process_` instead of `hProcess.
134
    DWORD64 dwDisplacement = 0;
135
    // Patch: made into arg - DWORD64  dwAddress = SOME_ADDRESS;
136
137
    char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
138
    const auto pSymbol = reinterpret_cast<PSYMBOL_INFO>(buffer);
139
140
    pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
141
    pSymbol->MaxNameLen = MAX_SYM_NAME;
142
143
    if (SymFromAddr(current_process_, dwAddress, &dwDisplacement, pSymbol)) {
144
      // SymFromAddr returned success
145
      return NameAndDisplacement(pSymbol->Name, dwDisplacement);
146
    } else {
147
      // SymFromAddr failed
148
      const DWORD error = GetLastError();  // "eat" the error anyway
149
#ifdef DEBUG
150
      fprintf(stderr, "SymFromAddr returned error : %lu\n", error);
151
#endif
152
    }
153
    // End MSDN code
154
155
    return NameAndDisplacement();
156
  }
157
158
  SymbolInfo WrappedGetLine(DWORD64 dwAddress) const {
159
    SymbolInfo sym{};
160
161
    // Refs: https://docs.microsoft.com/en-us/windows/desktop/Debug/retrieving-symbol-information-by-address
162
    // Patches:
163
    // Use `fprintf(stderr, ` instead of `printf`.
164
    // Assign values to `sym` on success.
165
    // `current_process_` instead of `hProcess.
166
167
    // Patch: made into arg - DWORD64  dwAddress;
168
    DWORD dwDisplacement;
169
    IMAGEHLP_LINE64 line;
170
171
    SymSetOptions(SYMOPT_LOAD_LINES);
172
173
    line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
174
    // Patch: made into arg - dwAddress = 0x1000000;
175
176
    if (SymGetLineFromAddr64(current_process_, dwAddress,
177
                             &dwDisplacement, &line)) {
178
      // SymGetLineFromAddr64 returned success
179
      sym.filename = line.FileName;
180
      sym.line = line.LineNumber;
181
    } else {
182
      // SymGetLineFromAddr64 failed
183
      const DWORD error = GetLastError();  // "eat" the error anyway
184
#ifdef DEBUG
185
      fprintf(stderr, "SymGetLineFromAddr64 returned error : %lu\n", error);
186
#endif
187
    }
188
    // End MSDN code
189
190
    return sym;
191
  }
192
193
  // Fills the SymbolInfo::name of the io/out argument `sym`
194
  std::string WrappedUnDecorateSymbolName(const char* name) const {
195
    // Refs: https://docs.microsoft.com/en-us/windows/desktop/Debug/retrieving-undecorated-symbol-names
196
    // Patches:
197
    // Use `fprintf(stderr, ` instead of `printf`.
198
    // return `szUndName` instead of `printf` on success
199
    char szUndName[MAX_SYM_NAME];
200
    if (UnDecorateSymbolName(name, szUndName, sizeof(szUndName),
201
                             UNDNAME_COMPLETE)) {
202
      // UnDecorateSymbolName returned success
203
      return szUndName;
204
    } else {
205
      // UnDecorateSymbolName failed
206
      const DWORD error = GetLastError();  // "eat" the error anyway
207
#ifdef DEBUG
208
      fprintf(stderr, "UnDecorateSymbolName returned error %lu\n", error);
209
#endif
210
    }
211
    return nullptr;
212
  }
213
214
  SymbolInfo LookupSymbol(void* address) override {
215
    const DWORD64 dw_address = reinterpret_cast<DWORD64>(address);
216
    SymbolInfo ret = WrappedGetLine(dw_address);
217
    std::tie(ret.name, ret.dis) = WrappedSymFromAddr(dw_address);
218
    if (!ret.name.empty()) {
219
      ret.name = WrappedUnDecorateSymbolName(ret.name.c_str());
220
    }
221
    return ret;
222
  }
223
224
  bool IsMapped(void* address) override {
225
    MEMORY_BASIC_INFORMATION info;
226
227
    if (VirtualQuery(address, &info, sizeof(info)) != sizeof(info))
228
      return false;
229
230
    return info.State == MEM_COMMIT && info.Protect != 0;
231
  }
232
233
  int GetStackTrace(void** frames, int count) override {
234
    return CaptureStackBackTrace(0, count, frames, nullptr);
235
  }
236
237
  Win32SymbolDebuggingContext(const Win32SymbolDebuggingContext&) = delete;
238
  Win32SymbolDebuggingContext(Win32SymbolDebuggingContext&&) = delete;
239
  Win32SymbolDebuggingContext operator=(const Win32SymbolDebuggingContext&)
240
    = delete;
241
  Win32SymbolDebuggingContext operator=(Win32SymbolDebuggingContext&&)
242
    = delete;
243
244
 private:
245
  HANDLE current_process_;
246
};
247
248
std::unique_ptr<NativeSymbolDebuggingContext>
249
NativeSymbolDebuggingContext::New() {
250
  return std::unique_ptr<NativeSymbolDebuggingContext>(
251
      new Win32SymbolDebuggingContext());
252
}
253
254
#endif  // __POSIX__
255
256
std::string NativeSymbolDebuggingContext::SymbolInfo::Display() const {
257
  std::ostringstream oss;
258
  oss << name;
259
  if (dis != 0) {
260
    oss << "+" << dis;
261
  }
262
  if (!filename.empty()) {
263
    oss << " [" << filename << ']';
264
  }
265
  if (line != 0) {
266
    oss << ":L" << line;
267
  }
268
  return oss.str();
269
}
270
271
void DumpBacktrace(FILE* fp) {
272
  auto sym_ctx = NativeSymbolDebuggingContext::New();
273
  void* frames[256];
274
  const int size = sym_ctx->GetStackTrace(frames, arraysize(frames));
275
  for (int i = 1; i < size; i += 1) {
276
    void* frame = frames[i];
277
    NativeSymbolDebuggingContext::SymbolInfo s = sym_ctx->LookupSymbol(frame);
278
    fprintf(fp, "%2d: %p %s\n", i, frame, s.Display().c_str());
279
  }
280
}
281
282
332
void CheckedUvLoopClose(uv_loop_t* loop) {
283
664
  if (uv_loop_close(loop) == 0) return;
284
285
  auto sym_ctx = NativeSymbolDebuggingContext::New();
286
287
  fprintf(stderr, "uv loop at [%p] has active handles\n", loop);
288
289
  uv_walk(loop, [](uv_handle_t* handle, void* arg) {
290
    auto sym_ctx = static_cast<NativeSymbolDebuggingContext*>(arg);
291
292
    fprintf(stderr, "[%p] %s\n", handle, uv_handle_type_name(handle->type));
293
294
    void* close_cb = reinterpret_cast<void*>(handle->close_cb);
295
    fprintf(stderr, "\tClose callback: %p %s\n",
296
        close_cb, sym_ctx->LookupSymbol(close_cb).Display().c_str());
297
298
    fprintf(stderr, "\tData: %p %s\n",
299
        handle->data, sym_ctx->LookupSymbol(handle->data).Display().c_str());
300
301
    // We are also interested in the first field of what `handle->data`
302
    // points to, because for C++ code that is usually the virtual table pointer
303
    // and gives us information about the exact kind of object we're looking at.
304
    void* first_field = nullptr;
305
    // `handle->data` might be any value, including `nullptr`, or something
306
    // cast from a completely different type; therefore, check that it’s
307
    // dereferencable first.
308
    if (sym_ctx->IsMapped(handle->data))
309
      first_field = *reinterpret_cast<void**>(handle->data);
310
311
    if (first_field != nullptr) {
312
      fprintf(stderr, "\t(First field): %p %s\n",
313
          first_field, sym_ctx->LookupSymbol(first_field).Display().c_str());
314
    }
315
  }, sym_ctx.get());
316
317
  fflush(stderr);
318
  // Finally, abort.
319
  CHECK(0 && "uv_loop_close() while having open handles");
320
}
321
322
std::vector<std::string> NativeSymbolDebuggingContext::GetLoadedLibraries() {
323
  std::vector<std::string> list;
324
#if defined(__linux__) || defined(__FreeBSD__)
325
  dl_iterate_phdr(
326
      [](struct dl_phdr_info* info, size_t size, void* data) {
327
        auto list = static_cast<std::vector<std::string>*>(data);
328
        if (*info->dlpi_name != '\0') {
329
          list->push_back(info->dlpi_name);
330
        }
331
        return 0;
332
      },
333
      &list);
334
#elif __APPLE__
335
  uint32_t i = 0;
336
  for (const char* name = _dyld_get_image_name(i); name != nullptr;
337
       name = _dyld_get_image_name(++i)) {
338
    list.push_back(name);
339
  }
340
341
#elif _AIX
342
  // We can't tell in advance how large the buffer needs to be.
343
  // Retry until we reach too large a size (1Mb).
344
  const unsigned int kBufferGrowStep = 4096;
345
  MallocedBuffer<char> buffer(kBufferGrowStep);
346
  int rc = -1;
347
  do {
348
    rc = loadquery(L_GETINFO, buffer.data, buffer.size);
349
    if (rc == 0) break;
350
    buffer = MallocedBuffer<char>(buffer.size + kBufferGrowStep);
351
  } while (buffer.size < 1024 * 1024);
352
353
  if (rc == 0) {
354
    char* buf = buffer.data;
355
    ld_info* cur_info = nullptr;
356
    do {
357
      std::ostringstream str;
358
      cur_info = reinterpret_cast<ld_info*>(buf);
359
      char* member_name = cur_info->ldinfo_filename +
360
          strlen(cur_info->ldinfo_filename) + 1;
361
      if (*member_name != '\0') {
362
        str << cur_info->ldinfo_filename << "(" << member_name << ")";
363
        list.push_back(str.str());
364
        str.str("");
365
      } else {
366
        list.push_back(cur_info->ldinfo_filename);
367
      }
368
      buf += cur_info->ldinfo_next;
369
    } while (cur_info->ldinfo_next != 0);
370
  }
371
#elif __sun
372
  Link_map* p;
373
374
  if (dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &p) != -1) {
375
    for (Link_map* l = p; l != nullptr; l = l->l_next) {
376
      list.push_back(l->l_name);
377
    }
378
  }
379
380
#elif _WIN32
381
  // Windows implementation - get a handle to the process.
382
  HANDLE process_handle = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,
383
                                      FALSE, GetCurrentProcessId());
384
  if (process_handle == nullptr) {
385
    // Cannot proceed, return an empty list.
386
    return list;
387
  }
388
  // Get a list of all the modules in this process
389
  DWORD size_1 = 0;
390
  DWORD size_2 = 0;
391
  // First call to get the size of module array needed
392
  if (EnumProcessModules(process_handle, nullptr, 0, &size_1)) {
393
    MallocedBuffer<HMODULE> modules(size_1);
394
395
    // Second call to populate the module array
396
    if (EnumProcessModules(process_handle, modules.data, size_1, &size_2)) {
397
      for (DWORD i = 0;
398
           i < (size_1 / sizeof(HMODULE)) && i < (size_2 / sizeof(HMODULE));
399
           i++) {
400
        WCHAR module_name[MAX_PATH];
401
        // Obtain and report the full pathname for each module
402
        if (GetModuleFileNameExW(process_handle,
403
                                 modules.data[i],
404
                                 module_name,
405
                                 arraysize(module_name) / sizeof(WCHAR))) {
406
          DWORD size = WideCharToMultiByte(
407
              CP_UTF8, 0, module_name, -1, nullptr, 0, nullptr, nullptr);
408
          char* str = new char[size];
409
          WideCharToMultiByte(
410
              CP_UTF8, 0, module_name, -1, str, size, nullptr, nullptr);
411
          list.push_back(str);
412
        }
413
      }
414
    }
415
  }
416
417
  // Release the handle to the process.
418
  CloseHandle(process_handle);
419
#endif
420
  return list;
421
}
422
423
424
}  // namespace node
425
426
extern "C" void __DumpBacktrace(FILE* fp) {
427
  node::DumpBacktrace(fp);
428
}