objtool: Add abstraction for destination offsets
[linux-2.6-microblaze.git] / tools / objtool / arch / x86 / decode.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com>
4  */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8
9 #define unlikely(cond) (cond)
10 #include <asm/insn.h>
11 #include "../../../arch/x86/lib/inat.c"
12 #include "../../../arch/x86/lib/insn.c"
13
14 #include "../../check.h"
15 #include "../../elf.h"
16 #include "../../arch.h"
17 #include "../../warn.h"
18
19 static unsigned char op_to_cfi_reg[][2] = {
20         {CFI_AX, CFI_R8},
21         {CFI_CX, CFI_R9},
22         {CFI_DX, CFI_R10},
23         {CFI_BX, CFI_R11},
24         {CFI_SP, CFI_R12},
25         {CFI_BP, CFI_R13},
26         {CFI_SI, CFI_R14},
27         {CFI_DI, CFI_R15},
28 };
29
30 static int is_x86_64(struct elf *elf)
31 {
32         switch (elf->ehdr.e_machine) {
33         case EM_X86_64:
34                 return 1;
35         case EM_386:
36                 return 0;
37         default:
38                 WARN("unexpected ELF machine type %d", elf->ehdr.e_machine);
39                 return -1;
40         }
41 }
42
43 bool arch_callee_saved_reg(unsigned char reg)
44 {
45         switch (reg) {
46         case CFI_BP:
47         case CFI_BX:
48         case CFI_R12:
49         case CFI_R13:
50         case CFI_R14:
51         case CFI_R15:
52                 return true;
53
54         case CFI_AX:
55         case CFI_CX:
56         case CFI_DX:
57         case CFI_SI:
58         case CFI_DI:
59         case CFI_SP:
60         case CFI_R8:
61         case CFI_R9:
62         case CFI_R10:
63         case CFI_R11:
64         case CFI_RA:
65         default:
66                 return false;
67         }
68 }
69
70 unsigned long arch_dest_rela_offset(int addend)
71 {
72         return addend + 4;
73 }
74
75 unsigned long arch_jump_destination(struct instruction *insn)
76 {
77         return insn->offset + insn->len + insn->immediate;
78 }
79
80 int arch_decode_instruction(struct elf *elf, struct section *sec,
81                             unsigned long offset, unsigned int maxlen,
82                             unsigned int *len, enum insn_type *type,
83                             unsigned long *immediate, struct stack_op *op)
84 {
85         struct insn insn;
86         int x86_64, sign;
87         unsigned char op1, op2, rex = 0, rex_b = 0, rex_r = 0, rex_w = 0,
88                       rex_x = 0, modrm = 0, modrm_mod = 0, modrm_rm = 0,
89                       modrm_reg = 0, sib = 0;
90
91         x86_64 = is_x86_64(elf);
92         if (x86_64 == -1)
93                 return -1;
94
95         insn_init(&insn, sec->data->d_buf + offset, maxlen, x86_64);
96         insn_get_length(&insn);
97
98         if (!insn_complete(&insn)) {
99                 WARN_FUNC("can't decode instruction", sec, offset);
100                 return -1;
101         }
102
103         *len = insn.length;
104         *type = INSN_OTHER;
105
106         if (insn.vex_prefix.nbytes)
107                 return 0;
108
109         op1 = insn.opcode.bytes[0];
110         op2 = insn.opcode.bytes[1];
111
112         if (insn.rex_prefix.nbytes) {
113                 rex = insn.rex_prefix.bytes[0];
114                 rex_w = X86_REX_W(rex) >> 3;
115                 rex_r = X86_REX_R(rex) >> 2;
116                 rex_x = X86_REX_X(rex) >> 1;
117                 rex_b = X86_REX_B(rex);
118         }
119
120         if (insn.modrm.nbytes) {
121                 modrm = insn.modrm.bytes[0];
122                 modrm_mod = X86_MODRM_MOD(modrm);
123                 modrm_reg = X86_MODRM_REG(modrm);
124                 modrm_rm = X86_MODRM_RM(modrm);
125         }
126
127         if (insn.sib.nbytes)
128                 sib = insn.sib.bytes[0];
129
130         switch (op1) {
131
132         case 0x1:
133         case 0x29:
134                 if (rex_w && !rex_b && modrm_mod == 3 && modrm_rm == 4) {
135
136                         /* add/sub reg, %rsp */
137                         *type = INSN_STACK;
138                         op->src.type = OP_SRC_ADD;
139                         op->src.reg = op_to_cfi_reg[modrm_reg][rex_r];
140                         op->dest.type = OP_DEST_REG;
141                         op->dest.reg = CFI_SP;
142                 }
143                 break;
144
145         case 0x50 ... 0x57:
146
147                 /* push reg */
148                 *type = INSN_STACK;
149                 op->src.type = OP_SRC_REG;
150                 op->src.reg = op_to_cfi_reg[op1 & 0x7][rex_b];
151                 op->dest.type = OP_DEST_PUSH;
152
153                 break;
154
155         case 0x58 ... 0x5f:
156
157                 /* pop reg */
158                 *type = INSN_STACK;
159                 op->src.type = OP_SRC_POP;
160                 op->dest.type = OP_DEST_REG;
161                 op->dest.reg = op_to_cfi_reg[op1 & 0x7][rex_b];
162
163                 break;
164
165         case 0x68:
166         case 0x6a:
167                 /* push immediate */
168                 *type = INSN_STACK;
169                 op->src.type = OP_SRC_CONST;
170                 op->dest.type = OP_DEST_PUSH;
171                 break;
172
173         case 0x70 ... 0x7f:
174                 *type = INSN_JUMP_CONDITIONAL;
175                 break;
176
177         case 0x81:
178         case 0x83:
179                 if (rex != 0x48)
180                         break;
181
182                 if (modrm == 0xe4) {
183                         /* and imm, %rsp */
184                         *type = INSN_STACK;
185                         op->src.type = OP_SRC_AND;
186                         op->src.reg = CFI_SP;
187                         op->src.offset = insn.immediate.value;
188                         op->dest.type = OP_DEST_REG;
189                         op->dest.reg = CFI_SP;
190                         break;
191                 }
192
193                 if (modrm == 0xc4)
194                         sign = 1;
195                 else if (modrm == 0xec)
196                         sign = -1;
197                 else
198                         break;
199
200                 /* add/sub imm, %rsp */
201                 *type = INSN_STACK;
202                 op->src.type = OP_SRC_ADD;
203                 op->src.reg = CFI_SP;
204                 op->src.offset = insn.immediate.value * sign;
205                 op->dest.type = OP_DEST_REG;
206                 op->dest.reg = CFI_SP;
207                 break;
208
209         case 0x89:
210                 if (rex_w && !rex_r && modrm_mod == 3 && modrm_reg == 4) {
211
212                         /* mov %rsp, reg */
213                         *type = INSN_STACK;
214                         op->src.type = OP_SRC_REG;
215                         op->src.reg = CFI_SP;
216                         op->dest.type = OP_DEST_REG;
217                         op->dest.reg = op_to_cfi_reg[modrm_rm][rex_b];
218                         break;
219                 }
220
221                 if (rex_w && !rex_b && modrm_mod == 3 && modrm_rm == 4) {
222
223                         /* mov reg, %rsp */
224                         *type = INSN_STACK;
225                         op->src.type = OP_SRC_REG;
226                         op->src.reg = op_to_cfi_reg[modrm_reg][rex_r];
227                         op->dest.type = OP_DEST_REG;
228                         op->dest.reg = CFI_SP;
229                         break;
230                 }
231
232                 /* fallthrough */
233         case 0x88:
234                 if (!rex_b &&
235                     (modrm_mod == 1 || modrm_mod == 2) && modrm_rm == 5) {
236
237                         /* mov reg, disp(%rbp) */
238                         *type = INSN_STACK;
239                         op->src.type = OP_SRC_REG;
240                         op->src.reg = op_to_cfi_reg[modrm_reg][rex_r];
241                         op->dest.type = OP_DEST_REG_INDIRECT;
242                         op->dest.reg = CFI_BP;
243                         op->dest.offset = insn.displacement.value;
244
245                 } else if (rex_w && !rex_b && modrm_rm == 4 && sib == 0x24) {
246
247                         /* mov reg, disp(%rsp) */
248                         *type = INSN_STACK;
249                         op->src.type = OP_SRC_REG;
250                         op->src.reg = op_to_cfi_reg[modrm_reg][rex_r];
251                         op->dest.type = OP_DEST_REG_INDIRECT;
252                         op->dest.reg = CFI_SP;
253                         op->dest.offset = insn.displacement.value;
254                 }
255
256                 break;
257
258         case 0x8b:
259                 if (rex_w && !rex_b && modrm_mod == 1 && modrm_rm == 5) {
260
261                         /* mov disp(%rbp), reg */
262                         *type = INSN_STACK;
263                         op->src.type = OP_SRC_REG_INDIRECT;
264                         op->src.reg = CFI_BP;
265                         op->src.offset = insn.displacement.value;
266                         op->dest.type = OP_DEST_REG;
267                         op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r];
268
269                 } else if (rex_w && !rex_b && sib == 0x24 &&
270                            modrm_mod != 3 && modrm_rm == 4) {
271
272                         /* mov disp(%rsp), reg */
273                         *type = INSN_STACK;
274                         op->src.type = OP_SRC_REG_INDIRECT;
275                         op->src.reg = CFI_SP;
276                         op->src.offset = insn.displacement.value;
277                         op->dest.type = OP_DEST_REG;
278                         op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r];
279                 }
280
281                 break;
282
283         case 0x8d:
284                 if (sib == 0x24 && rex_w && !rex_b && !rex_x) {
285
286                         *type = INSN_STACK;
287                         if (!insn.displacement.value) {
288                                 /* lea (%rsp), reg */
289                                 op->src.type = OP_SRC_REG;
290                         } else {
291                                 /* lea disp(%rsp), reg */
292                                 op->src.type = OP_SRC_ADD;
293                                 op->src.offset = insn.displacement.value;
294                         }
295                         op->src.reg = CFI_SP;
296                         op->dest.type = OP_DEST_REG;
297                         op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r];
298
299                 } else if (rex == 0x48 && modrm == 0x65) {
300
301                         /* lea disp(%rbp), %rsp */
302                         *type = INSN_STACK;
303                         op->src.type = OP_SRC_ADD;
304                         op->src.reg = CFI_BP;
305                         op->src.offset = insn.displacement.value;
306                         op->dest.type = OP_DEST_REG;
307                         op->dest.reg = CFI_SP;
308
309                 } else if (rex == 0x49 && modrm == 0x62 &&
310                            insn.displacement.value == -8) {
311
312                         /*
313                          * lea -0x8(%r10), %rsp
314                          *
315                          * Restoring rsp back to its original value after a
316                          * stack realignment.
317                          */
318                         *type = INSN_STACK;
319                         op->src.type = OP_SRC_ADD;
320                         op->src.reg = CFI_R10;
321                         op->src.offset = -8;
322                         op->dest.type = OP_DEST_REG;
323                         op->dest.reg = CFI_SP;
324
325                 } else if (rex == 0x49 && modrm == 0x65 &&
326                            insn.displacement.value == -16) {
327
328                         /*
329                          * lea -0x10(%r13), %rsp
330                          *
331                          * Restoring rsp back to its original value after a
332                          * stack realignment.
333                          */
334                         *type = INSN_STACK;
335                         op->src.type = OP_SRC_ADD;
336                         op->src.reg = CFI_R13;
337                         op->src.offset = -16;
338                         op->dest.type = OP_DEST_REG;
339                         op->dest.reg = CFI_SP;
340                 }
341
342                 break;
343
344         case 0x8f:
345                 /* pop to mem */
346                 *type = INSN_STACK;
347                 op->src.type = OP_SRC_POP;
348                 op->dest.type = OP_DEST_MEM;
349                 break;
350
351         case 0x90:
352                 *type = INSN_NOP;
353                 break;
354
355         case 0x9c:
356                 /* pushf */
357                 *type = INSN_STACK;
358                 op->src.type = OP_SRC_CONST;
359                 op->dest.type = OP_DEST_PUSHF;
360                 break;
361
362         case 0x9d:
363                 /* popf */
364                 *type = INSN_STACK;
365                 op->src.type = OP_SRC_POPF;
366                 op->dest.type = OP_DEST_MEM;
367                 break;
368
369         case 0x0f:
370
371                 if (op2 == 0x01) {
372
373                         if (modrm == 0xca)
374                                 *type = INSN_CLAC;
375                         else if (modrm == 0xcb)
376                                 *type = INSN_STAC;
377
378                 } else if (op2 >= 0x80 && op2 <= 0x8f) {
379
380                         *type = INSN_JUMP_CONDITIONAL;
381
382                 } else if (op2 == 0x05 || op2 == 0x07 || op2 == 0x34 ||
383                            op2 == 0x35) {
384
385                         /* sysenter, sysret */
386                         *type = INSN_CONTEXT_SWITCH;
387
388                 } else if (op2 == 0x0b || op2 == 0xb9) {
389
390                         /* ud2 */
391                         *type = INSN_BUG;
392
393                 } else if (op2 == 0x0d || op2 == 0x1f) {
394
395                         /* nopl/nopw */
396                         *type = INSN_NOP;
397
398                 } else if (op2 == 0xa0 || op2 == 0xa8) {
399
400                         /* push fs/gs */
401                         *type = INSN_STACK;
402                         op->src.type = OP_SRC_CONST;
403                         op->dest.type = OP_DEST_PUSH;
404
405                 } else if (op2 == 0xa1 || op2 == 0xa9) {
406
407                         /* pop fs/gs */
408                         *type = INSN_STACK;
409                         op->src.type = OP_SRC_POP;
410                         op->dest.type = OP_DEST_MEM;
411                 }
412
413                 break;
414
415         case 0xc9:
416                 /*
417                  * leave
418                  *
419                  * equivalent to:
420                  * mov bp, sp
421                  * pop bp
422                  */
423                 *type = INSN_STACK;
424                 op->dest.type = OP_DEST_LEAVE;
425
426                 break;
427
428         case 0xe3:
429                 /* jecxz/jrcxz */
430                 *type = INSN_JUMP_CONDITIONAL;
431                 break;
432
433         case 0xe9:
434         case 0xeb:
435                 *type = INSN_JUMP_UNCONDITIONAL;
436                 break;
437
438         case 0xc2:
439         case 0xc3:
440                 *type = INSN_RETURN;
441                 break;
442
443         case 0xca: /* retf */
444         case 0xcb: /* retf */
445         case 0xcf: /* iret */
446                 *type = INSN_CONTEXT_SWITCH;
447                 break;
448
449         case 0xe8:
450                 *type = INSN_CALL;
451                 break;
452
453         case 0xfc:
454                 *type = INSN_CLD;
455                 break;
456
457         case 0xfd:
458                 *type = INSN_STD;
459                 break;
460
461         case 0xff:
462                 if (modrm_reg == 2 || modrm_reg == 3)
463
464                         *type = INSN_CALL_DYNAMIC;
465
466                 else if (modrm_reg == 4)
467
468                         *type = INSN_JUMP_DYNAMIC;
469
470                 else if (modrm_reg == 5)
471
472                         /* jmpf */
473                         *type = INSN_CONTEXT_SWITCH;
474
475                 else if (modrm_reg == 6) {
476
477                         /* push from mem */
478                         *type = INSN_STACK;
479                         op->src.type = OP_SRC_CONST;
480                         op->dest.type = OP_DEST_PUSH;
481                 }
482
483                 break;
484
485         default:
486                 break;
487         }
488
489         *immediate = insn.immediate.nbytes ? insn.immediate.value : 0;
490
491         return 0;
492 }
493
494 void arch_initial_func_cfi_state(struct cfi_state *state)
495 {
496         int i;
497
498         for (i = 0; i < CFI_NUM_REGS; i++) {
499                 state->regs[i].base = CFI_UNDEFINED;
500                 state->regs[i].offset = 0;
501         }
502
503         /* initial CFA (call frame address) */
504         state->cfa.base = CFI_SP;
505         state->cfa.offset = 8;
506
507         /* initial RA (return address) */
508         state->regs[16].base = CFI_CFA;
509         state->regs[16].offset = -8;
510 }