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-05-05 22:32:45 Branches: 15 26 57.7 %

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