FreeRDP
windows/debug.c
1 
21 #include <stdio.h>
22 #include <fcntl.h>
23 
24 #include <io.h>
25 #include <windows.h>
26 #include <dbghelp.h>
27 
28 #include "debug.h"
29 
30 #ifndef MIN
31 #define MIN(a, b) (a) < (b) ? (a) : (b)
32 #endif
33 
34 typedef struct
35 {
36  PVOID* stack;
37  ULONG used;
38  ULONG max;
39 } t_win_stack;
40 
41 void winpr_win_backtrace_free(void* buffer)
42 {
43  t_win_stack* data = (t_win_stack*)buffer;
44  if (!data)
45  return;
46 
47  free(data->stack);
48  free(data);
49 }
50 
51 void* winpr_win_backtrace(DWORD size)
52 {
53  HANDLE process = GetCurrentProcess();
54  t_win_stack* data = calloc(1, sizeof(t_win_stack));
55 
56  if (!data)
57  return NULL;
58 
59  data->max = size;
60  data->stack = calloc(data->max, sizeof(PVOID));
61 
62  if (!data->stack)
63  {
64  free(data);
65  return NULL;
66  }
67 
68  SymInitialize(process, NULL, TRUE);
69  data->used = RtlCaptureStackBackTrace(2, size, data->stack, NULL);
70  return data;
71 }
72 
73 char** winpr_win_backtrace_symbols(void* buffer, size_t* used)
74 {
75  if (used)
76  *used = 0;
77 
78  if (!buffer)
79  return NULL;
80 
81  {
82  size_t line_len = 1024;
83  HANDLE process = GetCurrentProcess();
84  t_win_stack* data = (t_win_stack*)buffer;
85  size_t array_size = data->used * sizeof(char*);
86  size_t lines_size = data->used * line_len;
87  char** vlines = calloc(1, array_size + lines_size);
88  SYMBOL_INFO* symbol = calloc(1, sizeof(SYMBOL_INFO) + line_len * sizeof(char));
89  IMAGEHLP_LINE64* line = (IMAGEHLP_LINE64*)calloc(1, sizeof(IMAGEHLP_LINE64));
90 
91  if (!vlines || !symbol || !line)
92  {
93  free(vlines);
94  free(symbol);
95  free(line);
96  return NULL;
97  }
98 
99  line->SizeOfStruct = sizeof(IMAGEHLP_LINE64);
100  symbol->MaxNameLen = (ULONG)line_len;
101  symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
102 
103  /* Set the pointers in the allocated buffer's initial array section */
104  for (size_t i = 0; i < data->used; i++)
105  vlines[i] = (char*)vlines + array_size + i * line_len;
106 
107  for (size_t i = 0; i < data->used; i++)
108  {
109  DWORD64 address = (DWORD64)(data->stack[i]);
110  DWORD displacement;
111  SymFromAddr(process, address, 0, symbol);
112 
113  if (SymGetLineFromAddr64(process, address, &displacement, line))
114  {
115  sprintf_s(vlines[i], line_len, "%016" PRIx64 ": %s in %s:%" PRIu32, symbol->Address,
116  symbol->Name, line->FileName, line->LineNumber);
117  }
118  else
119  sprintf_s(vlines[i], line_len, "%016" PRIx64 ": %s", symbol->Address, symbol->Name);
120  }
121 
122  if (used)
123  *used = data->used;
124 
125  free(symbol);
126  free(line);
127  return vlines;
128  }
129 }
130 
131 char* winpr_win_strerror(DWORD dw, char* dmsg, size_t size)
132 {
133  DWORD rc;
134  DWORD nSize = 0;
135  DWORD dwFlags = 0;
136  LPTSTR msg = NULL;
137  BOOL alloc = FALSE;
138  dwFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
139 #ifdef FORMAT_MESSAGE_ALLOCATE_BUFFER
140  alloc = TRUE;
141  dwFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER;
142 #else
143  nSize = (DWORD)(size * sizeof(WCHAR));
144  msg = (LPTSTR)calloc(nSize, sizeof(WCHAR));
145 #endif
146  rc = FormatMessage(dwFlags, NULL, dw, 0, alloc ? (LPTSTR)&msg : msg, nSize, NULL);
147 
148  if (rc)
149  {
150 #if defined(UNICODE)
151  WideCharToMultiByte(CP_ACP, 0, msg, rc, dmsg, (int)MIN(size - 1, INT_MAX), NULL, NULL);
152 #else /* defined(UNICODE) */
153  memcpy(dmsg, msg, MIN(rc, size - 1));
154 #endif /* defined(UNICODE) */
155  dmsg[MIN(rc, size - 1)] = 0;
156 #ifdef FORMAT_MESSAGE_ALLOCATE_BUFFER
157  LocalFree(msg);
158 #else
159  free(msg);
160 #endif
161  }
162  else
163  {
164  _snprintf(dmsg, size, "FAILURE: 0x%08" PRIX32 "", GetLastError());
165  }
166 
167  return dmsg;
168 }