Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
3316f590
Commit
3316f590
authored
Mar 04, 2024
by
Eric Pouech
Committed by
Alexandre Julliard
Mar 13, 2024
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
dbghelp/tests: Add tests about generated memory chunks.
Signed-off-by:
Eric Pouech
<
epouech@codeweavers.com
>
parent
9620340b
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
351 additions
and
0 deletions
+351
-0
minidump.c
dlls/dbghelp/tests/minidump.c
+351
-0
No files found.
dlls/dbghelp/tests/minidump.c
View file @
3316f590
...
...
@@ -158,7 +158,358 @@ static void test_minidump_contents(void)
}
}
static
void
minidump_check_nostream
(
void
*
data
,
MINIDUMP_STREAM_TYPE
stream_type
)
{
void
*
stream
;
BOOL
ret
;
ret
=
MiniDumpReadDumpStream
(
data
,
stream_type
,
NULL
,
(
void
**
)
&
stream
,
NULL
);
ok
(
!
ret
,
"Unexpected stream %u
\n
"
,
stream_type
);
}
static
void
minidump_check_pid
(
void
*
data
,
DWORD
pid
)
{
MINIDUMP_MISC_INFO
*
misc_info
;
BOOL
ret
;
ret
=
MiniDumpReadDumpStream
(
data
,
MiscInfoStream
,
NULL
,
(
void
**
)
&
misc_info
,
NULL
);
ok
(
ret
&&
misc_info
,
"Couldn't find misc-info stream
\n
"
);
ok
(
misc_info
->
Flags1
&
misc_info
->
Flags1
&
MINIDUMP_MISC1_PROCESS_ID
,
"No process-id in misc_info
\n
"
);
ok
(
pid
==
misc_info
->
ProcessId
,
"Unexpected process id
\n
"
);
}
static
unsigned
minidump_get_number_of_threads
(
void
*
data
)
{
MINIDUMP_THREAD_LIST
*
thread_list
;
BOOL
ret
;
ret
=
MiniDumpReadDumpStream
(
data
,
ThreadListStream
,
NULL
,
(
void
**
)
&
thread_list
,
NULL
);
ok
(
ret
&&
thread_list
,
"Couldn't find thread-list stream
\n
"
);
return
thread_list
->
NumberOfThreads
;
}
static
void
minidump_check_threads
(
void
*
data
)
{
MINIDUMP_THREAD_LIST
*
thread_list
;
int
i
;
BOOL
ret
;
ret
=
MiniDumpReadDumpStream
(
data
,
ThreadListStream
,
NULL
,
(
void
**
)
&
thread_list
,
NULL
);
ok
(
ret
&&
thread_list
,
"Couldn't find thread-list stream
\n
"
);
for
(
i
=
0
;
i
<
thread_list
->
NumberOfThreads
;
i
++
)
{
const
MINIDUMP_THREAD
*
thread
=
&
thread_list
->
Threads
[
i
];
const
CONTEXT
*
ctx
;
ok
(
thread
->
SuspendCount
==
0
,
"Unexpected value
\n
"
);
todo_wine
ok
(
thread
->
Stack
.
StartOfMemoryRange
,
"Unexpected value
\n
"
);
todo_wine
ok
(
thread
->
Stack
.
Memory
.
DataSize
,
"Unexpected value
\n
"
);
ok
(
thread
->
Teb
,
"Unexpected value
\n
"
);
todo_wine
ok
(
thread
->
ThreadContext
.
DataSize
>=
sizeof
(
CONTEXT
),
"Unexpected value
\n
"
);
ctx
=
RVA_TO_ADDR
(
data
,
thread
->
ThreadContext
.
Rva
);
todo_wine
ok
((
ctx
->
ContextFlags
&
CONTEXT_ALL
)
==
CONTEXT_ALL
,
"Unexpected value
\n
"
);
}
}
static
void
minidump_check_module
(
void
*
data
,
const
WCHAR
*
name
,
DWORD64
base
)
{
MINIDUMP_MODULE_LIST
*
module_list
;
size_t
namelen
=
wcslen
(
name
);
int
i
;
BOOL
ret
;
ret
=
MiniDumpReadDumpStream
(
data
,
ModuleListStream
,
NULL
,
(
void
**
)
&
module_list
,
NULL
);
ok
(
ret
&&
module_list
,
"Couldn't find module-list stream
\n
"
);
ok
(
module_list
->
NumberOfModules
>
3
,
"Unexpected number of modules
\n
"
);
for
(
i
=
0
;
i
<
module_list
->
NumberOfModules
;
i
++
)
{
MINIDUMP_MODULE
*
module
=
&
module_list
->
Modules
[
i
];
WCHAR
*
ptr
;
MINIDUMP_STRING
*
string
=
RVA_TO_ADDR
(
data
,
module
->
ModuleNameRva
);
for
(
ptr
=
string
->
Buffer
+
string
->
Length
/
sizeof
(
WCHAR
)
-
1
;
ptr
>=
string
->
Buffer
&&
*
ptr
!=
L'\\'
;
ptr
--
)
{}
ptr
++
;
if
(
ptr
+
namelen
==
string
->
Buffer
+
string
->
Length
/
sizeof
(
WCHAR
)
&&
!
wcsnicmp
(
name
,
ptr
,
namelen
)
&&
module
->
BaseOfImage
==
base
)
break
;
}
ok
(
i
<
module_list
->
NumberOfModules
,
"Couldn't find module %ls in minidump
\n
"
,
name
);
}
struct
memory_description
{
/* MD_SECTION, MD_DIRECTORY can be present at the same time */
/* MD_UNMAPPED: some DLLs are present when creating the minidump, but are unloaded afterwards (native) */
enum
{
MD_NONE
=
0
,
MD_UNMAPPED
=
1
,
MD_PE_HEADER
=
2
,
MD_STACK
=
3
,
MD_SECTION
=
4
,
MD_DIRECTORY
=
8
,
MD_UNWIND
=
16
}
kind
;
unsigned
id
;
/* MD_STACK: thread index
* MD_DIRECTORY: directory index
* MD_UNWIND: function index in function table
*/
const
char
*
name
;
/* MD_SECTION: section name */
};
static
struct
memory_description
minidump_get_memory_description
(
void
*
data
,
DWORD64
addr
)
{
const
BYTE
*
addr_ptr
=
(
void
*
)(
ULONG_PTR
)
addr
;
MINIDUMP_MODULE_LIST
*
module_list
;
MINIDUMP_THREAD_LIST
*
thread_list
;
struct
memory_description
md
=
{.
kind
=
MD_NONE
};
BOOL
ret
;
int
i
,
j
,
dir
;
ret
=
MiniDumpReadDumpStream
(
data
,
ModuleListStream
,
NULL
,
(
void
**
)
&
module_list
,
NULL
);
ok
(
ret
&&
module_list
,
"Couldn't find module-list stream
\n
"
);
for
(
i
=
0
;
i
<
module_list
->
NumberOfModules
;
i
++
)
{
MINIDUMP_MODULE
*
module
=
&
module_list
->
Modules
[
i
];
MINIDUMP_STRING
*
string
=
RVA_TO_ADDR
(
data
,
module
->
ModuleNameRva
);
if
(
module
->
BaseOfImage
<=
addr
&&
addr
<
module
->
BaseOfImage
+
module
->
SizeOfImage
)
{
HMODULE
module_handle
;
WCHAR
*
module_name
;
size_t
module_name_len
=
string
->
Length
/
sizeof
(
WCHAR
);
IMAGE_NT_HEADERS
*
nthdr
;
module_name
=
malloc
((
module_name_len
+
1
)
*
sizeof
(
WCHAR
));
if
(
!
module_name
)
continue
;
memcpy
(
module_name
,
string
->
Buffer
,
module_name_len
*
sizeof
(
WCHAR
));
module_name
[
module_name_len
]
=
L'\0'
;
module_handle
=
GetModuleHandleW
(
module_name
);
if
((
nthdr
=
RtlImageNtHeader
(
module_handle
)))
{
for
(
dir
=
0
;
dir
<
IMAGE_NUMBEROF_DIRECTORY_ENTRIES
;
dir
++
)
{
ULONG
dir_size
;
const
BYTE
*
dir_start
=
RtlImageDirectoryEntryToData
(
module_handle
,
TRUE
,
dir
,
&
dir_size
);
if
(
dir_start
&&
dir_start
<=
addr_ptr
&&
addr_ptr
<
dir_start
+
dir_size
)
{
md
.
kind
|=
MD_DIRECTORY
;
md
.
id
=
dir
;
}
switch
(
dir
)
{
case
IMAGE_DIRECTORY_ENTRY_EXCEPTION
:
if
(
nthdr
->
FileHeader
.
Machine
==
IMAGE_FILE_MACHINE_AMD64
)
{
const
IMAGE_AMD64_RUNTIME_FUNCTION_ENTRY
*
func
;
for
(
func
=
(
const
void
*
)
dir_start
;
func
<
(
const
IMAGE_AMD64_RUNTIME_FUNCTION_ENTRY
*
)(
dir_start
+
dir_size
);
func
++
)
{
if
(
RtlImageRvaToVa
(
nthdr
,
module_handle
,
func
->
UnwindData
,
NULL
)
==
addr_ptr
)
{
md
.
kind
=
MD_UNWIND
;
md
.
id
=
func
-
(
const
IMAGE_AMD64_RUNTIME_FUNCTION_ENTRY
*
)
dir_start
;
}
}
}
break
;
/* FIXME handle more areas: import/export tables... */
}
}
if
(
addr
<
(
DWORD_PTR
)(
IMAGE_FIRST_SECTION
(
nthdr
)
+
nthdr
->
FileHeader
.
NumberOfSections
))
{
md
.
kind
=
MD_PE_HEADER
;
}
for
(
j
=
0
;
j
<
nthdr
->
FileHeader
.
NumberOfSections
;
j
++
)
{
IMAGE_SECTION_HEADER
*
section
=
IMAGE_FIRST_SECTION
(
nthdr
)
+
j
;
const
BYTE
*
section_start
=
(
BYTE
*
)
module_handle
+
section
->
VirtualAddress
;
if
(
section_start
<=
addr_ptr
&&
addr_ptr
<
section_start
+
section
->
Misc
.
VirtualSize
)
{
md
.
kind
|=
MD_SECTION
;
md
.
name
=
(
const
char
*
)
section
->
Name
;
}
}
}
else
md
.
kind
=
MD_UNMAPPED
;
free
(
module_name
);
return
md
;
}
}
ret
=
MiniDumpReadDumpStream
(
data
,
ThreadListStream
,
NULL
,
(
void
**
)
&
thread_list
,
NULL
);
ok
(
ret
&&
thread_list
,
"Couldn't find thread-list stream
\n
"
);
for
(
i
=
0
;
i
<
thread_list
->
NumberOfThreads
;
i
++
)
{
MINIDUMP_THREAD
*
thread
=
&
thread_list
->
Threads
[
i
];
if
(
thread
->
Stack
.
StartOfMemoryRange
<=
addr
&&
addr
<
thread
->
Stack
.
StartOfMemoryRange
+
thread
->
Stack
.
Memory
.
DataSize
)
{
md
.
kind
=
MD_STACK
;
md
.
id
=
i
;
return
md
;
}
}
return
md
;
}
/* modules could be load/unloaded when generating the minidump, so count the number of available modules */
static
unsigned
minidump_get_number_of_available_modules
(
void
*
data
)
{
MINIDUMP_MODULE_LIST
*
module_list
;
unsigned
num_modules
=
0
;
BOOL
ret
;
int
i
;
ret
=
MiniDumpReadDumpStream
(
data
,
ModuleListStream
,
NULL
,
(
void
**
)
&
module_list
,
NULL
);
ok
(
ret
&&
module_list
,
"Couldn't find module-list stream
\n
"
);
for
(
i
=
0
;
i
<
module_list
->
NumberOfModules
;
i
++
)
{
struct
memory_description
md
;
md
=
minidump_get_memory_description
(
data
,
module_list
->
Modules
[
i
].
BaseOfImage
);
if
(
md
.
kind
!=
MD_UNMAPPED
)
num_modules
++
;
}
return
num_modules
;
}
struct
memory_walker
{
unsigned
num_unknown
;
/* number of unknown memory locations */
unsigned
num_thread_stack
;
/* number of locations inside a thread stack */
unsigned
num_directories
[
IMAGE_NUMBEROF_DIRECTORY_ENTRIES
];
/* number of locations in side the directories' content */
unsigned
num_text
;
/* number of locations inside .text section */
unsigned
num_unwind_info
;
};
static
void
minidump_walk_memory
(
void
*
data
,
struct
memory_walker
*
walker
)
{
MINIDUMP_MEMORY_LIST
*
memory_list
;
BOOL
ret
;
int
i
;
ret
=
MiniDumpReadDumpStream
(
data
,
MemoryListStream
,
NULL
,
(
void
**
)
&
memory_list
,
NULL
);
ok
(
ret
&&
memory_list
,
"Couldn't find memory-list stream
\n
"
);
for
(
i
=
0
;
i
<
memory_list
->
NumberOfMemoryRanges
;
i
++
)
{
MINIDUMP_MEMORY_DESCRIPTOR
*
desc
=
&
memory_list
->
MemoryRanges
[
i
];
struct
memory_description
md
;
md
=
minidump_get_memory_description
(
data
,
desc
->
StartOfMemoryRange
);
switch
((
int
)
md
.
kind
)
{
case
MD_NONE
:
walker
->
num_unknown
++
;
break
;
case
MD_UNMAPPED
:
/* nothing we can do here */
break
;
case
MD_STACK
:
walker
->
num_thread_stack
++
;
break
;
case
MD_SECTION
|
MD_UNWIND
:
walker
->
num_unwind_info
++
;
break
;
case
MD_PE_HEADER
:
/* FIXME may change with MiniDumpWithModuleHeaders */
ok
(
0
,
"Unexpected memory block in PE header
\n
"
);
break
;
case
MD_SECTION
:
case
MD_SECTION
|
MD_DIRECTORY
:
if
(
!
strcmp
(
md
.
name
,
".text"
))
walker
->
num_text
++
;
if
(
md
.
kind
&
MD_DIRECTORY
)
{
ok
(
md
.
id
<
ARRAY_SIZE
(
walker
->
num_directories
),
"Out of bounds index
\n
"
);
walker
->
num_directories
[
md
.
id
]
++
;
}
break
;
default:
ok
(
0
,
"Unexpected memory description kind: %x
\n
"
,
md
.
kind
);
break
;
}
}
}
static
void
test_current_process
(
void
)
{
static
const
struct
{
MINIDUMP_TYPE
dump_type
;
}
process_tests
[]
=
{
{
MiniDumpNormal
/* = 0 */
},
{
MiniDumpWithCodeSegs
},
{
MiniDumpWithDataSegs
},
{
MiniDumpWithThreadInfo
},
/* requires more work
{ MiniDumpWithModuleHeaders },
{ MiniDumpWithProcessThreadData },
*/
};
struct
memory_walker
walker
;
struct
memory_description
md
,
md2
;
unsigned
num_available_modules
,
num_threads
;
void
*
data
;
BOOL
ret
;
int
i
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
process_tests
);
i
++
)
{
winetest_push_context
(
"process_tests[%d]"
,
i
);
minidump_write
(
GetCurrentProcess
(),
L"foo.mdmp"
,
process_tests
[
i
].
dump_type
,
FALSE
);
data
=
minidump_open_for_read
(
"foo.mdmp"
);
num_threads
=
minidump_get_number_of_threads
(
data
);
ok
(
num_threads
>
0
,
"Unexpected number of threads
\n
"
);
minidump_check_threads
(
data
);
md
=
minidump_get_memory_description
(
data
,
(
DWORD_PTR
)
&
i
);
todo_wine
ok
(
md
.
kind
==
MD_STACK
,
"Couldn't find automatic variable
\n
"
);
md2
=
minidump_get_memory_description
(
data
,
(
DWORD_PTR
)
NtCurrentTeb
()
->
Tib
.
StackBase
-
sizeof
(
void
*
));
todo_wine
ok
(
md2
.
kind
==
MD_STACK
,
"Couldn't find stack bottom
\n
"
);
ok
(
md
.
id
==
md2
.
id
,
"Should be on same stack
\n
"
);
minidump_check_pid
(
data
,
GetCurrentProcessId
());
num_available_modules
=
minidump_get_number_of_available_modules
(
data
);
#define CHECK_MODULE(s) minidump_check_module(data, s, (DWORD64)(DWORD_PTR)GetModuleHandleW(s))
CHECK_MODULE
(
L"ntdll.dll"
);
CHECK_MODULE
(
L"kernelbase.dll"
);
CHECK_MODULE
(
L"kernel32.dll"
);
CHECK_MODULE
(
L"dbghelp.dll"
);
#undef CHECK_MODULE
memset
(
&
walker
,
0
,
sizeof
(
walker
));
minidump_walk_memory
(
data
,
&
walker
);
ok
(
walker
.
num_unknown
==
0
,
"unexpected unknown memory locations
\n
"
);
todo_wine
ok
(
walker
.
num_thread_stack
==
num_threads
,
"Unexpected number of stacks
\n
"
);
if
(
sizeof
(
void
*
)
>
4
&&
(
process_tests
[
i
].
dump_type
&
MiniDumpWithModuleHeaders
))
ok
(
walker
.
num_directories
[
IMAGE_DIRECTORY_ENTRY_EXCEPTION
]
>
0
,
"expected unwind information
\n
"
);
else
ok
(
walker
.
num_directories
[
IMAGE_DIRECTORY_ENTRY_EXCEPTION
]
==
0
,
"unexpected unwind information
\n
"
);
if
(
process_tests
[
i
].
dump_type
&
MiniDumpWithCodeSegs
)
{
todo_wine
ok
(
walker
.
num_text
>=
num_available_modules
||
/* win7 & 8 report one less */
broken
(
walker
.
num_text
+
1
>=
num_available_modules
),
"expected code segments %u %u
\n
"
,
walker
.
num_text
,
num_available_modules
);
}
else
/* native embeds some elements in code segment from ntdll */
ok
(
walker
.
num_text
<
5
,
"unexpected code segments %u %u
\n
"
,
walker
.
num_text
,
num_available_modules
);
todo_wine_if
(
RtlImageNtHeader
(
GetModuleHandleW
(
NULL
))
->
FileHeader
.
Machine
==
IMAGE_FILE_MACHINE_AMD64
)
ok
(
walker
.
num_unwind_info
==
0
,
"unexpected unwind info %u
\n
"
,
walker
.
num_unwind_info
);
minidump_check_nostream
(
data
,
ExceptionStream
);
minidump_close_for_read
(
data
);
ret
=
DeleteFileA
(
"foo.mdmp"
);
ok
(
ret
,
"Couldn't delete file
\n
"
);
winetest_pop_context
();
}
}
START_TEST
(
minidump
)
{
test_minidump_contents
();
test_current_process
();
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment