[Bug 48861] New: x64dbg fails to set debuggee command line via File -> Change Command Line menu
WineHQ Bugzilla
wine-bugs at winehq.org
Mon Mar 30 18:00:59 CDT 2020
https://bugs.winehq.org/show_bug.cgi?id=48861
Bug ID: 48861
Summary: x64dbg fails to set debuggee command line via File ->
Change Command Line menu
Product: Wine
Version: 5.5
Hardware: x86-64
OS: Linux
Status: NEW
Severity: normal
Priority: P2
Component: kernelbase
Assignee: wine-bugs at winehq.org
Reporter: focht at gmx.net
Distribution: ---
Hello folks,
https://github.com/x64dbg/x64dbg/wiki/Frequently-Asked-Questions
--- quote ---
Q: Help, how do I pass arguments to the program I want to debug?
A: Use the File -> Change Command Line option:
--- quote ---
This doesn't work under Wine. One has to start the debuggee using an
undocumented way.
https://github.com/x64dbg/x64dbg/issues/210
The documentation task https://github.com/x64dbg/docs/issues/26 is still open
since 2016.
Examples:
--- snip --
# starts x64dbg with 64-bit debuggee and args
$ wine ./x96dbg.exe "c:\\windows\\system32\\cmd.exe" /k echo
"%PROCESSOR_ARCHITECTURE%"
# starts x32dbg with 32-bit debuggee and args
$ wine ./x96dbg.exe "c:\\windows\\syswow64\\cmd.exe" /k echo
"%PROCESSOR_ARCHITECTURE%"
--- snip ---
Anyway, the problem here is how Wine implements 'kernel32.GetCommandLine{A,W}'
functions.
Starting with x64dbg sources...
https://github.com/x64dbg/x64dbg/blob/d2c62e69c2cd4d42cc4509612ad3cfd34e91426b/src/dbg/debugger.cpp#L2406
--- snip ---
bool dbgsetcmdline(const char* cmd_line, cmdline_error_t* cmd_line_error)
{
// Make sure cmd_line_error is a valid pointer
cmdline_error_t cmd_line_error_aux;
if(cmd_line_error == NULL)
cmd_line_error = &cmd_line_error_aux;
// Get the command line address
if(!getcommandlineaddr(&cmd_line_error->addr, cmd_line_error))
return false;
auto command_line_addr = cmd_line_error->addr;
// Convert the string to UTF-16
auto command_linewstr = StringUtils::Utf8ToUtf16(cmd_line);
if(command_linewstr.length() >= 32766) //32766 is maximum character count
for a null-terminated UNICODE_STRING
command_linewstr.resize(32766);
// Convert the UTF-16 string to ANSI
auto command_linestr = Utf16ToAnsi(command_linewstr.c_str());
// Fill the UNICODE_STRING to be set in the debuggee
UNICODE_STRING new_command_line;
new_command_line.Length = USHORT(command_linewstr.length() *
sizeof(WCHAR)); //max value: 32766 * 2 = 65532
new_command_line.MaximumLength = new_command_line.Length + sizeof(WCHAR);
//max value: 65532 + 2 = 65534
new_command_line.Buffer = PWSTR(command_linewstr.c_str()); //allow cast
from const because the UNICODE_STRING will not be used locally
// Allocate remote memory for both the UNICODE_STRING.Buffer and the (null
terminated) ANSI buffer
duint mem = MemAllocRemote(0, new_command_line.MaximumLength +
command_linestr.size());
if(!mem)
{
cmd_line_error->type = CMDL_ERR_ALLOC_UNICODEANSI_COMMANDLINE;
return false;
}
// Write the UNICODE_STRING.Buffer to the debuggee (UNICODE_STRING.Length
is used because the remote memory is zeroed)
if(!MemWrite(mem, new_command_line.Buffer, new_command_line.Length))
{
cmd_line_error->addr = mem;
cmd_line_error->type = CMDL_ERR_WRITE_UNICODE_COMMANDLINE;
return false;
}
// Write the (null-terminated) ANSI buffer to the debuggee
if(!MemWrite(mem + new_command_line.MaximumLength, command_linestr.data(),
command_linestr.size()))
{
cmd_line_error->addr = mem + new_command_line.MaximumLength;
cmd_line_error->type = CMDL_ERR_WRITE_ANSI_COMMANDLINE;
return false;
}
// Change the pointers to the command line
if(!fixgetcommandlinesbase(mem, mem + new_command_line.MaximumLength,
cmd_line_error))
return false;
// Put the remote buffer address in the UNICODE_STRING and write it to the
PEB
new_command_line.Buffer = PWSTR(mem);
if(!MemWrite(command_line_addr, &new_command_line,
sizeof(new_command_line)))
{
cmd_line_error->addr = command_line_addr;
cmd_line_error->type = CMDL_ERR_WRITE_PEBUNICODE_COMMANDLINE;
return false;
}
// Copy command line
copyCommandLine(cmd_line);
return true;
}
--- snip ---
Corresponding Wine trace log snippet:
--- snip ---
...
0009:Call KERNEL32.VirtualAllocEx(0000024c,00000000,00000087,00003000,00000040)
ret=01dd445c
0009:Call
ntdll.NtAllocateVirtualMemory(0000024c,0032ce3c,00000000,0032ce58,00003000,00000040)
ret=7b022f18
0009: queue_apc( handle=024c,
call={APC_VIRTUAL_ALLOC,addr==00000000,size=00000087,zero_bits_64=0,op_type=3000,prot=40}
)
0045: *wakeup* signaled=256
0009: queue_apc() = 0 { handle=02e8, self=0 }
0045: select( flags=2, cookie=7ffdb10c, timeout=infinite, prev_apc=0000,
result={APC_VIRTUAL_QUERY,status=0,base=00330000,alloc_base=00330000,size=00001000,state=1,prot=2,alloc_prot=80,alloc_type=100},
data={WAIT,handles={0048}} )
0045: select() = KERNEL_APC { timeout=infinite,
call={APC_VIRTUAL_ALLOC,addr==00000000,size=00000087,zero_bits_64=0,op_type=3000,prot=40},
apc_handle=004c }
0009: select( flags=2, cookie=0032c9ac, timeout=infinite, prev_apc=0000,
result={}, data={WAIT_ALL,handles={02e8}} )
0009: select() = PENDING { timeout=infinite, call={APC_NONE}, apc_handle=0000 }
0045: select( flags=2, cookie=7ffdb10c, timeout=infinite, prev_apc=004c,
result={APC_VIRTUAL_ALLOC,status=0,addr=00380000,size=00001000},
data={WAIT,handles={0048}} )
0009: *wakeup* signaled=0
0045: select() = PENDING { timeout=infinite, call={APC_NONE}, apc_handle=0000 }
0009: get_apc_result( handle=02e8 )
0009: get_apc_result() = 0 {
result={APC_VIRTUAL_ALLOC,status=0,addr=00380000,size=00001000} }
0009:Ret ntdll.NtAllocateVirtualMemory() retval=00000000 ret=7b022f18
0009:Ret KERNEL32.VirtualAllocEx() retval=00380000 ret=01dd445c
0009:Call
KERNEL32.WriteProcessMemory(0000024c,00380000,05ab7250,00000058,0032cea8)
ret=0211b7b8
0009:Call
ntdll.NtWriteVirtualMemory(0000024c,00380000,05ab7250,00000058,0032cea8)
ret=7b023199
0009: write_process_memory( handle=024c, addr=00380000,
data={22,00,43,00,3a,00,5c,00,77,00,69,00,6e,00,64,00,6f,00,77,00,73,00,5c,00,73,00,79,00,73,00,77,00,6f,00,77,00,36,00,34,00,5c,00,77,00,69,00,6e,00,65,00,6d,00,69,00,6e,00,65,00,2e,00,65,00,78,00,65,00,22,00,20,00,2d,00,74,00,65,00,73,00,74,00,61,00,72,00,67,00,31,00}
)
0045: *signal* signal=19
0009: write_process_memory() = 0
0009:Ret ntdll.NtWriteVirtualMemory() retval=00000000 ret=7b023199
0009:Ret KERNEL32.WriteProcessMemory() retval=00000001 ret=0211b7b8
0009:Call
KERNEL32.WriteProcessMemory(0000024c,0038005a,05a989f8,0000002d,0032cea8)
ret=0211b7b8
0009:Call
ntdll.NtWriteVirtualMemory(0000024c,0038005a,05a989f8,0000002d,0032cea8)
ret=7b023199
0009: write_process_memory( handle=024c, addr=0038005a,
data={22,43,3a,5c,77,69,6e,64,6f,77,73,5c,73,79,73,77,6f,77,36,34,5c,77,69,6e,65,6d,69,6e,65,2e,65,78,65,22,20,2d,74,65,73,74,61,72,67,31,00}
)
0045: *signal* signal=19
0009: write_process_memory() = 0
0009:Ret ntdll.NtWriteVirtualMemory() retval=00000000 ret=7b023199
0009:Ret KERNEL32.WriteProcessMemory() retval=00000001 ret=0211b7b8
--- snip ---
Both, ANSI and UNICODE buffers are allocated and filled in debuggee process
space.
https://github.com/x64dbg/x64dbg/blob/d2c62e69c2cd4d42cc4509612ad3cfd34e91426b/src/dbg/debugger.cpp#L2365
--- snip ---
static bool fixgetcommandlinesbase(duint new_command_line_unicode, duint
new_command_line_ascii, cmdline_error_t* cmd_line_error)
{
duint getcommandline;
if(!valfromstring("kernelBase:GetCommandLineA", &getcommandline))
{
if(!valfromstring("kernel32:GetCommandLineA", &getcommandline))
{
cmd_line_error->type = CMDL_ERR_GET_GETCOMMANDLINE;
return false;
}
}
if(!patchcmdline(getcommandline, new_command_line_ascii, cmd_line_error))
return false;
if(!valfromstring("kernelbase:GetCommandLineW", &getcommandline))
{
if(!valfromstring("kernel32:GetCommandLineW", &getcommandline))
{
cmd_line_error->type = CMDL_ERR_GET_GETCOMMANDLINE;
return false;
}
}
if(!patchcmdline(getcommandline, new_command_line_unicode, cmd_line_error))
return false;
return true;
}
--- snip ---
Corresponding Wine trace log snippet:
--- snip ---
...
0009:Call KERNEL32.LoadLibraryExW(05ab78d8
L"Z:\\home\\focht\\projects\\wine\\mainline-install-x86_64\\lib\\wine\\kernelbase.dll",00000000,00000001)
ret=01e0dbdf
...
0009:Ret KERNEL32.LoadLibraryExW() retval=7b000000 ret=01e0dbdf
...
0009:Call KERNEL32.GetProcAddress(7b000000,05ab78bb "GetCommandLineA")
ret=01e0b046
0009:Ret KERNEL32.GetProcAddress() retval=7b0036ec ret=01e0b046
0009:Call KERNEL32.FreeLibrary(7b000000) ret=01e0ddf9
0009:Ret KERNEL32.FreeLibrary() retval=00000001 ret=01e0ddf9
...
0009:Call
KERNEL32.ReadProcessMemory(0000024c,7b0036ec,0032ce2c,00000064,0032ce08)
ret=0211b6bc
0009:Call
ntdll.NtReadVirtualMemory(0000024c,7b0036ec,0032ce2c,00000064,0032ce08)
ret=7b022cf9
0009: read_process_memory( handle=024c, addr=7b0036ec )
0045: *signal* signal=19
0009: read_process_memory() = 0 {
data={8b,ff,55,8b,ec,5d,68,36,01,0c,00,b8,00,50,07,7b,50,ff,50,04,c2,00,00,90,90,90,90,90,90,90,90,90,8b,ff,55,8b,ec,5d,68,37,01,0c,00,b8,00,50,07,7b,50,ff,50,04,c2,00,00,90,90,90,90,90,90,90,90,90,8b,ff,55,8b,ec,5d,68,38,01,0a,00,b8,00,50,07,7b,50,ff,50,04,c2,08,00,90,90,90,90,90,90,90,90,90,8b,ff,55,8b}
}
0009:Ret ntdll.NtReadVirtualMemory() retval=00000000 ret=7b022cf9
0009:Ret KERNEL32.ReadProcessMemory() retval=00000001 ret=0211b6bc
...
--- snip ---
x32dbg reads the opcodes of 32-bit 'kernelbase.GetCommandLineA' and is not
happy about it.
--- snip ---
static bool patchcmdline(duint getcommandline, duint new_command_line,
cmdline_error_t* cmd_line_error)
{
duint command_line_stored = 0;
unsigned char data[100];
cmd_line_error->addr = getcommandline;
if(!MemRead(cmd_line_error->addr, & data, sizeof(data)))
{
cmd_line_error->type = CMDL_ERR_READ_GETCOMMANDLINEBASE;
return false;
}
#ifdef _WIN64
/*
00007FFC5B91E3C8 | 48 8B 05 19 1D 0E 00 | mov rax,qword ptr
ds:[7FFC5BA000E8]
00007FFC5B91E3CF | C3 | ret
|
This is a relative offset then to get the symbol: next instruction of
getmodulehandle (+7 bytes) + offset to symbol
(the last 4 bytes of the instruction)
*/
if(data[0] != 0x48 || data[1] != 0x8B || data[2] != 0x05 || data[7] !=
0xC3)
{
cmd_line_error->type = CMDL_ERR_CHECK_GETCOMMANDLINESTORED;
return false;
}
DWORD offset = * ((DWORD*) & data[3]);
command_line_stored = getcommandline + 7 + offset;
#else //x86
/*
750FE9CA | A1 CC DB 1A 75 | mov eax,dword ptr ds:[751ADBCC]
|
750FE9CF | C3 | ret
|
*/
if(data[0] != 0xA1 || data[5] != 0xC3)
{
cmd_line_error->type = CMDL_ERR_CHECK_GETCOMMANDLINESTORED;
return false;
}
command_line_stored = * ((duint*) & data[1]);
#endif
//update the pointer in the debuggee
if(!MemWrite(command_line_stored, &new_command_line,
sizeof(new_command_line)))
{
cmd_line_error->addr = command_line_stored;
cmd_line_error->type = CMDL_ERR_WRITE_GETCOMMANDLINESTORED;
return false;
}
return true;
}
--- snip ---
Wine source:
https://source.winehq.org/git/wine.git/blob/9bcb1f5195d1e65e0e7afb288d36fee716fe3a60:/dlls/kernelbase/process.c#l1008
--- snip ---
1008 static STARTUPINFOW startup_infoW;
1009 static char *command_lineA;
1010 static WCHAR *command_lineW;
--- snip ---
https://source.winehq.org/git/wine.git/blob/9bcb1f5195d1e65e0e7afb288d36fee716fe3a60:/dlls/kernelbase/process.c#l1043
--- snip ---
1043 /***********************************************************************
1044 * GetCommandLineA (kernelbase.@)
1045 */
1046 LPSTR WINAPI DECLSPEC_HOTPATCH GetCommandLineA(void)
1047 {
1048 return command_lineA;
1049 }
1050
1051
1052 /***********************************************************************
1053 * GetCommandLineW (kernelbase.@)
1054 */
1055 LPWSTR WINAPI DECLSPEC_HOTPATCH GetCommandLineW(void)
1056 {
1057 return NtCurrentTeb()->Peb->ProcessParameters->CommandLine.Buffer;
1058 }
--- snip ---
Depending on which compiler (GCC or LLVM/MingW) is used to build Wine, the
following code is generated:
=== GCC ===
--- snip --
$ gcc -v
Using built-in specs.
COLLECT_GCC=/usr/bin/gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/8/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-redhat-linux
Configured with: ../configure --enable-bootstrap
--enable-languages=c,c++,fortran,objc,obj-c++,ada,go,lto --prefix=/usr
--mandir=/usr/share/man --infodir=/usr/share/info
--with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-shared
--enable-threads=posix --enable-checking=release --enable-multilib
--with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions
--enable-gnu-unique-object --enable-linker-build-id
--with-gcc-major-version-only --with-linker-hash-style=gnu --enable-plugin
--enable-initfini-array --with-isl --enable-libmpx
--enable-offload-targets=nvptx-none --without-cuda-driver
--enable-gnu-indirect-function --enable-cet --with-tune=generic
--with-arch_32=i686 --build=x86_64-redhat-linux
Thread model: posix
gcc version 8.3.1 20190223 (Red Hat 8.3.1-2) (GCC)
--- snip ---
--- snip ---
$ gdb mainline-install-x86_64/lib64/wine/kernelbase.dll.so -batch -ex
'disassemble GetCommandLineA'
Dump of assembler code for function GetCommandLineA:
0x000000007b05fd18 <+0>: push %rbp
0x000000007b05fd19 <+1>: mov 0x738a0(%rip),%rax # 0x7b0d35c0
<command_lineA>
0x000000007b05fd20 <+8>: mov %rsp,%rbp
0x000000007b05fd23 <+11>: and $0xfffffffffffffff0,%rsp
0x000000007b05fd27 <+15>: leaveq
0x000000007b05fd28 <+16>: retq
End of assembler dump.
--- snip ---
--- snip ---
$ gdb mainline-install-x86_64/lib64/wine/kernelbase.dll.so -batch -ex
'disassemble GetCommandLineW'
Dump of assembler code for function GetCommandLineW:
0x000000007b05fd58 <+0>: push %rbp
0x000000007b05fd59 <+1>: mov %gs:0x30,%rax
0x000000007b05fd62 <+10>: mov 0x60(%rax),%rax
0x000000007b05fd66 <+14>: mov %rsp,%rbp
0x000000007b05fd69 <+17>: and $0xfffffffffffffff0,%rsp
0x000000007b05fd6d <+21>: mov 0x20(%rax),%rax
0x000000007b05fd71 <+25>: mov 0x78(%rax),%rax
0x000000007b05fd75 <+29>: leaveq
0x000000007b05fd76 <+30>: retq
End of assembler dump.
--- snip ---
NOTE: offset-0x4 to work around dwarf symbol processing bug.
--- snip ---
$ gdb mainline-install-x86_64/lib/wine/kernelbase.dll.so -batch -ex
'disassemble GetCommandLineA-0x4'
Dump of assembler code for function GetCommandLineA:
0x7b060620 <+0>: mov %edi,%edi
0x7b060622 <+2>: push %ebp
0x7b060623 <+3>: mov %esp,%ebp
0x7b060625 <+0>: pop %ebp
0x7b060626 <+1>: mov 0x7b0d4a20,%eax
0x7b06062b <+6>: ret
End of assembler dump.
--- snip ---
--- snip ---
$ gdb mainline-install-x86_64/lib/wine/kernelbase.dll.so -batch -ex
'disassemble GetCommandLineW-0x4'
Dump of assembler code for function GetCommandLineW:
0x7b060640 <+0>: mov %edi,%edi
0x7b060642 <+2>: push %ebp
0x7b060643 <+3>: mov %esp,%ebp
0x7b060645 <+0>: mov %fs:0x18,%eax
0x7b06064b <+6>: mov 0x30(%eax),%eax
0x7b06064e <+9>: pop %ebp
0x7b06064f <+10>: mov 0x10(%eax),%eax
0x7b060652 <+13>: mov 0x44(%eax),%eax
0x7b060655 <+16>: ret
End of assembler dump.
--- snip ---
=== LLVM MinGW ===
--- snip ---
$ clang -v
clang version 10.0.0 (https://github.com/llvm/llvm-project.git
c49194969430f0ee817498a7000a979a7a0ded03)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /home/focht/projects/llvm-mingw-20191230-ubuntu-16.04/bin
Found candidate GCC installation: /usr/lib/gcc/x86_64-redhat-linux/8
Selected GCC installation: /usr/lib/gcc/x86_64-redhat-linux/8
Candidate multilib: .;@m64
Candidate multilib: 32;@m32
Selected multilib: .;@m64
--- snip ---
--- snip ---
$ gdb mainline-install-x86_64/lib/wine/kernelbase.dll -batch -ex 'disassemble
GetCommandLineA'
Dump of assembler code for function _GetCommandLineA at 0:
0x7b0313e0 <+0>: push %ebp
0x7b0313e1 <+1>: mov %esp,%ebp
0x7b0313e3 <+3>: mov 0x7b076bf8,%eax
0x7b0313e8 <+8>: pop %ebp
0x7b0313e9 <+9>: ret
End of assembler dump.
--- snip ---
--- snip ---
$ gdb mainline-install-x86_64/lib/wine/kernelbase.dll -batch -ex 'disassemble
GetCommandLineW'
Dump of assembler code for function _GetCommandLineW at 0:
0x7b0313f0 <+0>: push %ebp
0x7b0313f1 <+1>: mov %esp,%ebp
0x7b0313f3 <+3>: mov %fs:0x18,%eax
0x7b0313f9 <+9>: mov 0x30(%eax),%eax
0x7b0313fc <+12>: mov 0x10(%eax),%eax
0x7b0313ff <+15>: mov 0x44(%eax),%eax
0x7b031402 <+18>: pop %ebp
0x7b031403 <+19>: ret
End of assembler dump.
--- snip ---
--- snip ---
$ gdb mainline-install-x86_64/lib64/wine/kernelbase.dll -batch -ex 'disassemble
GetCommandLineA'
Dump of assembler code for function GetCommandLineA:
0x000000007b0389b0 <+0>: mov 0x4de49(%rip),%rax # 0x7b086800
0x000000007b0389b7 <+7>: retq
End of assembler dump.
--- snip ---
--- snip ---
$ gdb mainline-install-x86_64/lib64/wine/kernelbase.dll -batch -ex 'disassemble
GetCommandLineW'
Dump of assembler code for function GetCommandLineW:
0x000000007b0389c0 <+0>: mov %gs:0x30,%rax
0x000000007b0389c9 <+9>: mov 0x60(%rax),%rax
0x000000007b0389cd <+13>: mov 0x20(%rax),%rax
0x000000007b0389d1 <+17>: mov 0x78(%rax),%rax
0x000000007b0389d5 <+21>: retq
End of assembler dump.
--- snip ---
=====
General problems:
(1) asymmetric design of kernelbase GetCommandLineA/W commmand buffer handling
The ANSI variant returns the command line buffer address directly while the
UNICODE variant goes through the PEB.
The symmetric design was changed in 2003 with
https://source.winehq.org/git/wine.git/commitdiff/b53b5bcb50e75263e8bbffed34fc6ce48b4fdc24
("- fixed a couple of bugs in ntdll...") to be asymmetrical.
A big squash-like commit, doing major refactoring/various bugfixing = several
things in one go. No mentioning of this specific design change. Part of Wine
0.9 release.
(2) HOTPATCH entry
Commit
https://source.winehq.org/git/wine.git/commitdiff/911e50849a9bc05ab11d896a3b7f7a3b3462fabd
("kernel32: Move process startup information functions to kernelbase.") added
it. Part of Wine 4.16 release.
I couldn't find a bug report about hooking problems of GetCommandLineA/W which
requires those to be hotpatch-compatible entries. I guess this was added for no
special reason :|
(3) compiler choice/optimization settings, influencing generated code
---
Fixing above problems is not that easy by just returning 'command_lineW' in 'W'
variant and removing DECLSPEC_HOTPATCH because of (3).
Generated code:
--- snip ---
$ gdb mainline-install-x86_64/lib/wine/kernelbase.dll -batch -ex 'disassemble
GetCommandLineA'
Dump of assembler code for function _GetCommandLineA at 0:
0x7b0313e0 <+0>: push %ebp
0x7b0313e1 <+1>: mov %esp,%ebp
0x7b0313e3 <+3>: mov 0x7b076bf8,%eax
0x7b0313e8 <+8>: pop %ebp
0x7b0313e9 <+9>: ret
End of assembler dump.
--- snip ---
--- snip ---
$ gdb mainline-install-x86_64/lib/wine/kernelbase.dll -batch -ex 'disassemble
GetCommandLineW'
Dump of assembler code for function _GetCommandLineW at 0:
0x7b0313f0 <+0>: push %ebp
0x7b0313f1 <+1>: mov %esp,%ebp
0x7b0313f3 <+3>: mov 0x7b076bf4,%eax
0x7b0313f8 <+8>: pop %ebp
0x7b0313f9 <+9>: ret
End of assembler dump.
--- snip ---
--- snip ---
$ gdb mainline-install-x86_64/lib64/wine/kernelbase.dll -batch -ex 'disassemble
GetCommandLineA'
Dump of assembler code for function GetCommandLineA:
0x000000007b0389b0 <+0>: mov 0x4de49(%rip),%rax # 0x7b086800
0x000000007b0389b7 <+7>: retq
End of assembler dump.
--- snip ---
--- snip ---
$ gdb mainline-install-x86_64/lib64/wine/kernelbase.dll -batch -ex 'disassemble
GetCommandLineW'
Dump of assembler code for function GetCommandLineW:
0x000000007b0389c0 <+0>: mov 0x4de31(%rip),%rax # 0x7b0867f8
0x000000007b0389c7 <+7>: retq
End of assembler dump.
--- snip ---
The 64-bit variant looks good, but 32-bit is no-go. To have full control over
the generated code, small __i386__ and __x86_64__ assembly implementations for
A and W variant each are sufficient.
NOTE: the assembly for __x86_64__ needs to use RIP-relative addressing (PIE)
-> movq command_lineW(%rip), %rax
* encoding: [0x48,0x8b,0x05,A,A,A,A]
* kind: reloc_riprel_4byte_movq_load
With the small assembly functions in place, x64dbg and x32dbg were able to set
the debuggee command line via menu.
If assembly is not an option, consider changing A/W variant to be symmetrical
to make this bug report somewhat useful in the end (but still WONTFIX).
$ sha1sum snapshot_2020-02-11_01-07.zip
03fa18ffb1cbdd46a6b3c9b7e19332e7e2024edc snapshot_2020-02-11_01-07.zip
$ du -sh snapshot_2020-02-11_01-07.zip
31M snapshot_2020-02-11_01-07.zip
$ wine --version
wine-5.5
Regards
--
Do not reply to this email, post in Bugzilla using the
above URL to reply.
You are receiving this mail because:
You are watching all bug changes.
More information about the wine-bugs
mailing list