• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

STEllAR-GROUP / hpx / #852

17 Dec 2022 04:43PM UTC coverage: 85.912% (-0.7%) from 86.568%
#852

push

StellarBot
Merge #6106

6106: Modernizing modules of levels 0 to 5 r=hkaiser a=hkaiser

- flyby: HPX_FORWARD/HPX_MOVE now expand to std::forward and std::move if those are implemented as builtin functions

working towards #5497

Co-authored-by: Hartmut Kaiser <hartmut.kaiser@gmail.com>

87 of 87 new or added lines in 24 files covered. (100.0%)

173152 of 201546 relevant lines covered (85.91%)

1910264.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

73.91
/libs/core/debugging/src/backtrace.cpp
1
//
2
//  Copyright (c) 2011 Bryce Lelbach
3
//  Copyright (c) 2011-2022 Hartmut Kaiser
4
//  Copyright (c) 2010 Artyom Beilis (Tonkikh)
5
//
6
//  SPDX-License-Identifier: BSL-1.0
7
//  Distributed under the Boost Software License, Version 1.0. (See
8
//  accompanying file LICENSE_1_0.txt or copy at
9
//  http://www.boost.org/LICENSE_1_0.txt)
10
//
11

12
#include <hpx/config.hpp>
13

14
#if defined(HPX_HAVE_STACKTRACES)
15

16
#include <hpx/debugging/backtrace/backtrace.hpp>
17

18
#if (defined(__linux) || defined(__APPLE__) || defined(__sun)) &&              \
19
    (!defined(__ANDROID__) || !defined(ANDROID))
20
#if defined(__GLIBC__)
21
#define HPX_HAVE_EXECINFO
22
#endif
23
#define HPX_HAVE_DLFCN
24
#if defined(__GNUC__) && !defined(__clang__)
25
#define HPX_HAVE_UNWIND
26
#endif
27
#endif
28

29
#if defined(__GNUC__) && !defined(__bgq__)
30
#define HPX_HAVE_ABI_CXA_DEMANGLE
31
#endif
32

33
#ifdef HPX_HAVE_EXECINFO
34
#include <execinfo.h>
35
#endif
36

37
#ifdef HPX_HAVE_ABI_CXA_DEMANGLE
38
#include <cxxabi.h>
39
#endif
40

41
#ifdef HPX_HAVE_DLFCN
42
#include <dlfcn.h>
43
#endif
44
#ifdef HPX_HAVE_UNWIND
45
#include <unwind.h>
46
#endif
47

48
#include <cstddef>
49
#include <cstdint>
50
#include <cstdlib>
51
#include <cstring>
52
#include <iomanip>
53
#include <ostream>
54
#include <sstream>
55
#include <string>
56
#include <utility>
57
#include <vector>
58

59
#if defined(HPX_MSVC)
60
#include <windows.h>
61

62
#include <dbghelp.h>
63
#include <stdlib.h>
64
#include <winbase.h>
65
#endif
66

67
namespace hpx::util::stack_trace {
68

69
#if defined(HPX_HAVE_EXECINFO) && defined(HPX_HAVE_UNWIND)
70
    struct trace_data
71
    {
72
        constexpr trace_data(void** array, std::size_t size) noexcept
73
          : array_(array)
74
          , size_(size)
75
          , cfa_(0)
76
          , count_(std::size_t(-1))
77
        {
78
        }
79

80
        void** array_;         // storage for the stack trace
81
        std::size_t size_;     // number of frames
82
        std::uint64_t cfa_;    // canonical frame address
83
        std::size_t count_;
84
    };
85

86
    _Unwind_Reason_Code trace_callback(_Unwind_Context* ctx, void* ptr);
87
    _Unwind_Reason_Code trace_callback(_Unwind_Context* ctx, void* ptr)
88
    {
89
        if (!ptr)
90
            return _URC_NO_REASON;
91

92
        trace_data& d = *(reinterpret_cast<trace_data*>(ptr));
93

94
        // First call.
95
        if (std::size_t(-1) != d.count_)
96
        {
97
            // Get the instruction pointer for this frame.
98
            d.array_[d.count_] = reinterpret_cast<void*>(_Unwind_GetIP(ctx));
99

100
            // Get the CFA.
101
            std::uint64_t cfa = _Unwind_GetCFA(ctx);
102

103
            // Check if we're at the end of the stack.
104
            if ((0 < d.count_) &&
105
                (d.array_[d.count_ - 1] == d.array_[d.count_]) &&
106
                (cfa == d.cfa_))
107
            {
108
                return _URC_END_OF_STACK;
109
            }
110

111
            d.cfa_ = cfa;
112
        }
113

114
        if (++d.count_ == d.size_)
115
            return _URC_END_OF_STACK;
116

117
        return _URC_NO_REASON;
118
    }
119

120
    std::size_t trace(void** array, std::size_t n)
121
    {
122
        trace_data d(array, n);
123

124
        if (1 <= n)
125
            _Unwind_Backtrace(trace_callback, reinterpret_cast<void*>(&d));
126

127
        if ((1 < d.count_) && d.array_[d.count_ - 1])
128
            --d.count_;
129

130
        return (std::size_t(-1) != d.count_) ? d.count_ : 0;
131
    }
132

133
#elif defined(HPX_HAVE_EXECINFO)
134

135
    std::size_t trace(void** array, std::size_t n)
2,531✔
136
    {
137
        return ::backtrace(array, n);
2,531✔
138
    }
139

140
#elif defined(HPX_MSVC)
141

142
    std::size_t trace(void** array, std::size_t n)
143
    {
144
#if _WIN32_WINNT < 0x0600
145
        // for Windows XP/Windows Server 2003
146
        if (n >= 63)
147
            n = 62;
148
#endif
149
        return RtlCaptureStackBackTrace(ULONG(0), ULONG(n), array, nullptr);
150
    }
151

152
#else
153

154
    std::size_t trace(void** /*array*/, std::size_t /*n*/)
155
    {
156
        return 0;
157
    }
158

159
#endif
160

161
#if defined(HPX_HAVE_EXECINFO)
162
    std::string get_symbol_exec_info(void* address)
1,526✔
163
    {
164
        char** ptr = backtrace_symbols(&address, 1);
1,526✔
165
        try
166
        {
167
            if (ptr == nullptr)
1,526✔
168
                return std::string("???");
×
169
            std::string res = ptr[0];
1,526✔
170
            free(ptr);
1,526✔
171
            ptr = nullptr;
1,526✔
172
            return res;
1,526✔
173
        }
1,526✔
174
        catch (...)
175
        {
176
            free(ptr);
×
177
            throw;
×
178
        }
×
179
    }
1,526✔
180
#endif
181

182
#if defined(HPX_HAVE_DLFCN) && defined(HPX_HAVE_ABI_CXA_DEMANGLE)
183
    std::string get_symbol(void* ptr)
50,429✔
184
    {
185
        if (!ptr)
50,429✔
186
            return std::string();
×
187

188
        bool need_offset = true;
50,429✔
189
        std::ostringstream res;
50,429✔
190
        res.imbue(std::locale::classic());
50,429✔
191
        res << std::left << std::setw(sizeof(void*) * 2) << std::setfill(' ')
50,429✔
192
            << ptr << ": ";
50,429✔
193
        Dl_info info = {nullptr, nullptr, nullptr, nullptr};
50,429✔
194
        if (dladdr(ptr, &info) == 0)
50,429✔
195
        {
196
#if !defined(HPX_HAVE_EXECINFO)
197
            res << "???";
198
#else
199
            res << get_symbol_exec_info(ptr);
×
200
            need_offset = false;
×
201
#endif
202
        }
×
203
        else
204
        {
205
            if (info.dli_sname)
50,429✔
206
            {
207
#if defined(HPX_HAVE_STACKTRACES_DEMANGLE_SYMBOLS)
208
                int status = 0;
209
                char* demangled = abi::__cxa_demangle(
210
                    info.dli_sname, nullptr, nullptr, &status);
211
                if (demangled)
212
                {
213
                    res << demangled;
214
                    free(demangled);
215
                }
216
                else
217
                {
218
                    res << info.dli_sname;
219
                }
220
#else
221
                res << info.dli_sname;
48,903✔
222
#endif
223
            }
48,903✔
224
            else
225
            {
226
#if !defined(HPX_HAVE_EXECINFO)
227
                res << "???";
228
#else
229
                res << get_symbol_exec_info(ptr);
1,526✔
230
                need_offset = false;
1,526✔
231
#endif
232
            }
233

234
            std::ptrdiff_t offset = reinterpret_cast<char*>(ptr) -
100,858✔
235
                reinterpret_cast<char*>(info.dli_saddr);
50,429✔
236
            if (need_offset)
50,429✔
237
            {
238
                res << std::hex << " [0x" << offset << "]";
48,903✔
239
            }
48,903✔
240

241
            if (info.dli_fname)
50,429✔
242
            {
243
                res << " in " << info.dli_fname;
50,429✔
244
            }
50,429✔
245
        }
246
        return res.str();
50,429✔
247
    }
50,429✔
248

249
    std::string get_symbols(void* const* addresses, std::size_t size)
2,531✔
250
    {
251
        // the first two stack frames are from the back tracing facility itself
252
        if (size > 2)
2,531✔
253
        {
254
            addresses += 2;
2,531✔
255
            size -= 2;
2,531✔
256
        }
2,531✔
257

258
        std::string res =
2,531✔
259
            std::to_string(size) + ((1 == size) ? " frame:" : " frames:");
2,531✔
260
        for (std::size_t i = 0; i < size; i++)
52,960✔
261
        {
262
            std::string tmp = get_symbol(addresses[i]);
50,429✔
263
            if (!tmp.empty())
50,429✔
264
            {
265
                res += '\n';
50,429✔
266
                res += tmp;
50,429✔
267
            }
50,429✔
268
        }
50,429✔
269
        return res;
2,531✔
270
    }
2,531✔
271

272
    void write_symbols(
×
273
        void* const* addresses, std::size_t size, std::ostream& out)
274
    {
275
        out << size << ((1 == size) ? " frame:" : " frames:");
×
276
        for (std::size_t i = 0; i < size; i++)
×
277
        {
278
            std::string tmp = get_symbol(addresses[i]);
×
279
            if (!tmp.empty())
×
280
            {
281
                out << '\n' << tmp;
×
282
            }
×
283
        }
×
284
        out << std::flush;
×
285
    }
×
286

287
#elif defined(HPX_HAVE_EXECINFO)
288

289
    std::string get_symbol(void* address)
290
    {
291
        return get_symbol_exec_info(address);
292
    }
293

294
    std::string get_symbols(void* const* address, std::size_t size)
295
    {
296
        // the first two stack frames are from the back tracing facility itself
297
        if (size > 2)
298
        {
299
            addresses += 2;
300
            size -= 2;
301
        }
302

303
        char** ptr = backtrace_symbols(address, size);
304
        try
305
        {
306
            if (ptr == nullptr)
307
                return std::string();
308
            std::string res =
309
                std::to_string(size) + ((1 == size) ? " frame:" : " frames:");
310
            for (std::size_t i = 0; i < size; i++)
311
            {
312
                res += '\n';
313
                res += ptr[i];
314
            }
315
            free(ptr);
316
            ptr = nullptr;
317
            return res;
318
        }
319
        catch (...)
320
        {
321
            free(ptr);
322
            throw;
323
        }
324
    }
325

326
    void write_symbols(
327
        void* const* addresses, std::size_t size, std::ostream& out)
328
    {
329
        char** ptr = backtrace_symbols(addresses, size);
330
        out << size << ((1 == size) ? " frame:" : " frames:");
331
        try
332
        {
333
            if (ptr == nullptr)
334
                return;
335
            for (std::size_t i = 0; i < size; i++)
336
                out << '\n' << ptr[i];
337
            free(ptr);
338
            ptr = nullptr;
339
            out << std::flush;
340
        }
341
        catch (...)
342
        {
343
            free(ptr);
344
            throw;
345
        }
346
    }
347

348
#elif defined(HPX_MSVC)
349

350
    namespace {
351

352
        HANDLE hProcess = nullptr;
353
        bool syms_ready = false;
354

355
        void init()
356
        {
357
            if (hProcess == nullptr)
358
            {
359
                hProcess = GetCurrentProcess();
360
                SymSetOptions(SYMOPT_DEFERRED_LOADS);
361

362
                if (SymInitialize(hProcess, nullptr, TRUE))
363
                {
364
                    syms_ready = true;
365
                }
366
            }
367
        }
368
    }    // namespace
369

370
    std::string get_symbol(void* ptr)
371
    {
372
        if (ptr == nullptr)
373
            return std::string();
374
        init();
375
        std::ostringstream ss;
376
        ss << std::left << std::setw(sizeof(void*) * 2) << std::setfill(' ')
377
           << ptr;
378
        if (syms_ready)
379
        {
380
            DWORD64 dwDisplacement = 0;
381
            DWORD64 dwAddress = (DWORD64) ptr;
382

383
            std::vector<char> buffer(sizeof(SYMBOL_INFO) + MAX_SYM_NAME);
384
            PSYMBOL_INFO pSymbol = (PSYMBOL_INFO) &buffer.front();
385

386
            pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
387
            pSymbol->MaxNameLen = MAX_SYM_NAME;
388

389
            if (SymFromAddr(hProcess, dwAddress, &dwDisplacement, pSymbol))
390
            {
391
                ss << ": " << pSymbol->Name << std::hex << " +0x"
392
                   << dwDisplacement;
393
            }
394
            else
395
            {
396
                ss << ": ???";
397
            }
398
        }
399
        return ss.str();
400
    }
401

402
    std::string get_symbols(void* const* addresses, std::size_t size)
403
    {
404
        // the first two stack frames are from the back tracing facility itself
405
        if (size > 2)
406
        {
407
            addresses += 2;
408
            size -= 2;
409
        }
410

411
        std::string res =
412
            std::to_string(size) + ((1 == size) ? " frame:" : " frames:");
413
        for (std::size_t i = 0; i < size; i++)
414
        {
415
            std::string tmp = get_symbol(addresses[i]);
416
            if (!tmp.empty())
417
            {
418
                res += '\n';
419
                res += tmp;
420
            }
421
        }
422
        return res;
423
    }
424

425
    void write_symbols(
426
        void* const* addresses, std::size_t size, std::ostream& out)
427
    {
428
        out << size << ((1 == size) ? " frame:" : " frames:");    //-V128
429
        for (std::size_t i = 0; i < size; i++)
430
        {
431
            std::string tmp = get_symbol(addresses[i]);
432
            if (!tmp.empty())
433
            {
434
                out << '\n' << tmp;
435
            }
436
        }
437
        out << std::flush;
438
    }
439

440
#else
441

442
    std::string get_symbol(void* ptr)
443
    {
444
        if (!ptr)
445
            return std::string();
446
        std::ostringstream res;
447
        res.imbue(std::locale::classic());
448
        res << std::left << std::setw(sizeof(void*) * 2) << std::setfill(' ')
449
            << ptr;
450
        return res.str();
451
    }
452

453
    std::string get_symbols(void* const* ptrs, std::size_t size)
454
    {
455
        if (!ptrs)
456
            return std::string();
457

458
        // the first two stack frames are from the back tracing facility itself
459
        if (size > 2)
460
        {
461
            ptrs += 2;
462
            size -= 2;
463
        }
464

465
        std::ostringstream res;
466
        res.imbue(std::locale::classic());
467
        write_symbols(ptrs, size, res);
468
        return res.str();
469
    }
470

471
    void write_symbols(
472
        void* const* addresses, std::size_t size, std::ostream& out)
473
    {
474
        out << size << ((1 == size) ? " frame:" : " frames:");    //-V128
475
        for (std::size_t i = 0; i < size; i++)
476
        {
477
            if (addresses[i] != nullptr)
478
                out << '\n'
479
                    << std::left << std::setw(sizeof(void*) * 2)
480
                    << std::setfill(' ') << addresses[i];
481
        }
482
        out << std::flush;
483
    }
484

485
#endif
486
}    // namespace hpx::util::stack_trace
487

488
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc