Coverage Report

Created: 2024-05-20 06:11

/src/FreeRDP/winpr/libwinpr/utils/unwind/debug.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * WinPR Debugging helpers
4
 *
5
 * Copyright 2022 Armin Novak <armin.novak@thincast.com>
6
 * Copyright 2022 Thincast Technologies GmbH
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20
21
#ifndef _GNU_SOURCE
22
#define _GNU_SOURCE
23
#endif
24
25
#include <assert.h>
26
#include <stdlib.h>
27
#include <unwind.h>
28
29
#include <winpr/string.h>
30
#include "debug.h"
31
32
#include <dlfcn.h>
33
34
typedef struct
35
{
36
  uintptr_t pc;
37
  void* langSpecificData;
38
} unwind_info_t;
39
40
typedef struct
41
{
42
  size_t pos;
43
  size_t size;
44
  unwind_info_t* info;
45
} unwind_context_t;
46
47
static _Unwind_Reason_Code unwind_backtrace_callback(struct _Unwind_Context* context, void* arg)
48
2.14M
{
49
2.14M
  unwind_context_t* ctx = arg;
50
51
2.14M
  assert(ctx);
52
53
2.14M
  if (ctx->pos < ctx->size)
54
2.14M
  {
55
2.14M
    unwind_info_t* info = &ctx->info[ctx->pos++];
56
2.14M
    info->pc = _Unwind_GetIP(context);
57
2.14M
    info->langSpecificData = (void*)_Unwind_GetLanguageSpecificData(context);
58
2.14M
  }
59
60
2.14M
  return _URC_NO_REASON;
61
2.14M
}
62
63
void* winpr_unwind_backtrace(DWORD size)
64
157k
{
65
157k
  _Unwind_Reason_Code rc = _URC_FOREIGN_EXCEPTION_CAUGHT;
66
157k
  unwind_context_t* ctx = calloc(1, sizeof(unwind_context_t));
67
157k
  if (!ctx)
68
0
    goto fail;
69
157k
  ctx->size = size;
70
157k
  ctx->info = calloc(size, sizeof(unwind_info_t));
71
157k
  if (!ctx->info)
72
0
    goto fail;
73
74
157k
  rc = _Unwind_Backtrace(unwind_backtrace_callback, ctx);
75
157k
  if (rc != _URC_END_OF_STACK)
76
0
    goto fail;
77
78
157k
  return ctx;
79
0
fail:
80
0
  winpr_unwind_backtrace_free(ctx);
81
0
  return NULL;
82
157k
}
83
84
void winpr_unwind_backtrace_free(void* buffer)
85
157k
{
86
157k
  unwind_context_t* ctx = buffer;
87
157k
  if (!ctx)
88
0
    return;
89
157k
  free(ctx->info);
90
157k
  free(ctx);
91
157k
}
92
93
4.44M
#define UNWIND_MAX_LINE_SIZE 1024
94
95
char** winpr_unwind_backtrace_symbols(void* buffer, size_t* used)
96
157k
{
97
157k
  union
98
157k
  {
99
157k
    char* cp;
100
157k
    char** cpp;
101
157k
  } cnv;
102
157k
  unwind_context_t* ctx = buffer;
103
157k
  cnv.cpp = NULL;
104
105
157k
  if (!ctx)
106
0
    return NULL;
107
108
157k
  cnv.cpp = calloc(ctx->pos * (sizeof(char*) + UNWIND_MAX_LINE_SIZE), sizeof(char*));
109
157k
  if (!cnv.cpp)
110
0
    return NULL;
111
112
157k
  if (used)
113
157k
    *used = ctx->pos;
114
115
2.30M
  for (size_t x = 0; x < ctx->pos; x++)
116
2.14M
  {
117
2.14M
    char* msg = cnv.cp + ctx->pos * sizeof(char*) + x * UNWIND_MAX_LINE_SIZE;
118
2.14M
    const unwind_info_t* info = &ctx->info[x];
119
2.14M
    Dl_info dlinfo = { 0 };
120
2.14M
    int rc = dladdr((void*)info->pc, &dlinfo);
121
122
2.14M
    cnv.cpp[x] = msg;
123
124
2.14M
    if (rc == 0)
125
157k
      _snprintf(msg, UNWIND_MAX_LINE_SIZE, "unresolvable, address=%p", (void*)info->pc);
126
1.98M
    else
127
1.98M
      _snprintf(msg, UNWIND_MAX_LINE_SIZE, "dli_fname=%s [%p], dli_sname=%s [%p]",
128
1.98M
                dlinfo.dli_fname, dlinfo.dli_fbase, dlinfo.dli_sname, dlinfo.dli_saddr);
129
2.14M
  }
130
131
157k
  return cnv.cpp;
132
157k
}