diff options
author | Eugene Tarassov | 2014-08-27 18:14:16 +0000 |
---|---|---|
committer | Eugene Tarassov | 2014-08-27 18:14:16 +0000 |
commit | e2e994856d6aa49ec026e300ca04d2c72291f50c (patch) | |
tree | 2dfea02df99a2ccfd3a959e03a6b86a6545912a3 | |
parent | 5b08dc48519da3aa01b5460d599191dd7caadedc (diff) | |
download | org.eclipse.tcf.agent-e2e994856d6aa49ec026e300ca04d2c72291f50c.tar.gz org.eclipse.tcf.agent-e2e994856d6aa49ec026e300ca04d2c72291f50c.tar.xz org.eclipse.tcf.agent-e2e994856d6aa49ec026e300ca04d2c72291f50c.zip |
TCF Agent: better stack crawl for ARM AArch64
-rw-r--r-- | agent/machine/a64/tcf/stack-crawl-a64.c | 100 |
1 files changed, 81 insertions, 19 deletions
diff --git a/agent/machine/a64/tcf/stack-crawl-a64.c b/agent/machine/a64/tcf/stack-crawl-a64.c index c1891d07..0c5818ae 100644 --- a/agent/machine/a64/tcf/stack-crawl-a64.c +++ b/agent/machine/a64/tcf/stack-crawl-a64.c @@ -569,18 +569,12 @@ static int loads_and_stores(void) { int V = (instr & (1 << 26)) != 0; int L = (instr & (1 << 22)) != 0; int px = (instr & (1 << 24)) != 0; - uint32_t imm = (instr >> 15) & 0x7f; + uint64_t imm = (instr >> 15) & 0x7f; uint32_t rn = (instr >> 5) & 0x1f; uint32_t rt1 = (instr >> 0) & 0x1f; uint32_t rt2 = (instr >> 10) & 0x1f; uint32_t shift = 0; - if (imm & 0x40) imm |= ~(uint64_t)0x3f; - if (chk_loaded(rn) < 0) reg_data[rn].o = 0; - if (px && reg_data[rn].o) { - assert(reg_data[rn].o == REG_VAL_OTHER); - reg_data[rn].v += imm << shift; - } if (V) { /* Floating Point */ switch (opc) { @@ -592,6 +586,14 @@ static int loads_and_stores(void) { } else { shift = opc >= 2 ? 3 : 2; + } + if (imm & 0x40) imm |= ~(uint64_t)0x3f; + if (chk_loaded(rn) < 0) reg_data[rn].o = 0; + if (px && reg_data[rn].o) { + assert(reg_data[rn].o == REG_VAL_OTHER); + reg_data[rn].v += imm << shift; + } + if (!V) { if (L) { uint64_t addr = reg_data[rn].v; reg_data[rt1].o = 0; @@ -665,39 +667,39 @@ static int loads_and_stores(void) { if ((instr & 0x3b200c00) == 0x38000000) { /* Load/store register (unscaled immediate) */ - int32_t imm = (instr >> 12) & 0x1ff; - if (imm & 0x100) imm |= 0xffffff00; + int64_t imm = (instr >> 12) & 0x1ff; + if (imm & 0x100) imm |= ~(uint64_t)0xff; chk_loaded(rn); addr_ok = reg_data[rn].o == REG_VAL_OTHER; - addr = reg_data[rn].v + (int64_t)imm; + addr = reg_data[rn].v + imm; instr_ok = 1; } else if ((instr & 0x3b200c00) == 0x38000400) { /* Load/store register (immediate post-indexed) */ - uint32_t imm = (instr >> 12) & 0x1ff; - if (imm & 0x100) imm |= 0xffffff00; + int64_t imm = (instr >> 12) & 0x1ff; + if (imm & 0x100) imm |= ~(uint64_t)0xff; chk_loaded(rn); addr_ok = reg_data[rn].o == REG_VAL_OTHER; addr = reg_data[rn].v; - if (addr_ok) reg_data[rn].v += (int64_t)imm; + if (addr_ok) reg_data[rn].v += imm; instr_ok = 1; } else if ((instr & 0x3b200c00) == 0x38000800) { /* Load/store register (unprivileged) */ - uint32_t imm = (instr >> 12) & 0x1ff; - if (imm & 0x100) imm |= 0xffffff00; + int64_t imm = (instr >> 12) & 0x1ff; + if (imm & 0x100) imm |= ~(uint64_t)0xff; chk_loaded(rn); addr_ok = reg_data[rn].o == REG_VAL_OTHER; - addr = reg_data[rn].v + (int64_t)imm; + addr = reg_data[rn].v + imm; instr_ok = 1; } else if ((instr & 0x3b200c00) == 0x38000c00) { /* Load/store register (immediate pre-indexed) */ - uint32_t imm = (instr >> 12) & 0x1ff; - if (imm & 0x100) imm |= 0xffffff00; + int64_t imm = (instr >> 12) & 0x1ff; + if (imm & 0x100) imm |= ~(uint64_t)0xff; chk_loaded(rn); addr_ok = reg_data[rn].o == REG_VAL_OTHER; - addr = reg_data[rn].v + (int64_t)imm; + addr = reg_data[rn].v + imm; if (addr_ok) reg_data[rn].v = addr; instr_ok = 1; } @@ -837,6 +839,66 @@ static int data_processing_register(void) { return 0; } + if ((instr & 0x1f200000) == 0x0b000000) { + /* Add/subtract (shifted register) */ + int sf = (instr & (1 << 31)) != 0; + int n = (instr & (1 << 30)) != 0; + uint32_t imm = (instr >> 10) & 0x3f; + uint32_t shift = (instr >> 22) & 3; + uint32_t rm = (instr >> 16) & 0x1f; + uint32_t rn = (instr >> 5) & 0x1f; + uint32_t rd = instr & 0x1f; + uint64_t v = 0; + + if (rd == 31) return 0; + + if (rm != 31) { + chk_loaded(rm); + if (reg_data[rm].o != REG_VAL_OTHER) { + reg_data[rd].o = 0; + return 0; + } + v = reg_data[rm].v; + } + switch (shift) { + case 0: /* LSL */ + v = v << imm; + break; + case 1: /* LSR */ + v = v >> imm; + break; + case 2: /* ASR */ + if (!sf) { + int sign = (v & (1 << 31)) != 0; + v = (v & 0xffffffff) >> imm; + if (sign) v |= 0xffffffff << (32 - imm); + } + else { + int sign = (v & ((uint64_t)1 << 63)) != 0; + v = v >> imm; + if (sign) v |= 0xffffffffffffffff << (64 - imm); + } + break; + default: + return 0; + } + if (n) v = ~v + 1; + + if (rn == 31) { + set_reg(rd, sf, v); + } + else { + chk_loaded(rn); + if (reg_data[rn].o == REG_VAL_OTHER) { + set_reg(rd, sf, reg_data[rn].v + v); + } + else { + reg_data[rd].o = 0; + } + } + return 0; + } + return 0; } |