xref: /aosp_15_r20/external/OpenCSD/decoder/source/i_dec/trc_i_decode.cpp (revision 02ca8ccacfba7e0df68f3332a95f3180334d6649)
1 /*
2  * \file       trc_i_decode.cpp
3  * \brief      OpenCSD :
4  *
5  * \copyright  Copyright (c) 2015, ARM Limited. All Rights Reserved.
6  */
7 
8 /*
9  * Redistribution and use in source and binary forms, with or without modification,
10  * are permitted provided that the following conditions are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of the copyright holder nor the names of its contributors
20  * may be used to endorse or promote products derived from this software without
21  * specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include "opencsd/ocsd_if_types.h"
36 #include "i_dec/trc_i_decode.h"
37 #include "i_dec/trc_idec_arminst.h"
38 
39 #include <cstdlib>
40 
TrcIDecode()41 TrcIDecode::TrcIDecode() :
42     aa64_err_bad_opcode(false)
43 {
44 }
45 
envSetAA64_errOnBadOpcode()46 void TrcIDecode::envSetAA64_errOnBadOpcode()
47 {
48     char* env_var = NULL;
49 
50     if ((env_var = getenv(OCSD_ENV_ERR_ON_AA64_BAD_OPCODE)) != NULL)
51         setAA64_errOnBadOpcode(true);
52 }
53 
54 
DecodeInstruction(ocsd_instr_info * instr_info)55 ocsd_err_t TrcIDecode::DecodeInstruction(ocsd_instr_info *instr_info)
56 {
57     ocsd_err_t err = OCSD_OK;
58     struct decode_info info;
59 
60     info.instr_sub_type = OCSD_S_INSTR_NONE;
61     info.arch_version = instr_info->pe_type.arch;
62 
63     switch(instr_info->isa)
64     {
65     case ocsd_isa_arm:
66         err = DecodeA32(instr_info, &info);
67         break;
68 
69     case ocsd_isa_thumb2:
70         err = DecodeT32(instr_info, &info);
71         break;
72 
73     case ocsd_isa_aarch64:
74         err = DecodeA64(instr_info, &info);
75         break;
76 
77     case ocsd_isa_tee:
78     case ocsd_isa_jazelle:
79     default:
80         // unsupported ISA
81         err = OCSD_ERR_UNSUPPORTED_ISA;
82         break;
83     }
84     instr_info->sub_type = info.instr_sub_type;
85     return err;
86 }
87 
DecodeA32(ocsd_instr_info * instr_info,struct decode_info * info)88 ocsd_err_t TrcIDecode::DecodeA32(ocsd_instr_info *instr_info, struct decode_info *info)
89 {
90     uint32_t branchAddr = 0;
91     arm_barrier_t barrier;
92 
93     instr_info->instr_size = 4; // instruction size A32
94     instr_info->type =  OCSD_INSTR_OTHER;  // default type
95     instr_info->next_isa = instr_info->isa; // assume same ISA
96     instr_info->is_link = 0;
97 
98     if(inst_ARM_is_indirect_branch(instr_info->opcode, info))
99     {
100         instr_info->type = OCSD_INSTR_BR_INDIRECT;
101         instr_info->is_link = inst_ARM_is_branch_and_link(instr_info->opcode, info);
102     }
103     else if(inst_ARM_is_direct_branch(instr_info->opcode))
104     {
105         inst_ARM_branch_destination((uint32_t)instr_info->instr_addr,instr_info->opcode,&branchAddr);
106         instr_info->type = OCSD_INSTR_BR;
107         if (branchAddr & 0x1)
108         {
109             instr_info->next_isa = ocsd_isa_thumb2;
110             branchAddr &= ~0x1;
111         }
112         instr_info->branch_addr = (ocsd_vaddr_t)branchAddr;
113         instr_info->is_link = inst_ARM_is_branch_and_link(instr_info->opcode, info);
114     }
115     else if((barrier = inst_ARM_barrier(instr_info->opcode)) != ARM_BARRIER_NONE)
116     {
117         switch(barrier)
118         {
119         case ARM_BARRIER_ISB:
120             instr_info->type = OCSD_INSTR_ISB;
121             break;
122 
123         case ARM_BARRIER_DSB:
124         case ARM_BARRIER_DMB:
125             if(instr_info->dsb_dmb_waypoints)
126                 instr_info->type = OCSD_INSTR_DSB_DMB;
127             break;
128         }
129     }
130     else if (instr_info->wfi_wfe_branch)
131     {
132         if (inst_ARM_wfiwfe(instr_info->opcode))
133         {
134             instr_info->type = OCSD_INSTR_WFI_WFE;
135         }
136     }
137     instr_info->is_conditional = inst_ARM_is_conditional(instr_info->opcode);
138 
139     return OCSD_OK;
140 }
141 
DecodeA64(ocsd_instr_info * instr_info,struct decode_info * info)142 ocsd_err_t TrcIDecode::DecodeA64(ocsd_instr_info *instr_info, struct decode_info *info)
143 {
144     uint64_t branchAddr = 0;
145     arm_barrier_t barrier;
146 
147     instr_info->instr_size =  4; // default address update
148     instr_info->type =  OCSD_INSTR_OTHER;  // default type
149     instr_info->next_isa = instr_info->isa; // assume same ISA
150     instr_info->is_link = 0;
151 
152     // check for invalid opcode - top 16 bits cannot be 0x0000.
153     if (aa64_err_bad_opcode && !(instr_info->opcode & 0xFFFF0000))
154         return OCSD_ERR_INVALID_OPCODE;
155 
156     if(inst_A64_is_indirect_branch_link(instr_info->opcode, &instr_info->is_link, info))
157     {
158         instr_info->type = OCSD_INSTR_BR_INDIRECT;
159     }
160     else if(inst_A64_is_direct_branch_link(instr_info->opcode, &instr_info->is_link, info))
161     {
162         inst_A64_branch_destination(instr_info->instr_addr,instr_info->opcode,&branchAddr);
163         instr_info->type = OCSD_INSTR_BR;
164         instr_info->branch_addr = (ocsd_vaddr_t)branchAddr;
165     }
166     else if((barrier = inst_A64_barrier(instr_info->opcode)) != ARM_BARRIER_NONE)
167     {
168         switch(barrier)
169         {
170         case ARM_BARRIER_ISB:
171             instr_info->type = OCSD_INSTR_ISB;
172             break;
173 
174         case ARM_BARRIER_DSB:
175         case ARM_BARRIER_DMB:
176             if(instr_info->dsb_dmb_waypoints)
177                 instr_info->type = OCSD_INSTR_DSB_DMB;
178             break;
179         }
180     }
181     else if (instr_info->wfi_wfe_branch &&
182              inst_A64_wfiwfe(instr_info->opcode, info))
183     {
184         instr_info->type = OCSD_INSTR_WFI_WFE;
185     }
186     else if (OCSD_IS_ARCH_MINVER(info->arch_version, ARCH_AA64))
187     {
188         if (inst_A64_Tstart(instr_info->opcode))
189             instr_info->type = OCSD_INSTR_TSTART;
190     }
191 
192     instr_info->is_conditional = inst_A64_is_conditional(instr_info->opcode);
193 
194     return OCSD_OK;
195 }
196 
DecodeT32(ocsd_instr_info * instr_info,struct decode_info * info)197 ocsd_err_t TrcIDecode::DecodeT32(ocsd_instr_info *instr_info, struct decode_info *info)
198 {
199     uint32_t branchAddr = 0;
200     arm_barrier_t barrier;
201 
202     // need to align the 32 bit opcode as 2 16 bit, with LS 16 as in top 16 bit of
203     // 32 bit word - T2 routines assume 16 bit in top 16 bit of 32 bit opcode.
204     uint32_t op_temp = (instr_info->opcode >> 16) & 0xFFFF;
205     op_temp |= ((instr_info->opcode & 0xFFFF) << 16);
206     instr_info->opcode = op_temp;
207 
208 
209     instr_info->instr_size = is_wide_thumb((uint16_t)(instr_info->opcode >> 16)) ? 4 : 2;
210     instr_info->type =  OCSD_INSTR_OTHER;  // default type
211     instr_info->next_isa = instr_info->isa; // assume same ISA
212     instr_info->is_link = 0;
213     instr_info->is_conditional = 0;
214 
215 
216     if(inst_Thumb_is_direct_branch_link(instr_info->opcode,&instr_info->is_link, &instr_info->is_conditional, info))
217     {
218         inst_Thumb_branch_destination((uint32_t)instr_info->instr_addr,instr_info->opcode,&branchAddr);
219         instr_info->type = OCSD_INSTR_BR;
220         instr_info->branch_addr = (ocsd_vaddr_t)(branchAddr & ~0x1);
221         if((branchAddr & 0x1) == 0)
222             instr_info->next_isa = ocsd_isa_arm;
223     }
224     else if (inst_Thumb_is_indirect_branch_link(instr_info->opcode, &instr_info->is_link, info))
225     {
226         instr_info->type = OCSD_INSTR_BR_INDIRECT;
227     }
228     else if((barrier = inst_Thumb_barrier(instr_info->opcode)) != ARM_BARRIER_NONE)
229     {
230         switch(barrier)
231         {
232         case ARM_BARRIER_ISB:
233             instr_info->type = OCSD_INSTR_ISB;
234             break;
235 
236         case ARM_BARRIER_DSB:
237         case ARM_BARRIER_DMB:
238             if(instr_info->dsb_dmb_waypoints)
239                 instr_info->type = OCSD_INSTR_DSB_DMB;
240             break;
241         }
242     }
243     else if (instr_info->wfi_wfe_branch)
244     {
245         if (inst_Thumb_wfiwfe(instr_info->opcode))
246         {
247             instr_info->type = OCSD_INSTR_WFI_WFE;
248         }
249     }
250     instr_info->is_conditional = inst_Thumb_is_conditional(instr_info->opcode);
251     instr_info->thumb_it_conditions = inst_Thumb_is_IT(instr_info->opcode);
252 
253     return OCSD_OK;
254 }
255 
256 /* End of File trc_i_decode.cpp */
257