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: 48 77 62.3 %
Date: 2019-09-07 22:28:56 Branches: 15 26 57.7 %

Line Branch Exec Source
1
#include "debug_utils.h"
2
#include "env-inl.h"
3
#include "util-inl.h"
4
5
#ifdef __POSIX__
6
#if defined(__linux__)
7
#include <features.h>
8
#endif
9
10
#if defined(__linux__) && !defined(__GLIBC__) || \
11
    defined(__UCLIBC__) || \
12
    defined(_AIX)
13
#define HAVE_EXECINFO_H 0
14
#else
15
#define HAVE_EXECINFO_H 1
16
#endif
17
18
#if HAVE_EXECINFO_H
19
#include <cxxabi.h>
20
#include <dlfcn.h>
21
#include <execinfo.h>
22
#include <unistd.h>
23
#include <sys/mman.h>
24
#include <cstdio>
25
#endif
26
27
#endif  // __POSIX__
28
29
#if defined(__linux__) || defined(__sun) || \
30
    defined(__FreeBSD__) || defined(__OpenBSD__)
31
#include <link.h>
32
#endif  // (__linux__) || defined(__sun) ||
33
        // (__FreeBSD__) || defined(__OpenBSD__)
34
35
#ifdef __APPLE__
36
#include <mach-o/dyld.h>  // _dyld_get_image_name()
37
#endif                    // __APPLE__
38
39
#ifdef _AIX
40
#include <sys/ldr.h>  // ld_info structure
41
#endif                // _AIX
42
43
#ifdef _WIN32
44
#include <Lm.h>
45
#include <Windows.h>
46
#include <dbghelp.h>
47
#include <process.h>
48
#include <psapi.h>
49
#include <tchar.h>
50
#endif  // _WIN32
51
52
namespace node {
53
54
#ifdef __POSIX__
55
#if HAVE_EXECINFO_H
56
38
class PosixSymbolDebuggingContext final : public NativeSymbolDebuggingContext {
57
 public:
58
19
  PosixSymbolDebuggingContext() : pagesize_(getpagesize()) { }
59
60
148
  SymbolInfo LookupSymbol(void* address) override {
61
    Dl_info info;
62
148
    const bool have_info = dladdr(address, &info);
63
148
    SymbolInfo ret;
64
148
    if (!have_info)
65
      return ret;
66
67
148
    if (info.dli_sname != nullptr) {
68
63
      if (char* demangled =
69
63
              abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, nullptr)) {
70
61
        ret.name = demangled;
71
61
        free(demangled);
72
      } else {
73
2
        ret.name = info.dli_sname;
74
      }
75
    }
76
77
148
    if (info.dli_fname != nullptr) {
78
148
      ret.filename = info.dli_fname;
79
    }
80
81
148
    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
19
  int GetStackTrace(void** frames, int count) override {
91
19
    return backtrace(frames, count);
92
  }
93
94
 private:
95
  uintptr_t pagesize_;
96
};
97
98
std::unique_ptr<NativeSymbolDebuggingContext>
99
19
NativeSymbolDebuggingContext::New() {
100
  return std::unique_ptr<NativeSymbolDebuggingContext>(
101
19
      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
148
std::string NativeSymbolDebuggingContext::SymbolInfo::Display() const {
257
148
  std::ostringstream oss;
258
148
  oss << name;
259
148
  if (dis != 0) {
260
    oss << "+" << dis;
261
  }
262
148
  if (!filename.empty()) {
263
148
    oss << " [" << filename << ']';
264
  }
265
148
  if (line != 0) {
266
    oss << ":L" << line;
267
  }
268
148
  return oss.str();
269
}
270
271
4
void DumpBacktrace(FILE* fp) {
272
4
  auto sym_ctx = NativeSymbolDebuggingContext::New();
273
  void* frames[256];
274
4
  const int size = sym_ctx->GetStackTrace(frames, arraysize(frames));
275
32
  for (int i = 1; i < size; i += 1) {
276
28
    void* frame = frames[i];
277
28
    NativeSymbolDebuggingContext::SymbolInfo s = sym_ctx->LookupSymbol(frame);
278
28
    fprintf(fp, "%2d: %p %s\n", i, frame, s.Display().c_str());
279
32
  }
280
4
}
281
282
18124
void CheckedUvLoopClose(uv_loop_t* loop) {
283
36248
  if (uv_loop_close(loop) == 0) return;
284
285
  PrintLibuvHandleInformation(loop, stderr);
286
287
  fflush(stderr);
288
  // Finally, abort.
289
  CHECK(0 && "uv_loop_close() while having open handles");
290
}
291
292
void PrintLibuvHandleInformation(uv_loop_t* loop, FILE* stream) {
293
  struct Info {
294
    std::unique_ptr<NativeSymbolDebuggingContext> ctx;
295
    FILE* stream;
296
  };
297
298
  Info info { NativeSymbolDebuggingContext::New(), stream };
299
300
  fprintf(stream, "uv loop at [%p] has %d active handles\n",
301
          loop, loop->active_handles);
302
303
  uv_walk(loop, [](uv_handle_t* handle, void* arg) {
304
    Info* info = static_cast<Info*>(arg);
305
    NativeSymbolDebuggingContext* sym_ctx = info->ctx.get();
306
    FILE* stream = info->stream;
307
308
    fprintf(stream, "[%p] %s\n", handle, uv_handle_type_name(handle->type));
309
310
    void* close_cb = reinterpret_cast<void*>(handle->close_cb);
311
    fprintf(stream, "\tClose callback: %p %s\n",
312
        close_cb, sym_ctx->LookupSymbol(close_cb).Display().c_str());
313
314
    fprintf(stream, "\tData: %p %s\n",
315
        handle->data, sym_ctx->LookupSymbol(handle->data).Display().c_str());
316
317
    // We are also interested in the first field of what `handle->data`
318
    // points to, because for C++ code that is usually the virtual table pointer
319
    // and gives us information about the exact kind of object we're looking at.
320
    void* first_field = nullptr;
321
    // `handle->data` might be any value, including `nullptr`, or something
322
    // cast from a completely different type; therefore, check that it’s
323
    // dereferencable first.
324
    if (sym_ctx->IsMapped(handle->data))
325
      first_field = *reinterpret_cast<void**>(handle->data);
326
327
    if (first_field != nullptr) {
328
      fprintf(stream, "\t(First field): %p %s\n",
329
          first_field, sym_ctx->LookupSymbol(first_field).Display().c_str());
330
    }
331
  }, &info);
332
}
333
334
15
std::vector<std::string> NativeSymbolDebuggingContext::GetLoadedLibraries() {
335
15
  std::vector<std::string> list;
336
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__)
337
  dl_iterate_phdr(
338
321
      [](struct dl_phdr_info* info, size_t size, void* data) {
339
153
        auto list = static_cast<std::vector<std::string>*>(data);
340
153
        if (*info->dlpi_name != '\0') {
341
123
          list->push_back(info->dlpi_name);
342
        }
343
153
        return 0;
344
168
      },
345
15
      &list);
346
#elif __APPLE__
347
  uint32_t i = 0;
348
  for (const char* name = _dyld_get_image_name(i); name != nullptr;
349
       name = _dyld_get_image_name(++i)) {
350
    list.push_back(name);
351
  }
352
353
#elif _AIX
354
  // We can't tell in advance how large the buffer needs to be.
355
  // Retry until we reach too large a size (1Mb).
356
  const unsigned int kBufferGrowStep = 4096;
357
  MallocedBuffer<char> buffer(kBufferGrowStep);
358
  int rc = -1;
359
  do {
360
    rc = loadquery(L_GETINFO, buffer.data, buffer.size);
361
    if (rc == 0) break;
362
    buffer = MallocedBuffer<char>(buffer.size + kBufferGrowStep);
363
  } while (buffer.size < 1024 * 1024);
364
365
  if (rc == 0) {
366
    char* buf = buffer.data;
367
    ld_info* cur_info = nullptr;
368
    do {
369
      std::ostringstream str;
370
      cur_info = reinterpret_cast<ld_info*>(buf);
371
      char* member_name = cur_info->ldinfo_filename +
372
          strlen(cur_info->ldinfo_filename) + 1;
373
      if (*member_name != '\0') {
374
        str << cur_info->ldinfo_filename << "(" << member_name << ")";
375
        list.push_back(str.str());
376
        str.str("");
377
      } else {
378
        list.push_back(cur_info->ldinfo_filename);
379
      }
380
      buf += cur_info->ldinfo_next;
381
    } while (cur_info->ldinfo_next != 0);
382
  }
383
#elif __sun
384
  Link_map* p;
385
386
  if (dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &p) != -1) {
387
    for (Link_map* l = p; l != nullptr; l = l->l_next) {
388
      list.push_back(l->l_name);
389
    }
390
  }
391
392
#elif _WIN32
393
  // Windows implementation - get a handle to the process.
394
  HANDLE process_handle = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,
395
                                      FALSE, GetCurrentProcessId());
396
  if (process_handle == nullptr) {
397
    // Cannot proceed, return an empty list.
398
    return list;
399
  }
400
  // Get a list of all the modules in this process
401
  DWORD size_1 = 0;
402
  DWORD size_2 = 0;
403
  // First call to get the size of module array needed
404
  if (EnumProcessModules(process_handle, nullptr, 0, &size_1)) {
405
    MallocedBuffer<HMODULE> modules(size_1);
406
407
    // Second call to populate the module array
408
    if (EnumProcessModules(process_handle, modules.data, size_1, &size_2)) {
409
      for (DWORD i = 0;
410
           i < (size_1 / sizeof(HMODULE)) && i < (size_2 / sizeof(HMODULE));
411
           i++) {
412
        WCHAR module_name[MAX_PATH];
413
        // Obtain and report the full pathname for each module
414
        if (GetModuleFileNameExW(process_handle,
415
                                 modules.data[i],
416
                                 module_name,
417
                                 arraysize(module_name) / sizeof(WCHAR))) {
418
          DWORD size = WideCharToMultiByte(
419
              CP_UTF8, 0, module_name, -1, nullptr, 0, nullptr, nullptr);
420
          char* str = new char[size];
421
          WideCharToMultiByte(
422
              CP_UTF8, 0, module_name, -1, str, size, nullptr, nullptr);
423
          list.push_back(str);
424
        }
425
      }
426
    }
427
  }
428
429
  // Release the handle to the process.
430
  CloseHandle(process_handle);
431
#endif
432
15
  return list;
433
}
434
435
436
}  // namespace node
437
438
extern "C" void __DumpBacktrace(FILE* fp) {
439
  node::DumpBacktrace(fp);
440
}