xref: /freebsd-src/contrib/opencsd/decoder/source/ocsd_code_follower.cpp (revision c120c5646da1a1d2c4d90fd069a7e2a8d559eb46)
1*c120c564SAndrew Turner /*
2*c120c564SAndrew Turner  * \file       ocsd_code_follower.cpp
3*c120c564SAndrew Turner  * \brief      OpenCSD : Instruction Code path follower.
4*c120c564SAndrew Turner  *
5*c120c564SAndrew Turner  * \copyright  Copyright (c) 2016, ARM Limited. All Rights Reserved.
6*c120c564SAndrew Turner  */
7*c120c564SAndrew Turner 
8*c120c564SAndrew Turner 
9*c120c564SAndrew Turner /*
10*c120c564SAndrew Turner  * Redistribution and use in source and binary forms, with or without modification,
11*c120c564SAndrew Turner  * are permitted provided that the following conditions are met:
12*c120c564SAndrew Turner  *
13*c120c564SAndrew Turner  * 1. Redistributions of source code must retain the above copyright notice,
14*c120c564SAndrew Turner  * this list of conditions and the following disclaimer.
15*c120c564SAndrew Turner  *
16*c120c564SAndrew Turner  * 2. Redistributions in binary form must reproduce the above copyright notice,
17*c120c564SAndrew Turner  * this list of conditions and the following disclaimer in the documentation
18*c120c564SAndrew Turner  * and/or other materials provided with the distribution.
19*c120c564SAndrew Turner  *
20*c120c564SAndrew Turner  * 3. Neither the name of the copyright holder nor the names of its contributors
21*c120c564SAndrew Turner  * may be used to endorse or promote products derived from this software without
22*c120c564SAndrew Turner  * specific prior written permission.
23*c120c564SAndrew Turner  *
24*c120c564SAndrew Turner  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
25*c120c564SAndrew Turner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26*c120c564SAndrew Turner  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27*c120c564SAndrew Turner  * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28*c120c564SAndrew Turner  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29*c120c564SAndrew Turner  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30*c120c564SAndrew Turner  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31*c120c564SAndrew Turner  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32*c120c564SAndrew Turner  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33*c120c564SAndrew Turner  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34*c120c564SAndrew Turner  */
35*c120c564SAndrew Turner 
36*c120c564SAndrew Turner #include "common/ocsd_code_follower.h"
37*c120c564SAndrew Turner 
OcsdCodeFollower()38*c120c564SAndrew Turner OcsdCodeFollower::OcsdCodeFollower()
39*c120c564SAndrew Turner {
40*c120c564SAndrew Turner     m_instr_info.pe_type.arch = ARCH_UNKNOWN;
41*c120c564SAndrew Turner     m_instr_info.pe_type.profile = profile_Unknown;
42*c120c564SAndrew Turner     m_instr_info.isa = ocsd_isa_unknown;
43*c120c564SAndrew Turner     m_instr_info.dsb_dmb_waypoints = 0;
44*c120c564SAndrew Turner     m_instr_info.wfi_wfe_branch = 0;
45*c120c564SAndrew Turner     m_instr_info.instr_addr = 0;
46*c120c564SAndrew Turner     m_instr_info.opcode = 0;
47*c120c564SAndrew Turner     m_pMemAccess = 0;
48*c120c564SAndrew Turner     m_pIDecode = 0;
49*c120c564SAndrew Turner     m_mem_space_csid = 0;
50*c120c564SAndrew Turner     m_st_range_addr =  m_en_range_addr = m_next_addr = 0;
51*c120c564SAndrew Turner     m_b_next_valid = false;
52*c120c564SAndrew Turner     m_b_nacc_err = false;
53*c120c564SAndrew Turner }
54*c120c564SAndrew Turner 
~OcsdCodeFollower()55*c120c564SAndrew Turner OcsdCodeFollower::~OcsdCodeFollower()
56*c120c564SAndrew Turner {
57*c120c564SAndrew Turner }
58*c120c564SAndrew Turner 
initInterfaces(componentAttachPt<ITargetMemAccess> * pMemAccess,componentAttachPt<IInstrDecode> * pIDecode)59*c120c564SAndrew Turner void OcsdCodeFollower::initInterfaces(componentAttachPt<ITargetMemAccess> *pMemAccess, componentAttachPt<IInstrDecode> *pIDecode)
60*c120c564SAndrew Turner {
61*c120c564SAndrew Turner     m_pMemAccess = pMemAccess;
62*c120c564SAndrew Turner     m_pIDecode = pIDecode;
63*c120c564SAndrew Turner }
64*c120c564SAndrew Turner 
initFollowerState()65*c120c564SAndrew Turner bool OcsdCodeFollower::initFollowerState()
66*c120c564SAndrew Turner {
67*c120c564SAndrew Turner     bool initDone = false;
68*c120c564SAndrew Turner 
69*c120c564SAndrew Turner     // reset per follow flags
70*c120c564SAndrew Turner     m_b_next_valid = false;
71*c120c564SAndrew Turner     m_b_nacc_err = false;
72*c120c564SAndrew Turner 
73*c120c564SAndrew Turner     // set range addresses
74*c120c564SAndrew Turner     m_en_range_addr = m_next_addr = m_st_range_addr;
75*c120c564SAndrew Turner 
76*c120c564SAndrew Turner // check initialisation is valid.
77*c120c564SAndrew Turner 
78*c120c564SAndrew Turner     // must have attached memory access and i-decode objects
79*c120c564SAndrew Turner     if(m_pMemAccess && m_pIDecode)
80*c120c564SAndrew Turner     {
81*c120c564SAndrew Turner         initDone = (m_pMemAccess->hasAttachedAndEnabled() && m_pIDecode->hasAttachedAndEnabled());
82*c120c564SAndrew Turner     }
83*c120c564SAndrew Turner     return initDone;
84*c120c564SAndrew Turner }
85*c120c564SAndrew Turner 
86*c120c564SAndrew Turner /*!
87*c120c564SAndrew Turner  * Decodes an instruction at a single location, calculates the next address
88*c120c564SAndrew Turner  * if possible according to the instruction type and atom.
89*c120c564SAndrew Turner  *
90*c120c564SAndrew Turner  * @param addrStart : Address of the instruction
91*c120c564SAndrew Turner  * @param A :  Atom value - E or N
92*c120c564SAndrew Turner  *
93*c120c564SAndrew Turner  * @return ocsd_err_t : OCSD_OK - decode correct, check flags for next address
94*c120c564SAndrew Turner  *                    : OCSD_ERR_MEM_NACC - unable to access memory area @ address - need new address in trace packet stream.
95*c120c564SAndrew Turner  *                    : OCSD_ERR_NOT_INIT - not initialised - fatal.
96*c120c564SAndrew Turner  *                    : OCSD_<other>  - other error occured - fatal.
97*c120c564SAndrew Turner  */
followSingleAtom(const ocsd_vaddr_t addrStart,const ocsd_atm_val A)98*c120c564SAndrew Turner ocsd_err_t OcsdCodeFollower::followSingleAtom(const ocsd_vaddr_t addrStart, const ocsd_atm_val A)
99*c120c564SAndrew Turner {
100*c120c564SAndrew Turner     ocsd_err_t err = OCSD_ERR_NOT_INIT;
101*c120c564SAndrew Turner 
102*c120c564SAndrew Turner     if(!initFollowerState())
103*c120c564SAndrew Turner         return err;
104*c120c564SAndrew Turner 
105*c120c564SAndrew Turner     m_en_range_addr = m_st_range_addr = m_instr_info.instr_addr = addrStart;
106*c120c564SAndrew Turner     err = decodeSingleOpCode();
107*c120c564SAndrew Turner 
108*c120c564SAndrew Turner     if(err != OCSD_OK)
109*c120c564SAndrew Turner         return err;
110*c120c564SAndrew Turner 
111*c120c564SAndrew Turner     // set end range - always after the instruction executed.
112*c120c564SAndrew Turner     m_en_range_addr = m_instr_info.instr_addr + m_instr_info.instr_size;
113*c120c564SAndrew Turner 
114*c120c564SAndrew Turner     // assume next addr is the instruction after
115*c120c564SAndrew Turner     m_next_addr = m_en_range_addr;
116*c120c564SAndrew Turner     m_b_next_valid = true;
117*c120c564SAndrew Turner 
118*c120c564SAndrew Turner     // case when next address is different
119*c120c564SAndrew Turner     switch(m_instr_info.type)
120*c120c564SAndrew Turner     {
121*c120c564SAndrew Turner     case OCSD_INSTR_BR:
122*c120c564SAndrew Turner         if(A == ATOM_E) // executed the direct branch
123*c120c564SAndrew Turner             m_next_addr = m_instr_info.branch_addr;
124*c120c564SAndrew Turner         break;
125*c120c564SAndrew Turner 
126*c120c564SAndrew Turner     case OCSD_INSTR_BR_INDIRECT:
127*c120c564SAndrew Turner         if(A == ATOM_E) // executed indirect branch
128*c120c564SAndrew Turner             m_b_next_valid = false;
129*c120c564SAndrew Turner         break;
130*c120c564SAndrew Turner     }
131*c120c564SAndrew Turner     return err;
132*c120c564SAndrew Turner }
133*c120c564SAndrew Turner 
decodeSingleOpCode()134*c120c564SAndrew Turner ocsd_err_t OcsdCodeFollower::decodeSingleOpCode()
135*c120c564SAndrew Turner {
136*c120c564SAndrew Turner     ocsd_err_t err = OCSD_OK;
137*c120c564SAndrew Turner     // request 4 bytes for the opcode - even for Thumb which may be T32
138*c120c564SAndrew Turner     uint32_t bytesReq = 4;
139*c120c564SAndrew Turner     uint32_t opcode;    // buffer for opcode
140*c120c564SAndrew Turner 
141*c120c564SAndrew Turner     // read memory location for opcode
142*c120c564SAndrew Turner     err = m_pMemAccess->first()->ReadTargetMemory(m_instr_info.instr_addr,m_mem_space_csid,m_mem_acc_rule,&bytesReq,(uint8_t *)&opcode);
143*c120c564SAndrew Turner 
144*c120c564SAndrew Turner     // operational error (not access problem - that is indicated by 0 bytes returned)
145*c120c564SAndrew Turner     if(err != OCSD_OK)
146*c120c564SAndrew Turner         return err;
147*c120c564SAndrew Turner 
148*c120c564SAndrew Turner     if(bytesReq == 4)       // check that we got all memory requested.
149*c120c564SAndrew Turner     {
150*c120c564SAndrew Turner         m_instr_info.opcode = opcode;
151*c120c564SAndrew Turner         err = m_pIDecode->first()->DecodeInstruction(&m_instr_info);
152*c120c564SAndrew Turner     }
153*c120c564SAndrew Turner     else       // otherwise memory unavailable.
154*c120c564SAndrew Turner     {
155*c120c564SAndrew Turner         m_b_nacc_err = true;
156*c120c564SAndrew Turner         m_nacc_address = m_instr_info.instr_addr;
157*c120c564SAndrew Turner         err = OCSD_ERR_MEM_NACC;
158*c120c564SAndrew Turner     }
159*c120c564SAndrew Turner     return err;
160*c120c564SAndrew Turner }
161*c120c564SAndrew Turner 
162*c120c564SAndrew Turner /* End of File ocsd_code_follower.cpp */
163