1*17f65170SRuslan Bukin /*
2*17f65170SRuslan Bukin * \file trc_ret_stack.cpp
3*17f65170SRuslan Bukin * \brief OpenCSD : trace decoder return stack feature.
4*17f65170SRuslan Bukin *
5*17f65170SRuslan Bukin * \copyright Copyright (c) 2017, ARM Limited. All Rights Reserved.
6*17f65170SRuslan Bukin */
7*17f65170SRuslan Bukin
8*17f65170SRuslan Bukin /*
9*17f65170SRuslan Bukin * Redistribution and use in source and binary forms, with or without modification,
10*17f65170SRuslan Bukin * are permitted provided that the following conditions are met:
11*17f65170SRuslan Bukin *
12*17f65170SRuslan Bukin * 1. Redistributions of source code must retain the above copyright notice,
13*17f65170SRuslan Bukin * this list of conditions and the following disclaimer.
14*17f65170SRuslan Bukin *
15*17f65170SRuslan Bukin * 2. Redistributions in binary form must reproduce the above copyright notice,
16*17f65170SRuslan Bukin * this list of conditions and the following disclaimer in the documentation
17*17f65170SRuslan Bukin * and/or other materials provided with the distribution.
18*17f65170SRuslan Bukin *
19*17f65170SRuslan Bukin * 3. Neither the name of the copyright holder nor the names of its contributors
20*17f65170SRuslan Bukin * may be used to endorse or promote products derived from this software without
21*17f65170SRuslan Bukin * specific prior written permission.
22*17f65170SRuslan Bukin *
23*17f65170SRuslan Bukin * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
24*17f65170SRuslan Bukin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25*17f65170SRuslan Bukin * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26*17f65170SRuslan Bukin * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27*17f65170SRuslan Bukin * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28*17f65170SRuslan Bukin * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29*17f65170SRuslan Bukin * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30*17f65170SRuslan Bukin * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31*17f65170SRuslan Bukin * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32*17f65170SRuslan Bukin * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33*17f65170SRuslan Bukin */
34*17f65170SRuslan Bukin #include "common/trc_ret_stack.h"
35*17f65170SRuslan Bukin
36*17f65170SRuslan Bukin #ifdef TRC_RET_STACK_DEBUG
37*17f65170SRuslan Bukin #include <sstream>
38*17f65170SRuslan Bukin #include <iostream>
39*17f65170SRuslan Bukin #include "common/trc_component.h"
40*17f65170SRuslan Bukin
41*17f65170SRuslan Bukin #define LOG_POP(A,O,I) LogOp("Pop",A,O,I)
42*17f65170SRuslan Bukin #define LOG_PUSH(A,O,I) LogOp("Push",A,O,I)
43*17f65170SRuslan Bukin #define LOG_FLUSH() LogOp("Flush",0,-1000,(const ocsd_isa)0)
44*17f65170SRuslan Bukin
45*17f65170SRuslan Bukin // uncomment for forced std::cout log, bypassing normal library debug logger.
46*17f65170SRuslan Bukin // useful perhaps when perf is decoding w/o printing.
47*17f65170SRuslan Bukin // #define FORCE_STD_COUT
48*17f65170SRuslan Bukin
49*17f65170SRuslan Bukin #else
50*17f65170SRuslan Bukin #define LOG_POP(A,O,I)
51*17f65170SRuslan Bukin #define LOG_PUSH(A,O,I)
52*17f65170SRuslan Bukin #define LOG_FLUSH()
53*17f65170SRuslan Bukin #endif
54*17f65170SRuslan Bukin
TrcAddrReturnStack()55*17f65170SRuslan Bukin TrcAddrReturnStack::TrcAddrReturnStack() :
56*17f65170SRuslan Bukin m_active(false),
57*17f65170SRuslan Bukin m_pop_pending(false),
58*17f65170SRuslan Bukin head_idx(0),
59*17f65170SRuslan Bukin num_entries(0)
60*17f65170SRuslan Bukin {
61*17f65170SRuslan Bukin #ifdef TRC_RET_STACK_DEBUG
62*17f65170SRuslan Bukin m_p_debug_logger = 0;
63*17f65170SRuslan Bukin #endif
64*17f65170SRuslan Bukin }
65*17f65170SRuslan Bukin
push(const ocsd_vaddr_t addr,const ocsd_isa isa)66*17f65170SRuslan Bukin void TrcAddrReturnStack::push(const ocsd_vaddr_t addr, const ocsd_isa isa)
67*17f65170SRuslan Bukin {
68*17f65170SRuslan Bukin if (is_active())
69*17f65170SRuslan Bukin {
70*17f65170SRuslan Bukin head_idx++;
71*17f65170SRuslan Bukin head_idx &= 0xF;
72*17f65170SRuslan Bukin m_stack[head_idx].ret_addr = addr;
73*17f65170SRuslan Bukin m_stack[head_idx].ret_isa = isa;
74*17f65170SRuslan Bukin num_entries++;
75*17f65170SRuslan Bukin if (num_entries > 16)
76*17f65170SRuslan Bukin num_entries = 16;
77*17f65170SRuslan Bukin LOG_PUSH(addr,0,isa);
78*17f65170SRuslan Bukin m_pop_pending = false;
79*17f65170SRuslan Bukin }
80*17f65170SRuslan Bukin }
81*17f65170SRuslan Bukin
pop(ocsd_isa & isa)82*17f65170SRuslan Bukin ocsd_vaddr_t TrcAddrReturnStack::pop(ocsd_isa &isa)
83*17f65170SRuslan Bukin {
84*17f65170SRuslan Bukin ocsd_vaddr_t addr = (ocsd_vaddr_t)-1;
85*17f65170SRuslan Bukin if (is_active())
86*17f65170SRuslan Bukin {
87*17f65170SRuslan Bukin if (num_entries > 0)
88*17f65170SRuslan Bukin {
89*17f65170SRuslan Bukin addr = m_stack[head_idx].ret_addr;
90*17f65170SRuslan Bukin isa = m_stack[head_idx].ret_isa;
91*17f65170SRuslan Bukin head_idx--;
92*17f65170SRuslan Bukin head_idx &= 0xF;
93*17f65170SRuslan Bukin }
94*17f65170SRuslan Bukin num_entries--;
95*17f65170SRuslan Bukin LOG_POP(addr,1,isa);
96*17f65170SRuslan Bukin m_pop_pending = false;
97*17f65170SRuslan Bukin }
98*17f65170SRuslan Bukin return addr;
99*17f65170SRuslan Bukin }
100*17f65170SRuslan Bukin
101*17f65170SRuslan Bukin
flush()102*17f65170SRuslan Bukin void TrcAddrReturnStack::flush()
103*17f65170SRuslan Bukin {
104*17f65170SRuslan Bukin num_entries = 0;
105*17f65170SRuslan Bukin m_pop_pending = false;
106*17f65170SRuslan Bukin LOG_FLUSH();
107*17f65170SRuslan Bukin }
108*17f65170SRuslan Bukin
109*17f65170SRuslan Bukin #ifdef TRC_RET_STACK_DEBUG
LogOp(const char * pszOpString,ocsd_vaddr_t addr,int head_off,ocsd_isa isa)110*17f65170SRuslan Bukin void TrcAddrReturnStack::LogOp(const char * pszOpString, ocsd_vaddr_t addr, int head_off, ocsd_isa isa)
111*17f65170SRuslan Bukin {
112*17f65170SRuslan Bukin static const char *isa_names[] =
113*17f65170SRuslan Bukin {
114*17f65170SRuslan Bukin "A32", /**< V7 ARM 32, V8 AArch32 */
115*17f65170SRuslan Bukin "T32", /**< Thumb2 -> 16/32 bit instructions */
116*17f65170SRuslan Bukin "A64", /**< V8 AArch64 */
117*17f65170SRuslan Bukin "TEE", /**< Thumb EE - unsupported */
118*17f65170SRuslan Bukin "JZL", /**< Jazelle - unsupported in trace */
119*17f65170SRuslan Bukin "custom", /**< Instruction set - custom arch decoder */
120*17f65170SRuslan Bukin "unknown" /**< ISA not yet known */
121*17f65170SRuslan Bukin };
122*17f65170SRuslan Bukin
123*17f65170SRuslan Bukin if (m_p_debug_logger)
124*17f65170SRuslan Bukin {
125*17f65170SRuslan Bukin std::ostringstream oss;
126*17f65170SRuslan Bukin if(head_off == -1000)
127*17f65170SRuslan Bukin {
128*17f65170SRuslan Bukin oss << "Return stack " << pszOpString << "\n";
129*17f65170SRuslan Bukin }
130*17f65170SRuslan Bukin else
131*17f65170SRuslan Bukin {
132*17f65170SRuslan Bukin int name_idx = (int)isa;
133*17f65170SRuslan Bukin if (name_idx > 6)
134*17f65170SRuslan Bukin name_idx = 6;
135*17f65170SRuslan Bukin oss << "Return stack " << pszOpString << "[" << std::dec << (head_idx+head_off) << "](0x" << std::hex << addr << "), " << isa_names[name_idx] << ";";
136*17f65170SRuslan Bukin oss << "current entries = " << std::dec << num_entries << ";";
137*17f65170SRuslan Bukin oss << "new head idx = " << head_idx << ";";
138*17f65170SRuslan Bukin oss << "pop pend (pre op) = " << (m_pop_pending ? "true\n" : "false\n");
139*17f65170SRuslan Bukin }
140*17f65170SRuslan Bukin #ifdef FORCE_STD_COUT
141*17f65170SRuslan Bukin std::cout << oss.str();
142*17f65170SRuslan Bukin std::cout.flush();
143*17f65170SRuslan Bukin #endif
144*17f65170SRuslan Bukin m_p_debug_logger->LogDefMessage(oss.str());
145*17f65170SRuslan Bukin }
146*17f65170SRuslan Bukin }
147*17f65170SRuslan Bukin #endif
148*17f65170SRuslan Bukin
149*17f65170SRuslan Bukin /* End of File trc_ret_stack.cpp */
150