Add class to library to handle return stack feature in trace for PTM and ETMv4.
Return stack allows return addresses to be saved on an internal hardware stack, and reused if matching on an indirect branch. This reduces the need for explicit address packets on indirect branches.
The return stack object maintains a stack of at least the size required by the protocols, as a circular buffer as old, unused values fall off the end. the object allows for push() and pop() operations, a check for overflow and also a flag to allow the decoder to mark pop as pending. This is where the decision to pop() may be dependent on a following packet.
Compile time debug option allows test and debug of the stack operations.
Signed-off-by: Mike Leach mike.leach@linaro.org --- decoder/build/linux/ref_trace_decode_lib/makefile | 1 + .../ref_trace_decode_lib.vcxproj | 2 + .../ref_trace_decode_lib.vcxproj.filters | 6 + decoder/include/common/trc_ret_stack.h | 120 ++++++++++++++++++++ decoder/source/trc_ret_stack.cpp | 122 +++++++++++++++++++++ 5 files changed, 251 insertions(+) create mode 100644 decoder/include/common/trc_ret_stack.h create mode 100644 decoder/source/trc_ret_stack.cpp
diff --git a/decoder/build/linux/ref_trace_decode_lib/makefile b/decoder/build/linux/ref_trace_decode_lib/makefile index 748bab1..ed947e7 100644 --- a/decoder/build/linux/ref_trace_decode_lib/makefile +++ b/decoder/build/linux/ref_trace_decode_lib/makefile @@ -104,6 +104,7 @@ OBJECTS=$(BUILD_DIR)/ocsd_code_follower.o \ $(BUILD_DIR)/trc_frame_deformatter.o \ $(BUILD_DIR)/trc_gen_elem.o \ $(BUILD_DIR)/trc_printable_elem.o \ + $(BUILD_DIR)/trc_ret_stack.o \ $(ETMV3OBJ) \ $(ETMV4OBJ) \ $(IDECOBJ) \ diff --git a/decoder/build/win-vs2015/ref_trace_decode_lib/ref_trace_decode_lib.vcxproj b/decoder/build/win-vs2015/ref_trace_decode_lib/ref_trace_decode_lib.vcxproj index 709f031..e9f231d 100644 --- a/decoder/build/win-vs2015/ref_trace_decode_lib/ref_trace_decode_lib.vcxproj +++ b/decoder/build/win-vs2015/ref_trace_decode_lib/ref_trace_decode_lib.vcxproj @@ -334,6 +334,7 @@ <ClInclude Include="..\..\..\include\common\trc_pkt_elem_base.h" /> <ClInclude Include="..\..\..\include\common\trc_pkt_proc_base.h" /> <ClInclude Include="..\..\..\include\common\trc_printable_elem.h" /> + <ClInclude Include="..\..\..\include\common\trc_ret_stack.h" /> <ClInclude Include="..\..\..\include\etmv3\etmv3_decoder.h" /> <ClInclude Include="..\..\..\include\etmv3\trc_cmp_cfg_etmv3.h" /> <ClInclude Include="..\..\..\include\etmv3\trc_dcd_mngr_etmv3.h" /> @@ -441,6 +442,7 @@ <ClCompile Include="..\..\..\source\trc_frame_deformatter.cpp" /> <ClCompile Include="..\..\..\source\trc_gen_elem.cpp" /> <ClCompile Include="..\..\..\source\trc_printable_elem.cpp" /> + <ClCompile Include="..\..\..\source\trc_ret_stack.cpp" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> diff --git a/decoder/build/win-vs2015/ref_trace_decode_lib/ref_trace_decode_lib.vcxproj.filters b/decoder/build/win-vs2015/ref_trace_decode_lib/ref_trace_decode_lib.vcxproj.filters index 2ee0f50..a3f3558 100644 --- a/decoder/build/win-vs2015/ref_trace_decode_lib/ref_trace_decode_lib.vcxproj.filters +++ b/decoder/build/win-vs2015/ref_trace_decode_lib/ref_trace_decode_lib.vcxproj.filters @@ -353,6 +353,9 @@ <ClInclude Include="..\..\..\include\pkt_printers\trc_print_fact.h"> <Filter>Header Files\pkt_printers</Filter> </ClInclude> + <ClInclude Include="..\..\..\include\common\trc_ret_stack.h"> + <Filter>Header Files\common</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="..\..\..\source\trc_component.cpp"> @@ -475,5 +478,8 @@ <ClCompile Include="..\..\..\source\pkt_printers\trc_print_fact.cpp"> <Filter>Source Files\pkt_printers</Filter> </ClCompile> + <ClCompile Include="..\..\..\source\trc_ret_stack.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> </Project> \ No newline at end of file diff --git a/decoder/include/common/trc_ret_stack.h b/decoder/include/common/trc_ret_stack.h new file mode 100644 index 0000000..8f876dc --- /dev/null +++ b/decoder/include/common/trc_ret_stack.h @@ -0,0 +1,120 @@ +/* +* \file trc_ret_stack.h +* \brief OpenCSD : trace decoder return stack feature. +* +* \copyright Copyright (c) 2017, ARM Limited. All Rights Reserved. +*/ + +/* +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its contributors +* may be used to endorse or promote products derived from this software without +* specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef ARM_TRC_RET_STACK_H_INCLUDED +#define ARM_TRC_RET_STACK_H_INCLUDED + +#include "ocsd_if_types.h" + +// uncomment below for return stack logging +#define TRC_RET_STACK_DEBUG + +#ifdef TRC_RET_STACK_DEBUG +class TraceComponent; +#endif + +typedef struct _retStackElement +{ + ocsd_vaddr_t ret_addr; + ocsd_isa ret_isa; +} retStackElement; + +class TrcAddrReturnStack +{ +public: + TrcAddrReturnStack(); + ~TrcAddrReturnStack() {}; + + void set_active(bool active) + { + m_active = active; + }; + + bool is_active() const + { + return m_active; + }; + + void push(const ocsd_vaddr_t addr, const ocsd_isa isa); + ocsd_vaddr_t pop(ocsd_isa &isa); + + void flush() + { + num_entries = 0; + m_pop_pending = false; + }; + + bool overflow() const + { + return (bool)(num_entries < 0); + }; + + void set_pop_pending() + { + if (m_active) + m_pop_pending = true; + } + + void clear_pop_pending() + { + m_pop_pending = false; + } + + bool pop_pending() const + { + return m_pop_pending; + }; + +#ifdef TRC_RET_STACK_DEBUG + void set_dbg_logger(TraceComponent *pLogger) { m_p_debug_logger = pLogger; }; +#endif + +private: + bool m_active; + bool m_pop_pending; // flag for decoder to indicate a pop might be needed depending on the next packet (ETMv4) + + int head_idx; + int num_entries; + retStackElement m_stack[16]; + +#ifdef TRC_RET_STACK_DEBUG + void LogOp(const char *pszOpString, ocsd_vaddr_t addr, int head_off, ocsd_isa isa); + + TraceComponent *m_p_debug_logger; +#endif // TRC_RET_STACK_DEBUG +}; + +#endif // ARM_TRC_RET_STACK_H_INCLUDED + +/* End of File trc_ret_stack.h */ diff --git a/decoder/source/trc_ret_stack.cpp b/decoder/source/trc_ret_stack.cpp new file mode 100644 index 0000000..9e7fb3c --- /dev/null +++ b/decoder/source/trc_ret_stack.cpp @@ -0,0 +1,122 @@ +/* +* \file trc_ret_stack.cpp +* \brief OpenCSD : trace decoder return stack feature. +* +* \copyright Copyright (c) 2017, ARM Limited. All Rights Reserved. +*/ + +/* +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its contributors +* may be used to endorse or promote products derived from this software without +* specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include "common/trc_ret_stack.h" + +#ifdef TRC_RET_STACK_DEBUG +#include <sstream> +#include "common/trc_component.h" + +#define LOG_POP(A,O,I) LogOp("Pop",A,O,I) +#define LOG_PUSH(A,O,I) LogOp("Push",A,O,I) +#else +#define LOG_POP(A,O,I) +#define LOG_PUSH(A,O,I) +#endif + +TrcAddrReturnStack::TrcAddrReturnStack() : + m_active(false), + m_pop_pending(false), + head_idx(0), + num_entries(0) +{ +#ifdef TRC_RET_STACK_DEBUG + m_p_debug_logger = 0; +#endif +} + +void TrcAddrReturnStack::push(const ocsd_vaddr_t addr, const ocsd_isa isa) +{ + if (is_active()) + { + head_idx++; + head_idx &= 0xF; + m_stack[head_idx].ret_addr = addr; + m_stack[head_idx].ret_isa = isa; + num_entries++; + if (num_entries > 16) + num_entries = 16; + LOG_PUSH(addr,0,isa); + m_pop_pending = false; + } +} + +ocsd_vaddr_t TrcAddrReturnStack::pop(ocsd_isa &isa) +{ + ocsd_vaddr_t addr = (ocsd_vaddr_t)-1; + if (is_active()) + { + if (num_entries > 0) + { + addr = m_stack[head_idx].ret_addr; + isa = m_stack[head_idx].ret_isa; + head_idx--; + head_idx &= 0xF; + } + num_entries--; + LOG_POP(addr,1,isa); + m_pop_pending = false; + } + return addr; +} + +#ifdef TRC_RET_STACK_DEBUG +void TrcAddrReturnStack::LogOp(const char * pszOpString, ocsd_vaddr_t addr, int head_off, ocsd_isa isa) +{ + static const char *isa_names[] = + { + "A32", /**< V7 ARM 32, V8 AArch32 */ + "T32", /**< Thumb2 -> 16/32 bit instructions */ + "A64", /**< V8 AArch64 */ + "TEE", /**< Thumb EE - unsupported */ + "JZL", /**< Jazelle - unsupported in trace */ + "custom", /**< Instruction set - custom arch decoder */ + "unknown" /**< ISA not yet known */ + }; + + if (m_p_debug_logger) + { + int name_idx = (int)isa; + if (name_idx > 6) + name_idx = 6; + std::ostringstream oss; + oss << "Return stack " << pszOpString << "[" << std::dec << (head_idx+head_off) << "](0x" << std::hex << addr << "), " << isa_names[name_idx] << ";"; + oss << "current entries = " << std::dec << num_entries << ";"; + oss << "new head idx = " << head_idx << ";"; + oss << "pop pend (pre op) = " << (m_pop_pending ? "true\n" : "false\n"); + m_p_debug_logger->LogDefMessage(oss.str()); + } +} +#endif + +/* End of File trc_ret_stack.cpp */