There is an issue with copy_line_W64_from_64 where converting to unicode the string would be truncated. This issue is caused by the use of the pointer return by fetch_buffer, in this cause both arguments passed to MultiByteToWideChar would be the same pointer.
SymGetLineFromAddrW64 - Call SymGetLineFromAddr64 - returns il64->Filename = fetch_buffer; - Call copy_line_W64_from_64 - Line->Filename = fetch_buffer; - Calls MultiByteToWideChar (.., il64->Filename, .. Line->Filename..)
Signed-off-by: Alistair Leslie-Hughes leslie_alistair@hotmail.com --- dlls/dbghelp/symbol.c | 69 ++++++++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 21 deletions(-)
diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index b2b4d578910..c701a973c2a 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -1528,6 +1528,38 @@ BOOL symt_fill_func_line_info(const struct module* module, const struct symt_fun return FALSE; }
+static BOOL symt_fill_func_line_info_w(const struct module* module, const struct symt_function* func, + DWORD64 addr, IMAGEHLP_LINEW64* line) +{ + struct line_info* dli = NULL; + BOOL found = FALSE; + int i; + + assert(func->symt.tag == SymTagFunction); + + for (i=vector_length(&func->vlines)-1; i>=0; i--) + { + dli = vector_at(&func->vlines, i); + if (!dli->is_source_file) + { + if (found || dli->u.pc_offset > addr) continue; + line->LineNumber = dli->line_number; + line->Address = dli->u.pc_offset; + line->Key = dli; + found = TRUE; + continue; + } + if (found) + { + WCHAR *dospath = wine_get_dos_file_name(source_get(module, dli->u.source_file)); + wcscpy(line->FileName, dospath); + HeapFree( GetProcessHeap(), 0, dospath ); + return TRUE; + } + } + return FALSE; +} + /*********************************************************************** * SymGetSymNext64 (DBGHELP.@) */ @@ -1587,22 +1619,6 @@ static void copy_line_64_from_32(IMAGEHLP_LINE64* l64, const IMAGEHLP_LINE* l32) l64->Address = l32->Address; }
-/****************************************************************** - * copy_line_W64_from_32 (internal) - * - */ -static void copy_line_W64_from_64(struct process* pcs, IMAGEHLP_LINEW64* l64w, const IMAGEHLP_LINE64* l64) -{ - unsigned len; - - l64w->Key = l64->Key; - l64w->LineNumber = l64->LineNumber; - len = MultiByteToWideChar(CP_ACP, 0, l64->FileName, -1, NULL, 0); - if ((l64w->FileName = fetch_buffer(pcs, len * sizeof(WCHAR)))) - MultiByteToWideChar(CP_ACP, 0, l64->FileName, -1, l64w->FileName, len); - l64w->Address = l64->Address; -} - /****************************************************************** * copy_line_32_from_64 (internal) * @@ -1666,12 +1682,23 @@ BOOL WINAPI SymGetLineFromAddr64(HANDLE hProcess, DWORD64 dwAddr, BOOL WINAPI SymGetLineFromAddrW64(HANDLE hProcess, DWORD64 dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINEW64 Line) { - IMAGEHLP_LINE64 il64; + struct module_pair pair; + struct symt_ht* symt;
- il64.SizeOfStruct = sizeof(il64); - if (!SymGetLineFromAddr64(hProcess, dwAddr, pdwDisplacement, &il64)) - return FALSE; - copy_line_W64_from_64(process_find_by_handle(hProcess), Line, &il64); + TRACE("%p %s %p %p\n", hProcess, wine_dbgstr_longlong(dwAddr), pdwDisplacement, Line); + + if (Line->SizeOfStruct < sizeof(*Line)) return FALSE; + + pair.pcs = process_find_by_handle(hProcess); + if (!pair.pcs) return FALSE; + pair.requested = module_find_by_addr(pair.pcs, dwAddr, DMT_UNKNOWN); + if (!module_get_debug(&pair)) return FALSE; + if ((symt = symt_find_nearest(pair.effective, dwAddr)) == NULL) return FALSE; + + if (symt->symt.tag != SymTagFunction) return FALSE; + if (!symt_fill_func_line_info_w(pair.effective, (struct symt_function*)symt, + dwAddr, Line)) return FALSE; + *pdwDisplacement = dwAddr - Line->Address; return TRUE; }
as reported by Alistair, SymGetLineFromAddrW64 requires at least two buffers
I suggest using this patch instead of Alistair's, because: - it doesn't duplicate internal lookup functions between A and W versions - it's more robust against future use of fetch_buffer
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dbghelp.c | 18 ++++++++++++------ dlls/dbghelp/dbghelp_private.h | 11 +++++++++-- 2 files changed, 21 insertions(+), 8 deletions(-)
diff --git a/dlls/dbghelp/dbghelp.c b/dlls/dbghelp/dbghelp.c index 00d7b61fbd8..af8cf17741c 100644 --- a/dlls/dbghelp/dbghelp.c +++ b/dlls/dbghelp/dbghelp.c @@ -118,15 +118,21 @@ BOOL validate_addr64(DWORD64 addr) */ void* fetch_buffer(struct process* pcs, unsigned size) { - if (size > pcs->buffer_size) + struct process_buffer* pb = &pcs->buffers[pcs->buffers_index]; + + if (size > pb->size) { - if (pcs->buffer) - pcs->buffer = HeapReAlloc(GetProcessHeap(), 0, pcs->buffer, size); + void* new; + if (pb->ptr) + new = HeapReAlloc(GetProcessHeap(), 0, pb->ptr, size); else - pcs->buffer = HeapAlloc(GetProcessHeap(), 0, size); - pcs->buffer_size = (pcs->buffer) ? size : 0; + new = HeapAlloc(GetProcessHeap(), 0, size); + if (!new) return NULL; + pb->size = size; + pb->ptr = new; } - return pcs->buffer; + pcs->buffers_index = (pcs->buffers_index + 1) % ARRAY_SIZE(pcs->buffers); + return pb->ptr; }
const char* wine_dbgstr_addr(const ADDRESS64* addr) diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 3415fc1557c..cc74d0c1edc 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -397,6 +397,12 @@ struct loader_ops BOOL (*fetch_file_info)(struct process* process, const WCHAR* name, ULONG_PTR load_addr, DWORD_PTR* base, DWORD* size, DWORD* checksum); };
+struct process_buffer +{ + unsigned size; + void* ptr; +}; + struct process { struct process* next; @@ -415,8 +421,9 @@ struct process
IMAGEHLP_STACK_FRAME ctx_frame;
- unsigned buffer_size; - void* buffer; + /* buffer:s ring */ + struct process_buffer buffers[2]; + unsigned buffers_index;
BOOL is_64bit; };