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.wfi_wfe_branch = 0; 45 m_instr_info.instr_addr = 0; 46 m_instr_info.opcode = 0; 47 m_pMemAccess = 0; 48 m_pIDecode = 0; 49 m_mem_space_csid = 0; 50 m_st_range_addr = m_en_range_addr = m_next_addr = 0; 51 m_b_next_valid = false; 52 m_b_nacc_err = false; 53 } 54 55 OcsdCodeFollower::~OcsdCodeFollower() 56 { 57 } 58 59 void OcsdCodeFollower::initInterfaces(componentAttachPt<ITargetMemAccess> *pMemAccess, componentAttachPt<IInstrDecode> *pIDecode) 60 { 61 m_pMemAccess = pMemAccess; 62 m_pIDecode = pIDecode; 63 } 64 65 bool OcsdCodeFollower::initFollowerState() 66 { 67 bool initDone = false; 68 69 // reset per follow flags 70 m_b_next_valid = false; 71 m_b_nacc_err = false; 72 73 // set range addresses 74 m_en_range_addr = m_next_addr = m_st_range_addr; 75 76 // check initialisation is valid. 77 78 // must have attached memory access and i-decode objects 79 if(m_pMemAccess && m_pIDecode) 80 { 81 initDone = (m_pMemAccess->hasAttachedAndEnabled() && m_pIDecode->hasAttachedAndEnabled()); 82 } 83 return initDone; 84 } 85 86 /*! 87 * Decodes an instruction at a single location, calculates the next address 88 * if possible according to the instruction type and atom. 89 * 90 * @param addrStart : Address of the instruction 91 * @param A : Atom value - E or N 92 * 93 * @return ocsd_err_t : OCSD_OK - decode correct, check flags for next address 94 * : OCSD_ERR_MEM_NACC - unable to access memory area @ address - need new address in trace packet stream. 95 * : OCSD_ERR_NOT_INIT - not initialised - fatal. 96 * : OCSD_<other> - other error occured - fatal. 97 */ 98 ocsd_err_t OcsdCodeFollower::followSingleAtom(const ocsd_vaddr_t addrStart, const ocsd_atm_val A) 99 { 100 ocsd_err_t err = OCSD_ERR_NOT_INIT; 101 102 if(!initFollowerState()) 103 return err; 104 105 m_en_range_addr = m_st_range_addr = m_instr_info.instr_addr = addrStart; 106 err = decodeSingleOpCode(); 107 108 if(err != OCSD_OK) 109 return err; 110 111 // set end range - always after the instruction executed. 112 m_en_range_addr = m_instr_info.instr_addr + m_instr_info.instr_size; 113 114 // assume next addr is the instruction after 115 m_next_addr = m_en_range_addr; 116 m_b_next_valid = true; 117 118 // case when next address is different 119 switch(m_instr_info.type) 120 { 121 case OCSD_INSTR_BR: 122 if(A == ATOM_E) // executed the direct branch 123 m_next_addr = m_instr_info.branch_addr; 124 break; 125 126 case OCSD_INSTR_BR_INDIRECT: 127 if(A == ATOM_E) // executed indirect branch 128 m_b_next_valid = false; 129 break; 130 } 131 return err; 132 } 133 134 ocsd_err_t OcsdCodeFollower::decodeSingleOpCode() 135 { 136 ocsd_err_t err = OCSD_OK; 137 // request 4 bytes for the opcode - even for Thumb which may be T32 138 uint32_t bytesReq = 4; 139 uint32_t opcode; // buffer for opcode 140 141 // read memory location for opcode 142 err = m_pMemAccess->first()->ReadTargetMemory(m_instr_info.instr_addr,m_mem_space_csid,m_mem_acc_rule,&bytesReq,(uint8_t *)&opcode); 143 144 // operational error (not access problem - that is indicated by 0 bytes returned) 145 if(err != OCSD_OK) 146 return err; 147 148 if(bytesReq == 4) // check that we got all memory requested. 149 { 150 m_instr_info.opcode = opcode; 151 err = m_pIDecode->first()->DecodeInstruction(&m_instr_info); 152 } 153 else // otherwise memory unavailable. 154 { 155 m_b_nacc_err = true; 156 m_nacc_address = m_instr_info.instr_addr; 157 err = OCSD_ERR_MEM_NACC; 158 } 159 return err; 160 } 161 162 /* End of File ocsd_code_follower.cpp */ 163