11// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
22// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2022 Datadog, Inc.
33
4+ #include " gtest/gtest.h"
5+
6+ #include " unknwn.h"
7+
8+ const IID IID_IUnknown = {0x00000000 ,
9+ 0x0000 ,
10+ 0x0000 ,
11+ {0xC0 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x46 }};
12+
13+ #include " CrashReporting.h"
14+
415#ifdef _WIN32
516
617#include " resource.h"
7- #include " gtest/gtest.h"
818#include < string_view>
919#include < windows.h>
1020#include < vector>
@@ -130,5 +140,107 @@ TEST(CrashReportingTest, ExtractPdbSignaturePE64)
130140 // | Pdb signature |Age|
131141 ASSERT_STRCASEEQ (buildIdStr.data (), " C465AFCDBDBC58A0100995839A0E4C271" );
132142}
143+ #endif
133144
134- #endif
145+ TEST (CrashReportingTest, CheckMergedCallstackOnAlternateStackWithHighAddresses)
146+ {
147+ std::vector<StackFrame> nativeFrames = {
148+ // next two frames simulate signal handler runnin on alternate stack
149+ {0x7F4DECDF2BC0 , 0x7F478000ACE0 , " __GI___wait4" , 0x7F4DECDF2BC0 , 0x7F4DECD1F000 , false , " " },
150+ {0x7F4DECB882F0 , 0x7F478000AD10 , " PROCCreateCrashDump(std::vector<char const*, std::allocator<char const*> >&, char*, int, bool)" , 0x7F4DECB882F0 , 0x7F4DEC514000 , false , " " },
151+ // below managed before the signal handler
152+ {0x7F4D778E1A7D , 0x7F476CC3E9D0 , " /memfd:doublemapper (deleted)!<unknown>+b84da7d" , 0x7F4D778E1A7D , 0x7F4D6C094000 , false , " " },
153+ {0x7F4D76593D2A , 0x7F476CC3EA10 , " /memfd:doublemapper (deleted)!<unknown>+a4ffd2a" , 0x7F4D76593D2A , 0x7F4D6C094000 , false , " " },
154+ {0x7F4D6D7D3924 , 0x7F476CC3EA90 , " /usr/share/dotnet/shared/Microsoft.NETCore.App/9.0.10/System.Private.CoreLib.dll!<unknown>+5e370b924" , 0x7F4D6D7D3924 , 0x7F478A0C8000 , false , " " },
155+ };
156+
157+ std::vector<StackFrame> managedFrames = {
158+ {0x7F4D778E1A7D , 0x7F476CC3E9D0 , " System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.Threading.Tasks.VoidTaskResult>+AsyncStateMachineBox<Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol+<ProcessRequests>d__238<System.__Canon>>.MoveNext" , 0x7F4D778E1A7D , 0x7F4D6C094000 , false , " " },
159+ {0x7F4D76593D2A , 0x7F476CC3EA10 , " System.Private.CoreLib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch" , 0x7F4D76593D2A , 0x7F4D6C094000 , false , " " },
160+ {0x7F4D6D7D3924 , 0x7F476CC3EA90 , " System.Private.CoreLib.dll!System.Threading.PortableThreadPool+WorkerThread.WorkerThreadStart" , 0x7F4D6D7D3924 , 0x7F478A0C8000 , false , " " },
161+ };
162+
163+ // MergeFrames returns the frames in the order of the sp addresses
164+ auto mergedFrames = CrashReporting::MergeFrames (nativeFrames, managedFrames);
165+
166+ std::vector<std::string> expectedFunctions = {
167+ " System.Private.CoreLib.dll!System.Threading.PortableThreadPool+WorkerThread.WorkerThreadStart" ,
168+ " System.Private.CoreLib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch" ,
169+ " System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.Threading.Tasks.VoidTaskResult>+AsyncStateMachineBox<Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol+<ProcessRequests>d__238<System.__Canon>>.MoveNext" ,
170+ " PROCCreateCrashDump(std::vector<char const*, std::allocator<char const*> >&, char*, int, bool)" ,
171+ " __GI___wait4" ,
172+ };
173+
174+ ASSERT_EQ (mergedFrames.size (), expectedFunctions.size ());
175+ for (size_t i = 0 ; i < mergedFrames.size (); i++)
176+ {
177+ ASSERT_EQ (mergedFrames[i].method , expectedFunctions[i]);
178+ }
179+ }
180+
181+ TEST (CrashReportingTest, CheckMergedCallstackOnAlternateStackWithLowAddresses)
182+ {
183+ std::vector<StackFrame> nativeFrames = {
184+ // next two frames simulate signal handler runnin on alternate stack
185+ {0x7F4DECDF2BC0 , 0x7F470000ACE0 , " __GI___wait4" , 0x7F4DECDF2BC0 , 0x7F4DECD1F000 , false , " " },
186+ {0x7F4DECB882F0 , 0x7F470000AD10 , " PROCCreateCrashDump(std::vector<char const*, std::allocator<char const*> >&, char*, int, bool)" , 0x7F4DECB882F0 , 0x7F4DEC514000 , false , " " },
187+ // below managed before the signal handler
188+ {0x7F4D778E1A7D , 0x7F476CC3E9D0 , " /memfd:doublemapper (deleted)!<unknown>+b84da7d" , 0x7F4D778E1A7D , 0x7F4D6C094000 , false , " " },
189+ {0x7F4D76593D2A , 0x7F476CC3EA10 , " /memfd:doublemapper (deleted)!<unknown>+a4ffd2a" , 0x7F4D76593D2A , 0x7F4D6C094000 , false , " " },
190+ {0x7F4D6D7D3924 , 0x7F476CC3EA90 , " /usr/share/dotnet/shared/Microsoft.NETCore.App/9.0.10/System.Private.CoreLib.dll!<unknown>+5e370b924" , 0x7F4D6D7D3924 , 0x7F478A0C8000 , false , " " },
191+ };
192+
193+ std::vector<StackFrame> managedFrames = {
194+ {0x7F4D778E1A7D , 0x7F476CC3E9D0 , " System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.Threading.Tasks.VoidTaskResult>+AsyncStateMachineBox<Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol+<ProcessRequests>d__238<System.__Canon>>.MoveNext" , 0x7F4D778E1A7D , 0x7F4D6C094000 , false , " " },
195+ {0x7F4D76593D2A , 0x7F476CC3EA10 , " System.Private.CoreLib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch" , 0x7F4D76593D2A , 0x7F4D6C094000 , false , " " },
196+ {0x7F4D6D7D3924 , 0x7F476CC3EA90 , " System.Private.CoreLib.dll!System.Threading.PortableThreadPool+WorkerThread.WorkerThreadStart" , 0x7F4D6D7D3924 , 0x7F478A0C8000 , false , " " },
197+ };
198+
199+ auto mergedFrames = CrashReporting::MergeFrames (nativeFrames, managedFrames);
200+
201+ std::vector<std::string> expectedFunctions = {
202+ " System.Private.CoreLib.dll!System.Threading.PortableThreadPool+WorkerThread.WorkerThreadStart" ,
203+ " System.Private.CoreLib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch" ,
204+ " System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.Threading.Tasks.VoidTaskResult>+AsyncStateMachineBox<Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol+<ProcessRequests>d__238<System.__Canon>>.MoveNext" ,
205+ " PROCCreateCrashDump(std::vector<char const*, std::allocator<char const*> >&, char*, int, bool)" ,
206+ " __GI___wait4" ,
207+ };
208+
209+ ASSERT_EQ (mergedFrames.size (), expectedFunctions.size ());
210+ for (size_t i = 0 ; i < mergedFrames.size (); i++)
211+ {
212+ ASSERT_EQ (mergedFrames[i].method , expectedFunctions[i]);
213+ }
214+ }
215+
216+ TEST (CrashReportingTest, CheckMergedCallstackButNoFusionBetweenNativeAndManaged)
217+ {
218+ std::vector<StackFrame> nativeFrames = {
219+ {0x7F4DEC9B2982 , 0x7F476CC39E90 , " MethodTable::GetFlag(MethodTable::WFLAGS_HIGH_ENUM) const" , 0x7F4D778E1A7D , 0x7F4D6C094000 , false , " " },
220+ {0x7F4DEC9B3233 , 0x7F476CC39F10 , " WKS::gc_heap::mark_object_simple(unsigned char**)" , 0x7F4D76593D2A , 0x7F4D6C094000 , false , " " },
221+ {0x7F4DEC9B7929 , 0x7F476CC39F70 , " WKS::gc_heap::mark_through_cards_helper(unsigned char**, unsigned long&, unsigned long&, void (*)(unsigned char**), unsigned char*, unsigned char*, int, int)" , 0x7F4D6D7D3924 , 0x7F478A0C8000 , false , " " },
222+ };
223+
224+ std::vector<StackFrame> managedFrames = {
225+ {0x7F4D778E1A7D , 0x7F476CC3E9D0 , " System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.Threading.Tasks.VoidTaskResult>+AsyncStateMachineBox<Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol+<ProcessRequests>d__238<System.__Canon>>.MoveNext" , 0x7F4D778E1A7D , 0x7F4D6C094000 , false , " " },
226+ {0x7F4D76593D2A , 0x7F476CC3EA10 , " System.Private.CoreLib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch" , 0x7F4D76593D2A , 0x7F4D6C094000 , false , " " },
227+ {0x7F4D6D7D3924 , 0x7F476CC3EA90 , " System.Private.CoreLib.dll!System.Threading.PortableThreadPool+WorkerThread.WorkerThreadStart" , 0x7F4D6D7D3924 , 0x7F478A0C8000 , false , " " },
228+ };
229+
230+ auto mergedFrames = CrashReporting::MergeFrames (nativeFrames, managedFrames);
231+
232+ std::vector<std::string> expectedFunctions = {
233+ " System.Private.CoreLib.dll!System.Threading.PortableThreadPool+WorkerThread.WorkerThreadStart" ,
234+ " System.Private.CoreLib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch" ,
235+ " System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.Threading.Tasks.VoidTaskResult>+AsyncStateMachineBox<Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol+<ProcessRequests>d__238<System.__Canon>>.MoveNext" ,
236+ " WKS::gc_heap::mark_through_cards_helper(unsigned char**, unsigned long&, unsigned long&, void (*)(unsigned char**), unsigned char*, unsigned char*, int, int)" ,
237+ " WKS::gc_heap::mark_object_simple(unsigned char**)" ,
238+ " MethodTable::GetFlag(MethodTable::WFLAGS_HIGH_ENUM) const" ,
239+ };
240+
241+ ASSERT_EQ (mergedFrames.size (), expectedFunctions.size ());
242+ for (size_t i = 0 ; i < mergedFrames.size (); i++)
243+ {
244+ ASSERT_EQ (mergedFrames[i].method , expectedFunctions[i]);
245+ }
246+ }
0 commit comments