The open source OpenXR runtime
1#ifndef __TRACYCALLSTACK_HPP__
2#define __TRACYCALLSTACK_HPP__
3
4#include "../common/TracyApi.h"
5#include "../common/TracyForceInline.hpp"
6#include "TracyCallstack.h"
7
8#if TRACY_HAS_CALLSTACK == 2 || TRACY_HAS_CALLSTACK == 5
9# include <unwind.h>
10#elif TRACY_HAS_CALLSTACK >= 3
11# include <execinfo.h>
12#endif
13
14
15#ifndef TRACY_HAS_CALLSTACK
16
17namespace tracy
18{
19static tracy_force_inline void* Callstack( int depth ) { return nullptr; }
20}
21
22#else
23
24#ifdef TRACY_DEBUGINFOD
25# include <elfutils/debuginfod.h>
26#endif
27
28#include <assert.h>
29#include <stdint.h>
30
31#include "../common/TracyAlloc.hpp"
32
33namespace tracy
34{
35
36struct CallstackSymbolData
37{
38 const char* file;
39 uint32_t line;
40 bool needFree;
41 uint64_t symAddr;
42};
43
44struct CallstackEntry
45{
46 const char* name;
47 const char* file;
48 uint32_t line;
49 uint32_t symLen;
50 uint64_t symAddr;
51};
52
53struct CallstackEntryData
54{
55 const CallstackEntry* data;
56 uint8_t size;
57 const char* imageName;
58};
59
60CallstackSymbolData DecodeSymbolAddress( uint64_t ptr );
61const char* DecodeCallstackPtrFast( uint64_t ptr );
62CallstackEntryData DecodeCallstackPtr( uint64_t ptr );
63void InitCallstack();
64void InitCallstackCritical();
65void EndCallstack();
66const char* GetKernelModulePath( uint64_t addr );
67
68#ifdef TRACY_DEBUGINFOD
69const uint8_t* GetBuildIdForImage( const char* image, size_t& size );
70debuginfod_client* GetDebuginfodClient();
71#endif
72
73#if TRACY_HAS_CALLSTACK == 1
74
75extern "C"
76{
77 typedef unsigned long (__stdcall *___tracy_t_RtlWalkFrameChain)( void**, unsigned long, unsigned long );
78 TRACY_API extern ___tracy_t_RtlWalkFrameChain ___tracy_RtlWalkFrameChain;
79}
80
81static tracy_force_inline void* Callstack( int depth )
82{
83 assert( depth >= 1 && depth < 63 );
84 auto trace = (uintptr_t*)tracy_malloc( ( 1 + depth ) * sizeof( uintptr_t ) );
85 const auto num = ___tracy_RtlWalkFrameChain( (void**)( trace + 1 ), depth, 0 );
86 *trace = num;
87 return trace;
88}
89
90#elif TRACY_HAS_CALLSTACK == 2 || TRACY_HAS_CALLSTACK == 5
91
92struct BacktraceState
93{
94 void** current;
95 void** end;
96};
97
98static _Unwind_Reason_Code tracy_unwind_callback( struct _Unwind_Context* ctx, void* arg )
99{
100 auto state = (BacktraceState*)arg;
101 uintptr_t pc = _Unwind_GetIP( ctx );
102 if( pc )
103 {
104 if( state->current == state->end ) return _URC_END_OF_STACK;
105 *state->current++ = (void*)pc;
106 }
107 return _URC_NO_REASON;
108}
109
110static tracy_force_inline void* Callstack( int depth )
111{
112 assert( depth >= 1 && depth < 63 );
113
114 auto trace = (uintptr_t*)tracy_malloc( ( 1 + depth ) * sizeof( uintptr_t ) );
115 BacktraceState state = { (void**)(trace+1), (void**)(trace+1+depth) };
116 _Unwind_Backtrace( tracy_unwind_callback, &state );
117
118 *trace = (uintptr_t*)state.current - trace + 1;
119
120 return trace;
121}
122
123#elif TRACY_HAS_CALLSTACK == 3 || TRACY_HAS_CALLSTACK == 4 || TRACY_HAS_CALLSTACK == 6
124
125static tracy_force_inline void* Callstack( int depth )
126{
127 assert( depth >= 1 );
128
129 auto trace = (uintptr_t*)tracy_malloc( ( 1 + (size_t)depth ) * sizeof( uintptr_t ) );
130 const auto num = (size_t)backtrace( (void**)(trace+1), depth );
131 *trace = num;
132
133 return trace;
134}
135
136#endif
137
138}
139
140#endif
141
142#endif