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