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
24 #include "dbghelp_private.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp
);
28 static DWORD64 WINAPI
addr_to_linear(HANDLE hProcess
, HANDLE hThread
, ADDRESS64
* addr
)
35 if (GetThreadSelectorEntry(hThread
, addr
->Segment
, &le
))
36 return (le
.HighWord
.Bits
.BaseHi
<< 24) +
37 (le
.HighWord
.Bits
.BaseMid
<< 16) + le
.BaseLow
+ LOWORD(addr
->Offset
);
40 if (GetThreadSelectorEntry(hThread
, addr
->Segment
, &le
))
41 return (le
.HighWord
.Bits
.BaseHi
<< 24) +
42 (le
.HighWord
.Bits
.BaseMid
<< 16) + le
.BaseLow
+ addr
->Offset
;
45 return (DWORD
)(LOWORD(addr
->Segment
) << 4) + addr
->Offset
;
49 FIXME("Unsupported (yet) mode (%x)\n", addr
->Mode
);
52 FIXME("Failed to linearize address %04x:%s (mode %x)\n",
53 addr
->Segment
, wine_dbgstr_longlong(addr
->Offset
), addr
->Mode
);
57 static BOOL CALLBACK
read_mem(HANDLE hProcess
, DWORD addr
, void* buffer
,
58 DWORD size
, LPDWORD nread
)
61 if (!ReadProcessMemory(hProcess
, (void*)(DWORD_PTR
)addr
, buffer
, size
, &r
)) return FALSE
;
62 if (nread
) *nread
= r
;
66 static BOOL CALLBACK
read_mem64(HANDLE hProcess
, DWORD64 addr
, void* buffer
,
67 DWORD size
, LPDWORD nread
)
70 if (!ReadProcessMemory(hProcess
, (void*)(DWORD_PTR
)addr
, buffer
, size
, &r
)) return FALSE
;
71 if (nread
) *nread
= r
;
75 static inline void addr_32to64(const ADDRESS
* addr32
, ADDRESS64
* addr64
)
77 addr64
->Offset
= (ULONG64
)addr32
->Offset
;
78 addr64
->Segment
= addr32
->Segment
;
79 addr64
->Mode
= addr32
->Mode
;
82 static inline void addr_64to32(const ADDRESS64
* addr64
, ADDRESS
* addr32
)
84 addr32
->Offset
= (ULONG
)addr64
->Offset
;
85 addr32
->Segment
= addr64
->Segment
;
86 addr32
->Mode
= addr64
->Mode
;
89 BOOL
sw_read_mem(struct cpu_stack_walk
* csw
, DWORD64 addr
, void* ptr
, DWORD sz
)
93 return csw
->u
.s32
.f_read_mem(csw
->hProcess
, addr
, ptr
, sz
, &bytes_read
);
95 return csw
->u
.s64
.f_read_mem(csw
->hProcess
, addr
, ptr
, sz
, &bytes_read
);
98 DWORD64
sw_xlat_addr(struct cpu_stack_walk
* csw
, ADDRESS64
* addr
)
100 if (addr
->Mode
== AddrModeFlat
) return addr
->Offset
;
105 addr_64to32(addr
, &addr32
);
106 return csw
->u
.s32
.f_xlat_adr(csw
->hProcess
, csw
->hThread
, &addr32
);
108 else if (csw
->u
.s64
.f_xlat_adr
)
109 return csw
->u
.s64
.f_xlat_adr(csw
->hProcess
, csw
->hThread
, addr
);
110 return addr_to_linear(csw
->hProcess
, csw
->hThread
, addr
);
113 void* sw_table_access(struct cpu_stack_walk
* csw
, DWORD64 addr
)
116 return csw
->u
.s32
.f_tabl_acs(csw
->hProcess
, addr
);
118 return csw
->u
.s64
.f_tabl_acs(csw
->hProcess
, addr
);
121 DWORD64
sw_module_base(struct cpu_stack_walk
* csw
, DWORD64 addr
)
124 return csw
->u
.s32
.f_modl_bas(csw
->hProcess
, addr
);
126 return csw
->u
.s64
.f_modl_bas(csw
->hProcess
, addr
);
129 /***********************************************************************
130 * StackWalk (DBGHELP.@)
132 BOOL WINAPI
StackWalk(DWORD MachineType
, HANDLE hProcess
, HANDLE hThread
,
133 LPSTACKFRAME frame32
, PVOID ctx
,
134 PREAD_PROCESS_MEMORY_ROUTINE f_read_mem
,
135 PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine
,
136 PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine
,
137 PTRANSLATE_ADDRESS_ROUTINE f_xlat_adr
)
139 struct cpu_stack_walk csw
;
140 STACKFRAME64 frame64
;
144 TRACE("(%d, %p, %p, %p, %p, %p, %p, %p, %p)\n",
145 MachineType
, hProcess
, hThread
, frame32
, ctx
,
146 f_read_mem
, FunctionTableAccessRoutine
,
147 GetModuleBaseRoutine
, f_xlat_adr
);
149 if (!(cpu
= cpu_find(MachineType
)))
151 SetLastError(ERROR_INVALID_PARAMETER
);
155 addr_32to64(&frame32
->AddrPC
, &frame64
.AddrPC
);
156 addr_32to64(&frame32
->AddrReturn
, &frame64
.AddrReturn
);
157 addr_32to64(&frame32
->AddrFrame
, &frame64
.AddrFrame
);
158 addr_32to64(&frame32
->AddrStack
, &frame64
.AddrStack
);
159 addr_32to64(&frame32
->AddrBStore
, &frame64
.AddrBStore
);
160 frame64
.FuncTableEntry
= frame32
->FuncTableEntry
; /* FIXME */
161 frame64
.Far
= frame32
->Far
;
162 frame64
.Virtual
= frame32
->Virtual
;
163 frame64
.Reserved
[0] = frame32
->Reserved
[0];
164 frame64
.Reserved
[1] = frame32
->Reserved
[1];
165 frame64
.Reserved
[2] = frame32
->Reserved
[2];
166 /* we don't handle KdHelp */
168 csw
.hProcess
= hProcess
;
169 csw
.hThread
= hThread
;
171 /* sigh... MS isn't even consistent in the func prototypes */
172 csw
.u
.s32
.f_read_mem
= (f_read_mem
) ? f_read_mem
: read_mem
;
173 csw
.u
.s32
.f_xlat_adr
= f_xlat_adr
;
174 csw
.u
.s32
.f_tabl_acs
= (FunctionTableAccessRoutine
) ? FunctionTableAccessRoutine
: SymFunctionTableAccess
;
175 csw
.u
.s32
.f_modl_bas
= (GetModuleBaseRoutine
) ? GetModuleBaseRoutine
: SymGetModuleBase
;
177 if ((ret
= cpu
->stack_walk(&csw
, &frame64
, ctx
)))
179 addr_64to32(&frame64
.AddrPC
, &frame32
->AddrPC
);
180 addr_64to32(&frame64
.AddrReturn
, &frame32
->AddrReturn
);
181 addr_64to32(&frame64
.AddrFrame
, &frame32
->AddrFrame
);
182 addr_64to32(&frame64
.AddrStack
, &frame32
->AddrStack
);
183 addr_64to32(&frame64
.AddrBStore
, &frame32
->AddrBStore
);
184 frame32
->FuncTableEntry
= frame64
.FuncTableEntry
; /* FIXME */
185 frame32
->Params
[0] = frame64
.Params
[0];
186 frame32
->Params
[1] = frame64
.Params
[1];
187 frame32
->Params
[2] = frame64
.Params
[2];
188 frame32
->Params
[3] = frame64
.Params
[3];
189 frame32
->Far
= frame64
.Far
;
190 frame32
->Virtual
= frame64
.Virtual
;
191 frame32
->Reserved
[0] = frame64
.Reserved
[0];
192 frame32
->Reserved
[1] = frame64
.Reserved
[1];
193 frame32
->Reserved
[2] = frame64
.Reserved
[2];
200 /***********************************************************************
201 * StackWalk64 (DBGHELP.@)
203 BOOL WINAPI
StackWalk64(DWORD MachineType
, HANDLE hProcess
, HANDLE hThread
,
204 LPSTACKFRAME64 frame
, PVOID ctx
,
205 PREAD_PROCESS_MEMORY_ROUTINE64 f_read_mem
,
206 PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine
,
207 PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine
,
208 PTRANSLATE_ADDRESS_ROUTINE64 f_xlat_adr
)
210 struct cpu_stack_walk csw
;
213 TRACE("(%d, %p, %p, %p, %p, %p, %p, %p, %p)\n",
214 MachineType
, hProcess
, hThread
, frame
, ctx
,
215 f_read_mem
, FunctionTableAccessRoutine
,
216 GetModuleBaseRoutine
, f_xlat_adr
);
218 if (!(cpu
= cpu_find(MachineType
)))
220 SetLastError(ERROR_INVALID_PARAMETER
);
224 csw
.hProcess
= hProcess
;
225 csw
.hThread
= hThread
;
227 /* sigh... MS isn't even consistent in the func prototypes */
228 csw
.u
.s64
.f_read_mem
= (f_read_mem
) ? f_read_mem
: read_mem64
;
229 csw
.u
.s64
.f_xlat_adr
= (f_xlat_adr
) ? f_xlat_adr
: addr_to_linear
;
230 csw
.u
.s64
.f_tabl_acs
= (FunctionTableAccessRoutine
) ? FunctionTableAccessRoutine
: SymFunctionTableAccess64
;
231 csw
.u
.s64
.f_modl_bas
= (GetModuleBaseRoutine
) ? GetModuleBaseRoutine
: SymGetModuleBase64
;
233 if (!cpu
->stack_walk(&csw
, frame
, ctx
)) return FALSE
;
235 /* we don't handle KdHelp */
240 /******************************************************************
241 * SymRegisterFunctionEntryCallback (DBGHELP.@)
245 BOOL WINAPI
SymRegisterFunctionEntryCallback(HANDLE hProc
,
246 PSYMBOL_FUNCENTRY_CALLBACK cb
, PVOID user
)
248 FIXME("(%p %p %p): stub!\n", hProc
, cb
, user
);
249 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
253 /******************************************************************
254 * SymRegisterFunctionEntryCallback64 (DBGHELP.@)
258 BOOL WINAPI
SymRegisterFunctionEntryCallback64(HANDLE hProc
,
259 PSYMBOL_FUNCENTRY_CALLBACK64 cb
,
262 FIXME("(%p %p %s): stub!\n", hProc
, cb
, wine_dbgstr_longlong(user
));
263 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);