4 * Copyright 1995 Alexandre Julliard
5 * Copyright 1996 Eric Youngdale
6 * Copyright 1999 Ove Kåven
7 * Copyright 2004 Eric Pouech
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "dbghelp_private.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp
);
34 static DWORD64 WINAPI
addr_to_linear(HANDLE hProcess
, HANDLE hThread
, ADDRESS64
* addr
)
41 if (GetThreadSelectorEntry(hThread
, addr
->Segment
, &le
))
42 return (le
.HighWord
.Bits
.BaseHi
<< 24) +
43 (le
.HighWord
.Bits
.BaseMid
<< 16) + le
.BaseLow
+ LOWORD(addr
->Offset
);
46 if (GetThreadSelectorEntry(hThread
, addr
->Segment
, &le
))
47 return (le
.HighWord
.Bits
.BaseHi
<< 24) +
48 (le
.HighWord
.Bits
.BaseMid
<< 16) + le
.BaseLow
+ addr
->Offset
;
51 return (DWORD
)(LOWORD(addr
->Segment
) << 4) + addr
->Offset
;
55 FIXME("Unsupported (yet) mode (%x)\n", addr
->Mode
);
58 FIXME("Failed to linearize address %04x:%I64x (mode %x)\n",
59 addr
->Segment
, addr
->Offset
, addr
->Mode
);
63 static BOOL CALLBACK
read_mem(HANDLE hProcess
, DWORD addr
, void* buffer
,
64 DWORD size
, LPDWORD nread
)
67 if (!ReadProcessMemory(hProcess
, (void*)(DWORD_PTR
)addr
, buffer
, size
, &r
)) return FALSE
;
68 if (nread
) *nread
= r
;
72 static BOOL CALLBACK
read_mem64(HANDLE hProcess
, DWORD64 addr
, void* buffer
,
73 DWORD size
, LPDWORD nread
)
76 if (!ReadProcessMemory(hProcess
, (void*)(DWORD_PTR
)addr
, buffer
, size
, &r
)) return FALSE
;
77 if (nread
) *nread
= r
;
81 static inline void addr_32to64(const ADDRESS
* addr32
, ADDRESS64
* addr64
)
83 addr64
->Offset
= (ULONG64
)addr32
->Offset
;
84 addr64
->Segment
= addr32
->Segment
;
85 addr64
->Mode
= addr32
->Mode
;
88 static inline void addr_64to32(const ADDRESS64
* addr64
, ADDRESS
* addr32
)
90 addr32
->Offset
= (ULONG
)addr64
->Offset
;
91 addr32
->Segment
= addr64
->Segment
;
92 addr32
->Mode
= addr64
->Mode
;
95 BOOL
sw_read_mem(struct cpu_stack_walk
* csw
, DWORD64 addr
, void* ptr
, DWORD sz
)
99 return csw
->u
.s32
.f_read_mem(csw
->hProcess
, addr
, ptr
, sz
, &bytes_read
);
101 return csw
->u
.s64
.f_read_mem(csw
->hProcess
, addr
, ptr
, sz
, &bytes_read
);
104 DWORD64
sw_xlat_addr(struct cpu_stack_walk
* csw
, ADDRESS64
* addr
)
106 if (addr
->Mode
== AddrModeFlat
) return addr
->Offset
;
111 addr_64to32(addr
, &addr32
);
112 return csw
->u
.s32
.f_xlat_adr(csw
->hProcess
, csw
->hThread
, &addr32
);
114 else if (csw
->u
.s64
.f_xlat_adr
)
115 return csw
->u
.s64
.f_xlat_adr(csw
->hProcess
, csw
->hThread
, addr
);
116 return addr_to_linear(csw
->hProcess
, csw
->hThread
, addr
);
119 void* sw_table_access(struct cpu_stack_walk
* csw
, DWORD64 addr
)
122 return csw
->u
.s32
.f_tabl_acs(csw
->hProcess
, addr
);
124 return csw
->u
.s64
.f_tabl_acs(csw
->hProcess
, addr
);
127 DWORD64
sw_module_base(struct cpu_stack_walk
* csw
, DWORD64 addr
)
130 return csw
->u
.s32
.f_modl_bas(csw
->hProcess
, addr
);
132 return csw
->u
.s64
.f_modl_bas(csw
->hProcess
, addr
);
135 /***********************************************************************
136 * StackWalk (DBGHELP.@)
138 BOOL WINAPI
StackWalk(DWORD MachineType
, HANDLE hProcess
, HANDLE hThread
,
139 LPSTACKFRAME frame32
, PVOID ctx
,
140 PREAD_PROCESS_MEMORY_ROUTINE f_read_mem
,
141 PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine
,
142 PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine
,
143 PTRANSLATE_ADDRESS_ROUTINE f_xlat_adr
)
145 struct cpu_stack_walk csw
;
146 STACKFRAME64 frame64
;
150 TRACE("(%ld, %p, %p, %p, %p, %p, %p, %p, %p)\n",
151 MachineType
, hProcess
, hThread
, frame32
, ctx
,
152 f_read_mem
, FunctionTableAccessRoutine
,
153 GetModuleBaseRoutine
, f_xlat_adr
);
155 if (!(cpu
= cpu_find(MachineType
)))
157 SetLastError(ERROR_INVALID_PARAMETER
);
161 addr_32to64(&frame32
->AddrPC
, &frame64
.AddrPC
);
162 addr_32to64(&frame32
->AddrReturn
, &frame64
.AddrReturn
);
163 addr_32to64(&frame32
->AddrFrame
, &frame64
.AddrFrame
);
164 addr_32to64(&frame32
->AddrStack
, &frame64
.AddrStack
);
165 addr_32to64(&frame32
->AddrBStore
, &frame64
.AddrBStore
);
166 frame64
.FuncTableEntry
= frame32
->FuncTableEntry
; /* FIXME */
167 frame64
.Far
= frame32
->Far
;
168 frame64
.Virtual
= frame32
->Virtual
;
169 frame64
.Reserved
[0] = frame32
->Reserved
[0];
170 frame64
.Reserved
[1] = frame32
->Reserved
[1];
171 frame64
.Reserved
[2] = frame32
->Reserved
[2];
172 /* we don't handle KdHelp */
174 csw
.hProcess
= hProcess
;
175 csw
.hThread
= hThread
;
178 /* sigh... MS isn't even consistent in the func prototypes */
179 csw
.u
.s32
.f_read_mem
= (f_read_mem
) ? f_read_mem
: read_mem
;
180 csw
.u
.s32
.f_xlat_adr
= f_xlat_adr
;
181 csw
.u
.s32
.f_tabl_acs
= (FunctionTableAccessRoutine
) ? FunctionTableAccessRoutine
: SymFunctionTableAccess
;
182 csw
.u
.s32
.f_modl_bas
= (GetModuleBaseRoutine
) ? GetModuleBaseRoutine
: SymGetModuleBase
;
184 if ((ret
= cpu
->stack_walk(&csw
, &frame64
, ctx
)))
186 addr_64to32(&frame64
.AddrPC
, &frame32
->AddrPC
);
187 addr_64to32(&frame64
.AddrReturn
, &frame32
->AddrReturn
);
188 addr_64to32(&frame64
.AddrFrame
, &frame32
->AddrFrame
);
189 addr_64to32(&frame64
.AddrStack
, &frame32
->AddrStack
);
190 addr_64to32(&frame64
.AddrBStore
, &frame32
->AddrBStore
);
191 frame32
->FuncTableEntry
= frame64
.FuncTableEntry
; /* FIXME */
192 frame32
->Params
[0] = frame64
.Params
[0];
193 frame32
->Params
[1] = frame64
.Params
[1];
194 frame32
->Params
[2] = frame64
.Params
[2];
195 frame32
->Params
[3] = frame64
.Params
[3];
196 frame32
->Far
= frame64
.Far
;
197 frame32
->Virtual
= frame64
.Virtual
;
198 frame32
->Reserved
[0] = frame64
.Reserved
[0];
199 frame32
->Reserved
[1] = frame64
.Reserved
[1];
200 frame32
->Reserved
[2] = frame64
.Reserved
[2];
207 /***********************************************************************
208 * StackWalk64 (DBGHELP.@)
210 BOOL WINAPI
StackWalk64(DWORD MachineType
, HANDLE hProcess
, HANDLE hThread
,
211 LPSTACKFRAME64 frame
, PVOID ctx
,
212 PREAD_PROCESS_MEMORY_ROUTINE64 f_read_mem
,
213 PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine
,
214 PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine
,
215 PTRANSLATE_ADDRESS_ROUTINE64 f_xlat_adr
)
217 struct cpu_stack_walk csw
;
220 TRACE("(%ld, %p, %p, %p, %p, %p, %p, %p, %p)\n",
221 MachineType
, hProcess
, hThread
, frame
, ctx
,
222 f_read_mem
, FunctionTableAccessRoutine
,
223 GetModuleBaseRoutine
, f_xlat_adr
);
225 if (!(cpu
= cpu_find(MachineType
)))
227 SetLastError(ERROR_INVALID_PARAMETER
);
231 csw
.hProcess
= hProcess
;
232 csw
.hThread
= hThread
;
235 /* sigh... MS isn't even consistent in the func prototypes */
236 csw
.u
.s64
.f_read_mem
= (f_read_mem
) ? f_read_mem
: read_mem64
;
237 csw
.u
.s64
.f_xlat_adr
= (f_xlat_adr
) ? f_xlat_adr
: addr_to_linear
;
238 csw
.u
.s64
.f_tabl_acs
= (FunctionTableAccessRoutine
) ? FunctionTableAccessRoutine
: SymFunctionTableAccess64
;
239 csw
.u
.s64
.f_modl_bas
= (GetModuleBaseRoutine
) ? GetModuleBaseRoutine
: SymGetModuleBase64
;
241 if (!cpu
->stack_walk(&csw
, frame
, ctx
)) return FALSE
;
243 /* we don't handle KdHelp */
248 /* all the fields of STACKFRAME64 are present in STACKFRAME_EX at same offset
249 * So casting down a STACKFRAME_EX into a STACKFRAME64 is valid!
251 C_ASSERT(sizeof(STACKFRAME64
) == FIELD_OFFSET(STACKFRAME_EX
, StackFrameSize
));
252 C_ASSERT(FIELD_OFFSET(STACKFRAME64
, AddrPC
) == FIELD_OFFSET(STACKFRAME_EX
, AddrPC
));
253 C_ASSERT(FIELD_OFFSET(STACKFRAME64
, AddrReturn
) == FIELD_OFFSET(STACKFRAME_EX
, AddrReturn
));
254 C_ASSERT(FIELD_OFFSET(STACKFRAME64
, AddrFrame
) == FIELD_OFFSET(STACKFRAME_EX
, AddrFrame
));
255 C_ASSERT(FIELD_OFFSET(STACKFRAME64
, AddrStack
) == FIELD_OFFSET(STACKFRAME_EX
, AddrStack
));
256 C_ASSERT(FIELD_OFFSET(STACKFRAME64
, AddrBStore
) == FIELD_OFFSET(STACKFRAME_EX
, AddrBStore
));
257 C_ASSERT(FIELD_OFFSET(STACKFRAME64
, FuncTableEntry
) == FIELD_OFFSET(STACKFRAME_EX
, FuncTableEntry
));
258 C_ASSERT(FIELD_OFFSET(STACKFRAME64
, Params
) == FIELD_OFFSET(STACKFRAME_EX
, Params
));
259 C_ASSERT(FIELD_OFFSET(STACKFRAME64
, Far
) == FIELD_OFFSET(STACKFRAME_EX
, Far
));
260 C_ASSERT(FIELD_OFFSET(STACKFRAME64
, Virtual
) == FIELD_OFFSET(STACKFRAME_EX
, Virtual
));
261 C_ASSERT(FIELD_OFFSET(STACKFRAME64
, Reserved
) == FIELD_OFFSET(STACKFRAME_EX
, Reserved
));
262 C_ASSERT(FIELD_OFFSET(STACKFRAME64
, KdHelp
) == FIELD_OFFSET(STACKFRAME_EX
, KdHelp
));
264 /***********************************************************************
265 * StackWalkEx (DBGHELP.@)
267 BOOL WINAPI
StackWalkEx(DWORD MachineType
, HANDLE hProcess
, HANDLE hThread
,
268 LPSTACKFRAME_EX frame
, PVOID ctx
,
269 PREAD_PROCESS_MEMORY_ROUTINE64 f_read_mem
,
270 PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine
,
271 PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine
,
272 PTRANSLATE_ADDRESS_ROUTINE64 f_xlat_adr
,
275 struct cpu_stack_walk csw
;
279 TRACE("(%ld, %p, %p, %p, %p, %p, %p, %p, %p, 0x%lx)\n",
280 MachineType
, hProcess
, hThread
, frame
, ctx
,
281 f_read_mem
, FunctionTableAccessRoutine
,
282 GetModuleBaseRoutine
, f_xlat_adr
, flags
);
284 if (!(cpu
= cpu_find(MachineType
)))
286 SetLastError(ERROR_INVALID_PARAMETER
);
289 if (frame
->StackFrameSize
!= sizeof(*frame
))
291 SetLastError(ERROR_INVALID_PARAMETER
);
296 FIXME("Unsupported yet flags 0x%lx\n", flags
);
297 SetLastError(ERROR_INVALID_PARAMETER
);
301 csw
.hProcess
= hProcess
;
302 csw
.hThread
= hThread
;
305 /* sigh... MS isn't even consistent in the func prototypes */
306 csw
.u
.s64
.f_read_mem
= (f_read_mem
) ? f_read_mem
: read_mem64
;
307 csw
.u
.s64
.f_xlat_adr
= (f_xlat_adr
) ? f_xlat_adr
: addr_to_linear
;
308 csw
.u
.s64
.f_tabl_acs
= (FunctionTableAccessRoutine
) ? FunctionTableAccessRoutine
: SymFunctionTableAccess64
;
309 csw
.u
.s64
.f_modl_bas
= (GetModuleBaseRoutine
) ? GetModuleBaseRoutine
: SymGetModuleBase64
;
311 addr
= sw_xlat_addr(&csw
, &frame
->AddrPC
);
313 if (IFC_MODE(frame
->InlineFrameContext
) == IFC_MODE_INLINE
)
315 DWORD depth
= SymAddrIncludeInlineTrace(hProcess
, addr
);
316 if (IFC_DEPTH(frame
->InlineFrameContext
) + 1 < depth
) /* move to next inlined function? */
318 TRACE("found inline ctx: depth=%lu current=%lu++\n",
319 depth
, frame
->InlineFrameContext
);
320 frame
->InlineFrameContext
++; /* just increase index, FIXME detect overflow */
324 frame
->InlineFrameContext
= IFC_MODE_REGULAR
; /* move to next top level function */
329 if (!cpu
->stack_walk(&csw
, (STACKFRAME64
*)frame
, ctx
)) return FALSE
;
330 if (frame
->InlineFrameContext
!= INLINE_FRAME_CONTEXT_IGNORE
)
332 addr
= sw_xlat_addr(&csw
, &frame
->AddrPC
);
333 frame
->InlineFrameContext
= SymAddrIncludeInlineTrace(hProcess
, addr
) == 0 ? IFC_MODE_REGULAR
: IFC_MODE_INLINE
;
334 TRACE("setting IFC mode to %lx\n", frame
->InlineFrameContext
);
338 /* we don't handle KdHelp */
343 /******************************************************************
344 * SymRegisterFunctionEntryCallback (DBGHELP.@)
348 BOOL WINAPI
SymRegisterFunctionEntryCallback(HANDLE hProc
,
349 PSYMBOL_FUNCENTRY_CALLBACK cb
, PVOID user
)
351 FIXME("(%p %p %p): stub!\n", hProc
, cb
, user
);
352 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
356 /******************************************************************
357 * SymRegisterFunctionEntryCallback64 (DBGHELP.@)
361 BOOL WINAPI
SymRegisterFunctionEntryCallback64(HANDLE hProc
,
362 PSYMBOL_FUNCENTRY_CALLBACK64 cb
,
365 FIXME("(%p %p %I64x): stub!\n", hProc
, cb
, user
);
366 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);