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