D-Bus 1.16.2
dbus-backtrace-win.c
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2/* dbus-backtrace-win.c Backtrace Generator
3 *
4 * Copyright 2004 Eric Poech
5 * Copyright 2004 Robert Shearman
6 * Copyright 2010 Patrick von Reth <patrick.vonreth@gmail.com>
7 * Copyright 2015 Ralf Habacker <ralf.habacker@freenet.de>
8 *
9 * SPDX-License-Identifier: LGPL-2.1-or-later
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 */
25
26#include <config.h>
27
28#include "dbus-internals.h"
29#include "dbus-sysdeps.h"
30
31#if !defined (DBUS_DISABLE_ASSERT) || defined(DBUS_ENABLE_EMBEDDED_TESTS)
32
33#if defined(_MSC_VER) || defined(DBUS_WINCE)
34# ifdef BACKTRACES
35# undef BACKTRACES
36# endif
37#else
38# define BACKTRACES
39#endif
40
41#ifdef BACKTRACES
42#include "dbus-sysdeps-win.h"
43
44#include <stdio.h>
45#include <windows.h>
46#include <imagehlp.h>
47
48#define DPRINTF(fmt, ...) fprintf (stderr, fmt, ##__VA_ARGS__)
49
50#ifdef _MSC_VER
51#define BOOL int
52
53#define __i386__
54#endif
55
56static void dump_backtrace_for_thread (HANDLE hThread)
57{
58 ADDRESS old_address;
59 STACKFRAME sf;
60 CONTEXT context;
61 DWORD dwImageType;
62 int i = 0;
63
64 SymSetOptions (SYMOPT_UNDNAME | SYMOPT_LOAD_LINES);
65 SymInitialize (GetCurrentProcess (), NULL, TRUE);
66
67
68 /* can't use this function for current thread as GetThreadContext
69 * doesn't support getting context from current thread */
70 if (hThread == GetCurrentThread())
71 return;
72
73 DPRINTF ("Backtrace:\n");
74
75 _DBUS_ZERO (old_address);
76 _DBUS_ZERO (context);
77 context.ContextFlags = CONTEXT_FULL;
78
79 SuspendThread (hThread);
80
81 if (!GetThreadContext (hThread, &context))
82 {
83 DPRINTF ("Couldn't get thread context (error %ld)\n", GetLastError ());
84 ResumeThread (hThread);
85 return;
86 }
87
88 _DBUS_ZERO (sf);
89
90#ifdef __i386__
91 dwImageType = IMAGE_FILE_MACHINE_I386;
92 sf.AddrFrame.Offset = context.Ebp;
93 sf.AddrFrame.Mode = AddrModeFlat;
94 sf.AddrPC.Offset = context.Eip;
95 sf.AddrPC.Mode = AddrModeFlat;
96#elif defined(_M_X64)
97 dwImageType = IMAGE_FILE_MACHINE_AMD64;
98 sf.AddrPC.Offset = context.Rip;
99 sf.AddrPC.Mode = AddrModeFlat;
100 sf.AddrFrame.Offset = context.Rsp;
101 sf.AddrFrame.Mode = AddrModeFlat;
102 sf.AddrStack.Offset = context.Rsp;
103 sf.AddrStack.Mode = AddrModeFlat;
104#elif defined(_M_IA64)
105 dwImageType = IMAGE_FILE_MACHINE_IA64;
106 sf.AddrPC.Offset = context.StIIP;
107 sf.AddrPC.Mode = AddrModeFlat;
108 sf.AddrFrame.Offset = context.IntSp;
109 sf.AddrFrame.Mode = AddrModeFlat;
110 sf.AddrBStore.Offset= context.RsBSP;
111 sf.AddrBStore.Mode = AddrModeFlat;
112 sf.AddrStack.Offset = context.IntSp;
113 sf.AddrStack.Mode = AddrModeFlat;
114#elif defined(_M_ARM64)
115 dwImageType = IMAGE_FILE_MACHINE_ARM64;
116 sf.AddrPC.Offset = context.Pc;
117 sf.AddrPC.Mode = AddrModeFlat;
118 sf.AddrFrame.Offset = context.Fp;
119 sf.AddrFrame.Mode = AddrModeFlat;
120 sf.AddrStack.Offset = context.Sp;
121 sf.AddrStack.Mode = AddrModeFlat;
122#else
123# error You need to fill in the STACKFRAME structure for your architecture
124#endif
125
126 /*
127 backtrace format
128 <level> <address> <symbol>[+offset] [ '[' <file> ':' <line> ']' ] [ 'in' <module> ]
129 example:
130 6 0xf75ade6b wine_switch_to_stack+0x2a [/usr/src/debug/wine-snapshot/libs/wine/port.c:59] in libwine.so.1
131 */
132 while (StackWalk (dwImageType, GetCurrentProcess (),
133 hThread, &sf, &context, NULL, SymFunctionTableAccess,
134 SymGetModuleBase, NULL))
135 {
136 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(char)];
137 PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
138 DWORD64 displacement;
139 IMAGEHLP_LINE line;
140 DWORD dwDisplacement;
141 IMAGEHLP_MODULE moduleInfo;
142
143 /*
144 on Wine64 version 1.7.54, we get an infinite number of stack entries
145 pointing to the same stack frame (_start+0x29 in <wine-loader>)
146 see bug https://bugs.winehq.org/show_bug.cgi?id=39606
147 */
148#ifndef __i386__
149 if (old_address.Offset == sf.AddrPC.Offset)
150 {
151 break;
152 }
153#endif
154
155 pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
156 pSymbol->MaxNameLen = MAX_SYM_NAME;
157
158 if (SymFromAddr (GetCurrentProcess (), sf.AddrPC.Offset, &displacement, pSymbol))
159 {
160 if (displacement)
161 DPRINTF ("%3d %s+0x%I64x", i++, pSymbol->Name, displacement);
162 else
163 DPRINTF ("%3d %s", i++, pSymbol->Name);
164 }
165 else
166 DPRINTF ("%3d 0x%Ix", i++, sf.AddrPC.Offset);
167
168 line.SizeOfStruct = sizeof(IMAGEHLP_LINE);
169 if (SymGetLineFromAddr (GetCurrentProcess (), sf.AddrPC.Offset, &dwDisplacement, &line))
170 {
171 DPRINTF (" [%s:%ld]", line.FileName, line.LineNumber);
172 }
173
174 moduleInfo.SizeOfStruct = sizeof(moduleInfo);
175 if (SymGetModuleInfo (GetCurrentProcess (), sf.AddrPC.Offset, &moduleInfo))
176 {
177 DPRINTF (" in %s", moduleInfo.ModuleName);
178 }
179 DPRINTF ("\n");
180 old_address = sf.AddrPC;
181 }
182 ResumeThread (hThread);
183}
184
185static DWORD WINAPI dump_thread_proc (LPVOID lpParameter)
186{
187 dump_backtrace_for_thread ((HANDLE) lpParameter);
188 return 0;
189}
190
191/* cannot get valid context from current thread, so we have to execute
192 * backtrace from another thread */
193static void
194dump_backtrace (void)
195{
196 HANDLE hCurrentThread;
197 HANDLE hThread;
198 DWORD dwThreadId;
199 DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
200 GetCurrentProcess (), &hCurrentThread,
201 0, FALSE, DUPLICATE_SAME_ACCESS);
202 hThread = CreateThread (NULL, 0, dump_thread_proc, (LPVOID)hCurrentThread,
203 0, &dwThreadId);
204 WaitForSingleObject (hThread, INFINITE);
205 CloseHandle (hThread);
206 CloseHandle (hCurrentThread);
207}
208#endif
209#endif /* asserts or tests enabled */
210
211#ifdef BACKTRACES
213{
214 dump_backtrace ();
215}
216#else
217void _dbus_print_backtrace (void)
218{
219 _dbus_verbose (" D-Bus not compiled with backtrace support\n");
220}
221#endif
#define _DBUS_ZERO(object)
Sets all bits in an object to zero.
#define NULL
A null pointer, defined appropriately for C or C++.
Definition dbus-macros.h:51
#define TRUE
Expands to "1".
Definition dbus-macros.h:41
#define FALSE
Expands to "0".
Definition dbus-macros.h:44
void _dbus_print_backtrace(void)
On GNU libc systems, print a crude backtrace to stderr.