| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SRC_DEVELOPER_DEBUG_ZXDB_CLIENT_INLINE_THREAD_CONTROLLER_TEST_H_ |
| #define SRC_DEVELOPER_DEBUG_ZXDB_CLIENT_INLINE_THREAD_CONTROLLER_TEST_H_ |
| |
| #include <vector> |
| |
| #include "src/developer/debug/zxdb/client/mock_frame.h" |
| #include "src/developer/debug/zxdb/client/thread_controller_test.h" |
| #include "src/developer/debug/zxdb/common/address_ranges.h" |
| #include "src/developer/debug/zxdb/symbols/location.h" |
| #include "src/lib/fxl/memory/ref_ptr.h" |
| |
| namespace zxdb { |
| |
| class Function; |
| class MockFrame; |
| |
| // Helper class used for testing thread controllers that need inline stacks. |
| // |
| // Note on code locations: The source location for inline calls and physical calls is different. The |
| // current instruction for a non-topmost physical frame is always the return address of the function |
| // call (typically the next line) because the debuggers knows the return address but don't |
| // necessarily know the exact call location. For inline calls, however, we show the inline call |
| // location because we do have that information, but don't know exactly where the inline call will |
| // "return" to since there's no clear return address. |
| // |
| // The code looks like this, with line numbers and the code locations (see note above): |
| // |
| // 10 inline void TopInline() { |
| // 11 ... <- kTopInlineFileLine |
| // 12 } |
| // 13 void Top() { |
| // 14 ... |
| // 15 TopInlineFunction(); <- kTopFileLine |
| // 16 ... |
| // 17 } |
| // 18 |
| // 19 inline void MiddleInline2() { |
| // 20 ... |
| // 21 Top(); // Non-inline call. |
| // 22 ... <- kMiddleInline2FileLine |
| // 23 } |
| // 24 inline void MiddleInline1() { |
| // 25 MiddleInline2(); <- kMiddleInline1FileLine |
| // 26 ... |
| // 27 } |
| // 28 void Middle() { |
| // 29 ... |
| // 30 MiddleInline1(); <- kMiddleFileLine |
| // 31 ... |
| // 32 } |
| // 33 |
| // 34 void Bottom() { |
| // 35 ... |
| // 36 Middle(); |
| // 37 ... |
| // 38 } |
| // |
| // The stack looks like this: |
| // |
| // [0] = inline from frame 1: TopInline() |
| // [1] = physical frame at kTopSP: Top() |
| // [2] = inline #2 from frame 4: MiddleInline2() |
| // [3] = inline #1 from frame 4: MiddleInline1() |
| // [4] = physical frame at kMiddleSP: Middle() |
| // [5] = physical frame at kBottomSP |
| // |
| // Binary code layout |
| // |
| // +--------------------------+ |
| // | TopFunction | |
| // | | |
| // | +--------------------+ | |
| // | | TopInlineFunction | | |
| // | +--------------------+ | |
| // +--------------------------+ |
| // |
| // +----------------------------------------------------------+ |
| // | MiddleFunction | |
| // | | |
| // | +------------------------+------------------------+--+ | |
| // | | MiddleFunctionInline1 | MiddleFunctionInline2 | | | |
| // | | +------------------------+ | | |
| // | | | | |
| // | +----------------------------------------------------+ | |
| // | | |
| // +----------------------------------------------------------+ |
| // |
| // Note that MiddleInline1() and MiddleInline2() start at the same location |
| // (as if calling #2 was the first thing #1 did). |
| class InlineThreadControllerTest : public ThreadControllerTest { |
| public: |
| // Stack pointers for each physical frame. |
| static const uint64_t kTopSP; |
| static const uint64_t kMiddleSP; |
| static const uint64_t kBottomSP; |
| |
| // Address range for each function. |
| static const AddressRange kTopFunctionRange; |
| static const AddressRange kTopInlineFunctionRange; |
| static const AddressRange kMiddleFunctionRange; |
| static const AddressRange kMiddleInline1FunctionRange; |
| static const AddressRange kMiddleInline2FunctionRange; |
| |
| // Line numbers. |
| static const FileLine kTopInlineFileLine; // IP @ top of stack |
| static const FileLine kTopFileLine; // Call loc of top inline. |
| static const FileLine kMiddleInline2FileLine; // Return of Top(). |
| static const FileLine kMiddleInline1FileLine; // Call loc of inline2. |
| static const FileLine kMiddleFileLine; // Call loc of inline1. |
| |
| // Creates functions associated with each of the frames. |
| static fxl::RefPtr<Function> GetTopFunction(); |
| static fxl::RefPtr<Function> GetTopInlineFunction(); |
| static fxl::RefPtr<Function> GetMiddleFunction(); |
| static fxl::RefPtr<Function> GetMiddleInline1Function(); |
| static fxl::RefPtr<Function> GetMiddleInline2Function(); |
| |
| // Creates locations. The address is passed in and must be inside of the |
| // range for the corresponding function. |
| static Location GetTopLocation(uint64_t address); |
| static Location GetTopInlineLocation(uint64_t address); |
| static Location GetMiddleLocation(uint64_t address); |
| static Location GetMiddleInline1Location(uint64_t address); |
| static Location GetMiddleInline2Location(uint64_t address); |
| |
| // Constructor for frames. |
| static std::unique_ptr<MockFrame> GetTopFrame(uint64_t address); |
| static std::unique_ptr<MockFrame> GetTopInlineFrame(uint64_t address, MockFrame* top); |
| static std::unique_ptr<MockFrame> GetMiddleFrame(uint64_t address); |
| static std::unique_ptr<MockFrame> GetMiddleInline1Frame(uint64_t address, MockFrame* middle); |
| static std::unique_ptr<MockFrame> GetMiddleInline2Frame(uint64_t address, MockFrame* middle); |
| static std::unique_ptr<MockFrame> GetBottomFrame(uint64_t address); |
| |
| // Constructs a fake stack. Even frame will have the address at the beginning of its range. |
| // |
| // This function returns a vector of MockFrames so the caller can modify the locations. It can |
| // then call MockFrameVectorToFrameVector() below to convert to the frame vector other code |
| // expects. |
| static std::vector<std::unique_ptr<MockFrame>> GetStack(); |
| |
| // Downcasts a vector of owning MockFrame pointers to the corresponding Frame pointers. |
| static std::vector<std::unique_ptr<Frame>> MockFrameVectorToFrameVector( |
| std::vector<std::unique_ptr<MockFrame>> mock_frames); |
| }; |
| |
| } // namespace zxdb |
| |
| #endif // SRC_DEVELOPER_DEBUG_ZXDB_CLIENT_INLINE_THREAD_CONTROLLER_TEST_H_ |