29 #include <winpr/string.h>
32 #include <winpr/wlog.h>
37 #define TAG WINPR_TAG("utils.unwind")
39 #define UNWIND_MAX_LINE_SIZE 1024ULL
62 static const char* unwind_reason_str(_Unwind_Reason_Code code)
66 #if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__ARM_DWARF_EH__) && \
72 return "_URC_NO_REASON";
73 case _URC_FATAL_PHASE2_ERROR:
74 return "_URC_FATAL_PHASE2_ERROR";
75 case _URC_FATAL_PHASE1_ERROR:
76 return "_URC_FATAL_PHASE1_ERROR";
77 case _URC_NORMAL_STOP:
78 return "_URC_NORMAL_STOP";
80 case _URC_FOREIGN_EXCEPTION_CAUGHT:
81 return "_URC_FOREIGN_EXCEPTION_CAUGHT";
82 case _URC_END_OF_STACK:
83 return "_URC_END_OF_STACK";
84 case _URC_HANDLER_FOUND:
85 return "_URC_HANDLER_FOUND";
86 case _URC_INSTALL_CONTEXT:
87 return "_URC_INSTALL_CONTEXT";
88 case _URC_CONTINUE_UNWIND:
89 return "_URC_CONTINUE_UNWIND";
90 #if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__ARM_DWARF_EH__) && \
93 return "_URC_FAILURE";
96 return "_URC_UNKNOWN";
100 static const char* unwind_reason_str_buffer(_Unwind_Reason_Code code,
char* buffer,
size_t size)
102 const char* str = unwind_reason_str(code);
103 (void)_snprintf(buffer, size,
"%s [0x%02x]", str, code);
107 static _Unwind_Reason_Code unwind_backtrace_callback(
struct _Unwind_Context* context,
void* arg)
109 unwind_context_t* ctx = arg;
113 if (ctx->pos < ctx->size)
115 unwind_info_t* info = &ctx->info[ctx->pos++];
116 info->pc.uw = _Unwind_GetIP(context);
122 info->langSpecificData.pv = (
void*)_Unwind_GetLanguageSpecificData(context);
125 return _URC_NO_REASON;
128 void* winpr_unwind_backtrace(DWORD size)
130 _Unwind_Reason_Code rc = _URC_FOREIGN_EXCEPTION_CAUGHT;
131 unwind_context_t* ctx = calloc(1,
sizeof(unwind_context_t));
135 ctx->info = calloc(size,
sizeof(unwind_info_t));
139 rc = _Unwind_Backtrace(unwind_backtrace_callback, ctx);
140 if (rc != _URC_END_OF_STACK)
142 char buffer[64] = { 0 };
143 WLog_ERR(TAG,
"_Unwind_Backtrace failed with %s",
144 unwind_reason_str_buffer(rc, buffer,
sizeof(buffer)));
150 winpr_unwind_backtrace_free(ctx);
154 void winpr_unwind_backtrace_free(
void* buffer)
156 unwind_context_t* ctx = buffer;
163 char** winpr_unwind_backtrace_symbols(
void* buffer,
size_t* used)
170 unwind_context_t* ctx = buffer;
176 cnv.cpp = calloc(ctx->pos * (
sizeof(
char*) + UNWIND_MAX_LINE_SIZE),
sizeof(
char*));
183 for (
size_t x = 0; x < ctx->pos; x++)
185 char* msg = cnv.cp + ctx->pos *
sizeof(
char*) + x * UNWIND_MAX_LINE_SIZE;
186 const unwind_info_t* info = &ctx->info[x];
187 Dl_info dlinfo = { 0 };
188 int rc = dladdr(info->pc.pv, &dlinfo);
193 (void)_snprintf(msg, UNWIND_MAX_LINE_SIZE,
"unresolvable, address=%p", info->pc.pv);
195 (
void)_snprintf(msg, UNWIND_MAX_LINE_SIZE,
"dli_fname=%s [%p], dli_sname=%s [%p]",
196 dlinfo.dli_fname, dlinfo.dli_fbase, dlinfo.dli_sname, dlinfo.dli_saddr);