1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_PROFILER_WIN32_STACK_FRAME_UNWINDER_H_
6 #define BASE_PROFILER_WIN32_STACK_FRAME_UNWINDER_H_
7 
8 #include <windows.h>
9 
10 #include <memory>
11 
12 #include "base/base_export.h"
13 #include "base/macros.h"
14 #include "base/win/scoped_handle.h"
15 
16 namespace base {
17 
18 #if !defined(_WIN64)
19 // Allows code to compile for x86. Actual support for x86 will require either
20 // refactoring these interfaces or separate architecture-specific interfaces.
21 struct RUNTIME_FUNCTION {
22   DWORD BeginAddress;
23   DWORD EndAddress;
24 };
25 using PRUNTIME_FUNCTION = RUNTIME_FUNCTION*;
26 #endif  // !defined(_WIN64)
27 
28 // Traits class to adapt GenericScopedHandle for HMODULES.
29 class ModuleHandleTraits : public win::HandleTraits {
30  public:
31   using Handle = HMODULE;
32 
33   static bool BASE_EXPORT CloseHandle(HMODULE handle);
34   static bool BASE_EXPORT IsHandleValid(HMODULE handle);
35   static HMODULE BASE_EXPORT NullHandle();
36 
37   BASE_EXPORT static const HMODULE kNonNullModuleForTesting;
38 
39  private:
40   DISALLOW_IMPLICIT_CONSTRUCTORS(ModuleHandleTraits);
41 };
42 
43 // HMODULE is not really a handle, and has reference count semantics, so the
44 // standard VerifierTraits does not apply.
45 using ScopedModuleHandle =
46     win::GenericScopedHandle<ModuleHandleTraits, win::DummyVerifierTraits>;
47 
48 // Instances of this class are expected to be created and destroyed for each
49 // stack unwinding. This class is not used while the target thread is suspended,
50 // so may allocate from the default heap.
51 class BASE_EXPORT Win32StackFrameUnwinder {
52  public:
53   // Interface for Win32 unwind-related functionality this class depends
54   // on. Provides a seam for testing.
55   class BASE_EXPORT UnwindFunctions {
56    public:
57     virtual ~UnwindFunctions();
58 
59     virtual PRUNTIME_FUNCTION LookupFunctionEntry(DWORD64 program_counter,
60                                                   PDWORD64 image_base) = 0;
61     virtual void VirtualUnwind(DWORD64 image_base,
62                                DWORD64 program_counter,
63                                PRUNTIME_FUNCTION runtime_function,
64                                CONTEXT* context) = 0;
65 
66     // Returns the module containing |program_counter|. Can return null if the
67     // module has been unloaded.
68     virtual ScopedModuleHandle GetModuleForProgramCounter(
69         DWORD64 program_counter) = 0;
70 
71    protected:
72     UnwindFunctions();
73 
74    private:
75     DISALLOW_COPY_AND_ASSIGN(UnwindFunctions);
76   };
77 
78   Win32StackFrameUnwinder();
79   ~Win32StackFrameUnwinder();
80 
81   // Attempts to unwind the frame represented by the stack and instruction
82   // pointers in |context|. If successful, updates |context| and provides the
83   // module associated with the frame in |module|.
84   bool TryUnwind(CONTEXT* context, ScopedModuleHandle* module);
85 
86  private:
87   // This function is for internal and test purposes only.
88   Win32StackFrameUnwinder(std::unique_ptr<UnwindFunctions> unwind_functions);
89   friend class Win32StackFrameUnwinderTest;
90 
91   // State associated with each stack unwinding.
92   bool at_top_frame_;
93   bool unwind_info_present_for_all_frames_;
94 
95   std::unique_ptr<UnwindFunctions> unwind_functions_;
96 
97   DISALLOW_COPY_AND_ASSIGN(Win32StackFrameUnwinder);
98 };
99 
100 }  // namespace base
101 
102 #endif  // BASE_PROFILER_WIN32_STACK_FRAME_UNWINDER_H_
103