[PATCH v5 2/4] ntdll: Implement RtlWalkFrameChain() for x86 and x86_64.
Giovanni Mascellani
gmascellani at codeweavers.com
Wed Nov 3 07:49:28 CDT 2021
Signed-off-by: Giovanni Mascellani <gmascellani at codeweavers.com>
On 03/11/21 11:41, Paul Gofman wrote:
> Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
> ---
> v5:
> - also test for requested_count == frame_count + 1.
>
> dlls/ntdll/exception.c | 24 ++++++++-
> dlls/ntdll/ntdll.spec | 2 +-
> dlls/ntdll/signal_i386.c | 17 +++---
> dlls/ntdll/signal_x86_64.c | 7 +--
> dlls/ntdll/tests/exception.c | 83 +++++++++++++++++++++++++++++
> dlls/ntoskrnl.exe/ntoskrnl.exe.spec | 2 +-
> include/ddk/ntddk.h | 3 ++
> include/winnt.h | 2 +
> 8 files changed, 124 insertions(+), 16 deletions(-)
>
> diff --git a/dlls/ntdll/exception.c b/dlls/ntdll/exception.c
> index e956d8a722f..b020b829ae7 100644
> --- a/dlls/ntdll/exception.c
> +++ b/dlls/ntdll/exception.c
> @@ -30,6 +30,7 @@
> #define WIN32_NO_STATUS
> #include "windef.h"
> #include "winternl.h"
> +#include "ddk/ntddk.h"
> #include "ddk/wdm.h"
> #include "wine/exception.h"
> #include "wine/list.h"
> @@ -1074,6 +1075,25 @@ USHORT WINAPI RtlCaptureStackBackTrace( ULONG skip, ULONG count, PVOID *buffer,
> {
> ULONG ret;
>
> - ret = capture_stack_back_trace( skip, count, buffer, hash );
> - return min( ret, (USHORT)~0 );
> + ret = capture_stack_back_trace( skip, skip + count, buffer, hash );
> + if (ret < skip) return 0;
> + return min( ret - skip, (USHORT)~0 );
> +}
> +
> +
> +/**********************************************************************
> + * RtlWalkFrameChain (NTDLL.@)
> + */
> +ULONG WINAPI RtlWalkFrameChain( void **callers, ULONG count, ULONG skip )
> +{
> + TRACE( "callers %p, count %u, skip %#x.\n", callers, count, skip );
> +
> + if (skip & ~(0xff << RTL_STACK_WALKING_MODE_FRAMES_TO_SKIP_SHIFT))
> + {
> + WARN( "Invalid flags %#x.\n", skip );
> + return 0;
> + }
> + skip >>= RTL_STACK_WALKING_MODE_FRAMES_TO_SKIP_SHIFT;
> +
> + return capture_stack_back_trace( skip, count, callers, NULL );
> }
> diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
> index 13e65f65139..c54b2e205aa 100644
> --- a/dlls/ntdll/ntdll.spec
> +++ b/dlls/ntdll/ntdll.spec
> @@ -1073,7 +1073,7 @@
> @ stdcall RtlWakeAddressSingle(ptr)
> @ stdcall RtlWakeAllConditionVariable(ptr)
> @ stdcall RtlWakeConditionVariable(ptr)
> -@ stub RtlWalkFrameChain
> +@ stdcall RtlWalkFrameChain(ptr long long)
> @ stdcall RtlWalkHeap(long ptr)
> @ stdcall RtlWow64EnableFsRedirection(long)
> @ stdcall RtlWow64EnableFsRedirectionEx(long ptr)
> diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c
> index 26150ce877b..ff3e837c784 100644
> --- a/dlls/ntdll/signal_i386.c
> +++ b/dlls/ntdll/signal_i386.c
> @@ -488,27 +488,26 @@ ULONG WINAPI capture_stack_back_trace( ULONG skip, ULONG count, PVOID *buffer, U
> CONTEXT context;
> ULONG i;
> ULONG *frame;
> + ULONG num_entries = 0;
>
> ++skip;
> + ++count;
>
> RtlCaptureContext( &context );
> if (hash) *hash = 0;
> frame = (ULONG *)context.Ebp;
>
> - while (skip--)
> - {
> - if (!is_valid_frame( frame )) return 0;
> - frame = (ULONG *)*frame;
> - }
> -
> for (i = 0; i < count; i++)
> {
> if (!is_valid_frame( frame )) break;
> - buffer[i] = (void *)frame[1];
> - if (hash) *hash += frame[1];
> + if (i >= skip)
> + {
> + buffer[num_entries++] = (void *)frame[1];
> + if (hash) *hash += frame[1];
> + }
> frame = (ULONG *)*frame;
> }
> - return i;
> + return i ? i - 1 : 0;
> }
>
>
> diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c
> index 5f3c8f70208..4a9c7d4b9ff 100644
> --- a/dlls/ntdll/signal_x86_64.c
> +++ b/dlls/ntdll/signal_x86_64.c
> @@ -1504,16 +1504,17 @@ ULONG WINAPI capture_stack_back_trace( ULONG skip, ULONG count, PVOID *buffer, U
> TRACE( "(%u, %u, %p, %p)\n", skip, count, buffer, hash );
>
> ++skip;
> + ++count;
>
> RtlCaptureContext( &context );
> dispatch.TargetIp = 0;
> dispatch.ContextRecord = &context;
> dispatch.HistoryTable = &table;
> if (hash) *hash = 0;
> - for (i = 0; i < skip + count; i++)
> + for (i = 0; i < count; i++)
> {
> status = virtual_unwind( UNW_FLAG_NHANDLER, &dispatch, &context );
> - if (status != STATUS_SUCCESS) return i;
> + if (status != STATUS_SUCCESS) break;
>
> if (!dispatch.EstablisherFrame) break;
>
> @@ -1532,7 +1533,7 @@ ULONG WINAPI capture_stack_back_trace( ULONG skip, ULONG count, PVOID *buffer, U
> }
> if (hash && num_entries > 0) *hash = hash_pointers( buffer, num_entries );
> TRACE( "captured %u frames\n", num_entries );
> - return num_entries;
> + return i ? i - 1 : 0;
> }
>
>
> diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c
> index 6af68317732..6f3b08b5ea6 100644
> --- a/dlls/ntdll/tests/exception.c
> +++ b/dlls/ntdll/tests/exception.c
> @@ -28,6 +28,7 @@
> #include "winnt.h"
> #include "winreg.h"
> #include "winternl.h"
> +#include "ddk/ntddk.h"
> #include "ddk/wdm.h"
> #include "excpt.h"
> #include "wine/test.h"
> @@ -9113,6 +9114,87 @@ static void test_copy_context(void)
> }
> #endif
>
> +static void test_walk_stack(void)
> +{
> + ULONG count, expected, frame_count, requested_count, skip_count;
> + void *addrs[256], *addrs2[256];
> + void *start, *end;
> + unsigned int i, j;
> +
> + memset(addrs, 0xcc, sizeof(addrs));
> + memset(addrs2, 0xcc, sizeof(addrs2));
> +
> + frame_count = RtlCaptureStackBackTrace(0, ARRAY_SIZE(addrs), addrs, NULL);
> + count = RtlWalkFrameChain(addrs2, ARRAY_SIZE(addrs2), 0);
> +
> + trace("frame_count %u.\n", frame_count);
> +
> + ok(frame_count > 1, "Got zero frame_count.\n");
> + ok(count == frame_count, "Got unexpected frame_count %u, count %u.\n", frame_count, count);
> +
> + start = test_walk_stack;
> + end = (BYTE *)start + 0x1000;
> + todo_wine_if(sizeof(void *) == 4)
> + ok(addrs[0] >= start && addrs[0] < end, "Address is not inside test function, start %p, end %p, addr %p.\n",
> + start, end, addrs[0]);
> + todo_wine_if(sizeof(void *) == 4)
> + ok(addrs2[0] >= start && addrs2[0] < end, "Address is not inside test function, start %p, end %p, addr %p.\n",
> + start, end, addrs2[0]);
> +
> + for (i = 1; i < frame_count; ++i)
> + {
> + ok(addrs[i] == addrs2[i], "i %u, addresses do not match, %p vs %p.\n", i, addrs[i], addrs2[i]);
> + }
> + todo_wine ok(!!addrs[frame_count - 1], "Expected non-NULL last address.\n");
> +
> + for (requested_count = frame_count - 1; requested_count <= frame_count + 1; ++requested_count)
> + {
> + for (i = 0; i < 32; ++i)
> + {
> + winetest_push_context("requested_count %u, i %u", requested_count, i);
> + skip_count = (1 << i) >> 8;
> +
> + if (i < RTL_STACK_WALKING_MODE_FRAMES_TO_SKIP_SHIFT
> + || i >= RTL_STACK_WALKING_MODE_FRAMES_TO_SKIP_SHIFT + 8)
> + expected = 0;
> + else
> + expected = min(frame_count, requested_count);
> +
> + memset(addrs2, 0xcc, sizeof(addrs2));
> + count = RtlWalkFrameChain(addrs2, requested_count, 1 << i);
> + ok(count == expected, "Got unexpected frame_count %u, expected %u.\n", count, expected);
> +
> + if (skip_count < count)
> + count -= skip_count;
> + else
> + count = 0;
> +
> + for (j = 0; j < count; ++j)
> + ok( addrs2[j] != (void *)(ULONG_PTR)0xcccccccccccccccc, "Address is not set, j %u.\n", j );
> + for (; j < ARRAY_SIZE(addrs2); ++j)
> + ok( addrs2[j] == (void *)(ULONG_PTR)0xcccccccccccccccc, "Address is set, j %u.\n", j );
> +
> + if (!count)
> + {
> + winetest_pop_context();
> + continue;
> + }
> +
> + memset(addrs, 0xcc, sizeof(addrs));
> + expected = skip_count > frame_count ? 0 : min(frame_count - skip_count, requested_count);
> + count = RtlCaptureStackBackTrace(skip_count, requested_count, addrs, NULL);
> + ok(count == expected, "Got unexpected frame_count %u, expected %u. i %u.\n", count, expected, i);
> +
> + count = min(frame_count, requested_count) - skip_count;
> + for (j = 0; j < count; ++j)
> + {
> + ok(addrs[j] == addrs2[j], "Addresses do not match, j %u, %p, %p.\n", j, addrs[j], addrs2[j]);
> + }
> + winetest_pop_context();
> + }
> + }
> +}
> +
> START_TEST(exception)
> {
> HMODULE hntdll = GetModuleHandleA("ntdll.dll");
> @@ -9339,5 +9421,6 @@ START_TEST(exception)
> test_suspend_thread();
> test_suspend_process();
> test_unload_trace();
> + test_walk_stack();
> VirtualFree(code_mem, 0, MEM_RELEASE);
> }
> diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
> index 0208e2f633f..b94e58ccb26 100644
> --- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
> +++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
> @@ -1300,7 +1300,7 @@
> @ stdcall RtlVerifyVersionInfo(ptr long int64)
> @ stdcall -arch=arm64,x86_64 RtlVirtualUnwind(long long long ptr ptr ptr ptr ptr)
> @ stub RtlVolumeDeviceToDosName
> -@ stub RtlWalkFrameChain
> +@ stdcall RtlWalkFrameChain(ptr long long)
> @ stdcall RtlWriteRegistryValue(long ptr ptr long ptr long)
> @ stub RtlZeroHeap
> @ stdcall RtlZeroMemory(ptr long)
> diff --git a/include/ddk/ntddk.h b/include/ddk/ntddk.h
> index 41ad3d721bd..ce558139aa6 100644
> --- a/include/ddk/ntddk.h
> +++ b/include/ddk/ntddk.h
> @@ -245,6 +245,8 @@ typedef EXPAND_STACK_CALLOUT *PEXPAND_STACK_CALLOUT;
> typedef GUID UUID;
> #endif
>
> +#define RTL_STACK_WALKING_MODE_FRAMES_TO_SKIP_SHIFT 8
> +
> NTSTATUS WINAPI ExUuidCreate(UUID*);
> NTSTATUS WINAPI IoQueryDeviceDescription(PINTERFACE_TYPE,PULONG,PCONFIGURATION_TYPE,PULONG,
> PCONFIGURATION_TYPE,PULONG,PIO_QUERY_DEVICE_ROUTINE,PVOID);
> @@ -267,5 +269,6 @@ NTSTATUS WINAPI PsSetCreateThreadNotifyRoutine(PCREATE_THREAD_NOTIFY_ROUTINE);
> NTSTATUS WINAPI PsSetLoadImageNotifyRoutine(PLOAD_IMAGE_NOTIFY_ROUTINE);
> void WINAPI RtlInitializeGenericTableAvl(PRTL_AVL_TABLE,PRTL_AVL_COMPARE_ROUTINE,PRTL_AVL_ALLOCATE_ROUTINE, PRTL_AVL_FREE_ROUTINE,void *);
> void WINAPI RtlInsertElementGenericTableAvl(PRTL_AVL_TABLE,void *,ULONG,BOOL*);
> +ULONG WINAPI RtlWalkFrameChain(void **,ULONG,ULONG);
>
> #endif
> diff --git a/include/winnt.h b/include/winnt.h
> index ef731e29c52..eb1bd165720 100644
> --- a/include/winnt.h
> +++ b/include/winnt.h
> @@ -1840,6 +1840,8 @@ NTSYSAPI PVOID WINAPI RtlVirtualUnwind(DWORD,ULONG_PTR,ULONG_PTR,RUNTIME_FUNCT
>
> #endif
>
> +NTSYSAPI USHORT WINAPI RtlCaptureStackBackTrace(ULONG,ULONG,void **,ULONG *);
> +
> /*
> * Product types
> */
>
More information about the wine-devel
mailing list