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: 54 92 58.7 %
Date: 2020-02-19 22:14:06 Branches: 15 30 50.0 %

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

1779
  if (file != stderr && file != stdout) {
449
    simple_fwrite();
450
    return;
451
  }
452
#ifdef _WIN32
453
  HANDLE handle =
454
      GetStdHandle(file == stdout ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
455
456
  // Check if stderr is something other than a tty/console
457
  if (handle == INVALID_HANDLE_VALUE || handle == nullptr ||
458
      uv_guess_handle(_fileno(file)) != UV_TTY) {
459
    simple_fwrite();
460
    return;
461
  }
462
463
  // Get required wide buffer size
464
  int n = MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), nullptr, 0);
465
466
  std::vector<wchar_t> wbuf(n);
467
  MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), wbuf.data(), n);
468
469
  WriteConsoleW(handle, wbuf.data(), n, nullptr, nullptr);
470
  return;
471
#elif defined(__ANDROID__)
472
  if (file == stderr) {
473
    __android_log_print(ANDROID_LOG_ERROR, "nodejs", "%s", str.data());
474
    return;
475
  }
476
#endif
477
1779
  simple_fwrite();
478
}
479
480
}  // namespace node
481
482
extern "C" void __DumpBacktrace(FILE* fp) {
483
  node::DumpBacktrace(fp);
484
}