811 lines
17 KiB
C
811 lines
17 KiB
C
/* Print sparc instructions for GDB, the GNU debugger.
|
||
Copyright (C) 1986, 1987 Free Software Foundation, Inc.
|
||
Contributed by Michael Tiemann (tiemann@mcc.com)
|
||
|
||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||
for the consequences of using it or for whether it serves any
|
||
particular purpose or works at all, unless he says so in writing.
|
||
Refer to the GDB General Public License for full details.
|
||
|
||
Everyone is granted permission to copy, modify and redistribute GDB,
|
||
but only under the conditions described in the GDB General Public
|
||
License. A copy of this license is supposed to have been given to you
|
||
along with GDB so you can know your rights and responsibilities. It
|
||
should be in a file named COPYING. Among other things, the copyright
|
||
notice and this notice must be preserved on all copies.
|
||
|
||
In other words, go ahead and share GDB, but don't try to stop
|
||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||
*/
|
||
|
||
#include <stdio.h>
|
||
|
||
#include "defs.h"
|
||
#include "param.h"
|
||
#include "symtab.h"
|
||
#include "sparc-opcode.h"
|
||
|
||
/* sparc instructions are never longer than this many bytes. */
|
||
#define MAXLEN 4
|
||
|
||
/* Print the sparc instruction at address MEMADDR in debugged memory,
|
||
on STREAM. Returns length of the instruction, in bytes, which
|
||
is always 4. */
|
||
|
||
struct op1_fmt
|
||
{
|
||
unsigned op1 : 2;
|
||
unsigned dummy : 30;
|
||
};
|
||
|
||
struct op2_fmt
|
||
{
|
||
unsigned dummy1 : 7;
|
||
unsigned op2 : 3;
|
||
unsigned dummy2 : 22;
|
||
};
|
||
|
||
struct op3_fmt
|
||
{
|
||
unsigned dummy1 : 7;
|
||
unsigned op3 : 6;
|
||
unsigned dummy2 : 19;
|
||
};
|
||
|
||
struct call_fmt
|
||
{
|
||
unsigned op : 2;
|
||
unsigned disp : 30;
|
||
};
|
||
|
||
struct sethi_fmt
|
||
{
|
||
unsigned op : 2;
|
||
unsigned rd : 5;
|
||
unsigned op2 : 3;
|
||
unsigned imm : 22;
|
||
};
|
||
|
||
struct branch_fmt
|
||
{
|
||
unsigned op : 2;
|
||
unsigned a : 1;
|
||
unsigned cond : 4;
|
||
unsigned op2 : 3;
|
||
unsigned disp : 22; /* this should really be signed. */
|
||
};
|
||
|
||
struct ldst_fmt
|
||
{
|
||
unsigned op : 2;
|
||
unsigned rd : 5;
|
||
unsigned op3 : 6;
|
||
unsigned rs1 : 5;
|
||
unsigned i : 1;
|
||
unsigned asi : 8;
|
||
unsigned rs2 : 5;
|
||
};
|
||
|
||
struct arith_imm_fmt
|
||
{
|
||
unsigned op : 2;
|
||
unsigned rd : 5;
|
||
unsigned op3 : 6;
|
||
unsigned rs1 : 5;
|
||
unsigned i : 1;
|
||
unsigned simm : 13;
|
||
};
|
||
|
||
struct arith_fmt
|
||
{
|
||
unsigned op : 2;
|
||
unsigned rd : 5;
|
||
unsigned op3 : 6;
|
||
unsigned rs1 : 5;
|
||
unsigned i : 1;
|
||
unsigned opf : 8;
|
||
unsigned rs2 : 5;
|
||
};
|
||
|
||
union insn_fmt
|
||
{
|
||
struct op1_fmt op1;
|
||
struct op2_fmt op2;
|
||
struct op3_fmt op3;
|
||
struct call_fmt call;
|
||
struct sethi_fmt sethi;
|
||
struct branch_fmt branch;
|
||
struct ldst_fmt ldst;
|
||
struct arith_imm_fmt arith_imm;
|
||
struct arith_fmt arith;
|
||
int intval;
|
||
float floatval; /* ?? */
|
||
};
|
||
|
||
typedef enum
|
||
{
|
||
Error, not_branch, bicc, bicca, ba, baa, ticc, ta,
|
||
} branch_type;
|
||
|
||
static char *icc_name[] =
|
||
{ "~", "eq", "le", "lt", "leu", "ltu", "neg", "vs",
|
||
"", "ne", "gt", "ge", "gtu", "geu", "pos", "vc"};
|
||
|
||
static char *fcc_name[] =
|
||
{ "~fb", "fbne", "fblg", "fbul", "fbl", "fbug", "fbg", "fbu",
|
||
"fb", "fbe", "fbue", "fbge", "fbuge", "fble", "fbule", "fbo"};
|
||
|
||
static char *ccc_name[] =
|
||
{ "~cb", "cb123", "cb12", "cb13", "cb1", "cb23", "cb2", "cb3",
|
||
"cb", "cb0", "cb03", "cb02", "cb023", "cb01", "cb013", "cb012"};
|
||
|
||
static char *arith_name[] =
|
||
{ "add", "and", "or", "xor", "sub", "andn", "orn", "xnor",
|
||
"addx", 0, 0, 0, "subx", 0, 0, 0};
|
||
|
||
static char *xarith_name[] =
|
||
{ "taddcc", "tsubcc", "taddcctv", "tsubcctv", "mulscc", "sll", "srl", "sra"};
|
||
|
||
static char *state_reg_name[] =
|
||
{ "%y", "%psr", "%wim", "%tbr", 0, 0, 0, 0};
|
||
|
||
static char *ldst_i_name[] =
|
||
{ "ld", "ldub", "lduh", "ldd", "st", "stb", "sth", "std",
|
||
0, "ldsb", "ldsh", 0, 0, "ldstub", 0, "swap",
|
||
"lda", "lduba", "lduha", "ldda", "sta", "stba", "stha", "stda",
|
||
0, "ldsba", "ldsha", 0, 0, "ldstuba", 0, "swapa"};
|
||
|
||
static char *ldst_f_name[] =
|
||
{ "ldf", "ldfsr", 0, "lddf", "stf", "stfsr", "stdfq", "stdf"};
|
||
|
||
static char *ldst_c_name[] =
|
||
{ "ldc", "ldcsr", 0, "lddc", "stc", "stcsr", "stdcq", "stdc"};
|
||
|
||
static int this_sethi_target = -1;
|
||
static int last_sethi_target = -1;
|
||
static int sethi_value = 0;
|
||
|
||
static void fprint_addr1 ();
|
||
static void fprint_ldst ();
|
||
static void fprint_f_ldst ();
|
||
static void fprint_c_ldst ();
|
||
static void fprint_fpop ();
|
||
|
||
int
|
||
print_insn (memaddr, stream)
|
||
CORE_ADDR memaddr;
|
||
FILE *stream;
|
||
{
|
||
union insn_fmt insn;
|
||
int disp22;
|
||
|
||
read_memory (memaddr, &insn, MAXLEN);
|
||
|
||
this_sethi_target = -1;
|
||
switch (insn.op1.op1)
|
||
{
|
||
case 1:
|
||
/* CALL format. */
|
||
fprintf (stream, "call ");
|
||
print_address (memaddr + (insn.call.disp << 2), stream);
|
||
break;
|
||
case 0:
|
||
/* Bicc, FBfcc, CBccc, SETHI format. */
|
||
switch (insn.op2.op2)
|
||
{
|
||
case 0:
|
||
fprintf (stream, "unimp");
|
||
break;
|
||
case 2:
|
||
/* Bicc. */
|
||
fprintf (stream, "b%s", icc_name[insn.branch.cond]);
|
||
if (insn.branch.a) fprintf (stream, ",a ");
|
||
else fprintf (stream, " ");
|
||
disp22 = insn.branch.disp;
|
||
disp22 = ((disp22 << 10) >> 10);
|
||
print_address (memaddr + (disp22 << 2), stream);
|
||
break;
|
||
case 4:
|
||
/* SETHI. */
|
||
fprintf (stream, "sethi %%hi(0x%x),%s",
|
||
insn.sethi.imm << 10, reg_names[insn.sethi.rd]);
|
||
this_sethi_target = insn.sethi.rd;
|
||
sethi_value = insn.sethi.imm << 12;
|
||
break;
|
||
case 6:
|
||
/* FBdfcc. */
|
||
fprintf (stream, "fb%s", fcc_name[insn.branch.cond]);
|
||
if (insn.branch.a) fprintf (stream, ",a ");
|
||
else fprintf (stream, " ");
|
||
disp22 = insn.branch.disp;
|
||
disp22 = ((disp22 << 10) >> 10);
|
||
print_address (memaddr + (disp22 << 2), stream);
|
||
break;
|
||
case 7:
|
||
/* CBccc. */
|
||
fprintf (stream, "cb%s", ccc_name[insn.branch.cond]);
|
||
if (insn.branch.a) fprintf (stream, ",a ");
|
||
else fprintf (stream, " ");
|
||
disp22 = insn.branch.disp;
|
||
disp22 = ((disp22 << 10) >> 10);
|
||
print_address (memaddr + (disp22 << 2), stream);
|
||
break;
|
||
default:
|
||
fprintf (stream, "0x%x (illegal op2 format)", insn.intval);
|
||
break;
|
||
}
|
||
break;
|
||
case 2:
|
||
{
|
||
/* vaguely arithmetic insns. */
|
||
char *rd = reg_names[insn.arith.rd];
|
||
char *rs1 = reg_names[insn.arith.rs1];
|
||
|
||
if (insn.op3.op3 <= 28)
|
||
{
|
||
/* Arithmetic insns, with a few unimplemented. */
|
||
register int affect_cc = insn.op3.op3 & 16;
|
||
char *name = arith_name[insn.op3.op3 ^ affect_cc];
|
||
char *tmp = affect_cc ? "cc" : "";
|
||
|
||
if (name == 0)
|
||
{
|
||
fprintf (stream, "0x%08x (unimplemented arithmetic insn)",
|
||
insn.intval);
|
||
}
|
||
else if (insn.arith.i)
|
||
{
|
||
fprintf (stream, "%s%s %s,0x%x,%s",
|
||
name, tmp, rs1, insn.arith_imm.simm, rd);
|
||
if (last_sethi_target == insn.arith.rd)
|
||
{
|
||
fprintf (stream, "\t! ");
|
||
print_address (sethi_value + insn.arith_imm.simm);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
fprintf (stream, "%s%s %s,%s,%s",
|
||
name, tmp, rs1, reg_names[insn.arith.rs2], rd);
|
||
}
|
||
break;
|
||
}
|
||
if (insn.op3.op3 < 32)
|
||
{
|
||
fprintf (stream, "0x%08x (unimplemented arithmetic insn)",
|
||
insn.intval);
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
int op = insn.op3.op3 ^ 32;
|
||
|
||
if (op < 8)
|
||
{
|
||
char *name = xarith_name[op];
|
||
/* tagged add/sub insns and shift insns. */
|
||
if (insn.arith.i)
|
||
{
|
||
int i = insn.arith_imm.simm;
|
||
if (op > 4)
|
||
/* Its a shift insn. */
|
||
i &= 31;
|
||
|
||
fprintf (stream, "%s %s,0x%x,%s",
|
||
name, rs1, i, rd);
|
||
}
|
||
else
|
||
{
|
||
fprintf (stream, "%s %s,%s,%s",
|
||
name, rs1, reg_names[insn.arith.rs2], rd);
|
||
}
|
||
break;
|
||
}
|
||
if (op < 20)
|
||
{
|
||
/* read/write state registers. */
|
||
char *sr = state_reg_name[op & 7];
|
||
if (sr == 0)
|
||
fprintf (stream, "0x%08x (unimplemented state register insn",
|
||
insn.intval);
|
||
else
|
||
fprintf (stream, "%s %s,%s", op & 16 ? "wr" : "rd", sr, rd);
|
||
break;
|
||
}
|
||
if (op < 22)
|
||
{
|
||
/* floating point insns. */
|
||
int opcode = insn.arith.opf;
|
||
|
||
fprint_fpop (stream, insn, op & 3, opcode);
|
||
break;
|
||
}
|
||
if (op < 24)
|
||
{
|
||
/* coprocessor insns. */
|
||
char *rs2 = reg_names[insn.arith.rs2];
|
||
int opcode = insn.arith.opf;
|
||
|
||
fprintf (stream, "cpop%d rs1=%s,rs2=%s,op=0x%x,rd=%s",
|
||
op & 1, rs1, rs2, opcode, rd);
|
||
break;
|
||
}
|
||
|
||
switch (op)
|
||
{
|
||
char *rndop_ptr;
|
||
|
||
case 24:
|
||
fprint_addr1 (stream, "jumpl", insn);
|
||
break;
|
||
case 25:
|
||
fprint_addr1 (stream, "rett", insn);
|
||
break;
|
||
case 26:
|
||
{
|
||
char rndop_buf[32];
|
||
sprintf (rndop_buf, "t%s", icc_name[insn.branch.cond]);
|
||
fprint_addr1 (stream, rndop_buf, insn);
|
||
}
|
||
break;
|
||
case 27:
|
||
fprint_addr1 (stream, "iflush", insn);
|
||
break;
|
||
|
||
case 28:
|
||
rndop_ptr = "save";
|
||
case 29:
|
||
if (op == 29)
|
||
rndop_ptr = "restore";
|
||
|
||
if (insn.arith.i)
|
||
{
|
||
fprintf (stream, "%s %s,0x%x,%s",
|
||
rndop_ptr, rs1,
|
||
((insn.arith_imm.simm << 19) >> 19), rd);
|
||
}
|
||
else
|
||
{
|
||
fprintf (stream, "%s %s,%s,%s",
|
||
rndop_ptr, rs1, reg_names[insn.arith.rs2], rd);
|
||
}
|
||
break;
|
||
case 30:
|
||
case 31:
|
||
fprintf (stream, "0x%08x (unimplemented op3 insn)",
|
||
insn.intval);
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
case 3:
|
||
/* load and store insns. */
|
||
{
|
||
char *rd = reg_names[insn.arith.rd];
|
||
char *rs1 = reg_names[insn.arith.rs1];
|
||
int op = insn.arith.op3;
|
||
|
||
if ((op & 32) == 0)
|
||
{
|
||
/* Integer ops. */
|
||
fprint_ldst (stream, insn, op);
|
||
break;
|
||
}
|
||
if ((op & 16) == 0)
|
||
{
|
||
/* Float ops. */
|
||
op ^= 32;
|
||
if (op <= 7)
|
||
{
|
||
fprint_f_ldst (stream, insn, op);
|
||
}
|
||
else
|
||
fprintf (stream, "0x%08x (unimplemented float load/store insn)",
|
||
insn.intval);
|
||
}
|
||
else
|
||
{
|
||
/* Coprocessor ops. */
|
||
op ^= (32+16);
|
||
if (op <= 7)
|
||
{
|
||
fprint_c_ldst (stream, insn, op);
|
||
}
|
||
else
|
||
fprintf (stream, "0x%08x (unimplemented coprocessor load/store insn)",
|
||
insn.intval);
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
return 4;
|
||
}
|
||
|
||
/* It would be nice if this routine could print out a symbolic address
|
||
when appropriate. */
|
||
static void
|
||
fprint_addr1 (stream, name, insn)
|
||
FILE *stream;
|
||
char *name;
|
||
union insn_fmt insn;
|
||
{
|
||
char *rs1 = reg_names[insn.arith.rs1];
|
||
char *rd = reg_names[insn.arith.rd];
|
||
|
||
if (insn.arith.i)
|
||
{
|
||
fprintf (stream, "%s %s,0x%x,%s",
|
||
name, rs1, insn.arith_imm.simm, rd);
|
||
}
|
||
else
|
||
{
|
||
fprintf (stream, "%s %s,%s,%s",
|
||
name, rs1, reg_names[insn.arith.rs2], rd);
|
||
}
|
||
}
|
||
|
||
static void
|
||
fprint_mem (stream, insn)
|
||
FILE *stream;
|
||
union insn_fmt insn;
|
||
{
|
||
char *reg_name = reg_names[insn.arith.rs1];
|
||
if (insn.arith.i)
|
||
{
|
||
if (insn.arith_imm.simm == 0)
|
||
fprintf (stream, "[%s]", reg_name);
|
||
else if (insn.arith_imm.simm & 0x1000)
|
||
fprintf (stream, "[%s-0x%x]", reg_name,
|
||
- (insn.arith_imm.simm | 0xffffe000));
|
||
else
|
||
fprintf (stream, "[%s+0x%x]", reg_name, insn.arith_imm.simm);
|
||
}
|
||
else
|
||
{
|
||
if (insn.arith.rs2 == 0)
|
||
fprintf (stream, "[%s]", reg_name);
|
||
else
|
||
fprintf (stream, "[%s,%s]", reg_names[insn.arith.rs2], reg_name);
|
||
}
|
||
}
|
||
|
||
static void
|
||
fprint_ldst (stream, insn, op)
|
||
FILE *stream;
|
||
union insn_fmt insn;
|
||
int op;
|
||
{
|
||
char *name = ldst_i_name[op];
|
||
char *rd = reg_names[insn.arith.rd];
|
||
|
||
if (name)
|
||
{
|
||
if (name[0] == 's')
|
||
{
|
||
fprintf (stream, "%s %s,", name, rd);
|
||
fprint_mem (stream, insn);
|
||
}
|
||
else
|
||
{
|
||
fprintf (stream, "%s ", name);
|
||
fprint_mem (stream, insn);
|
||
fprintf (stream, ",%s", rd);
|
||
}
|
||
}
|
||
else
|
||
fprintf (stream, "0x%08x (unimplemented load/store insn)", insn.intval);
|
||
}
|
||
|
||
static void
|
||
fprint_f_ldst (stream, insn, op)
|
||
FILE *stream;
|
||
union insn_fmt insn;
|
||
int op;
|
||
{
|
||
char *name = ldst_f_name[op];
|
||
if (name)
|
||
{
|
||
char *rd = reg_names[insn.arith.rd + 32];
|
||
|
||
if (name[0] == 's')
|
||
{
|
||
fprintf (stream, "%s %s,", name, rd);
|
||
fprint_mem (stream, insn);
|
||
}
|
||
else
|
||
{
|
||
fprintf (stream, "%s ", name);
|
||
fprint_mem (stream, insn);
|
||
fprintf (stream, ",%s", rd);
|
||
}
|
||
}
|
||
else
|
||
fprintf (stream, "0x%08x (unimplemented float load/store insn)", insn.intval);
|
||
}
|
||
|
||
static void
|
||
fprint_c_ldst (stream, insn, op)
|
||
FILE *stream;
|
||
union insn_fmt insn;
|
||
int op;
|
||
{
|
||
char *name = ldst_c_name[op];
|
||
if (name)
|
||
{
|
||
if (name[0] == 's')
|
||
{
|
||
fprintf (stream, "%s %%cpreg(%d),", name, insn.arith.rs1);
|
||
fprint_mem (stream, insn);
|
||
}
|
||
else
|
||
{
|
||
fprintf (stream, "%s ");
|
||
fprint_mem (stream, insn);
|
||
fprintf (stream, ",%%cpreg(%d)", insn.arith.rd);
|
||
}
|
||
}
|
||
else
|
||
fprintf (stream, "0x%08x (unimplemented coprocessor load/store insn)",
|
||
insn.intval);
|
||
}
|
||
|
||
static void
|
||
fprint_fpop (stream, insn, op, opcode)
|
||
FILE *stream;
|
||
union insn_fmt insn;
|
||
int op, opcode;
|
||
{
|
||
char *name;
|
||
char *rs1, *rs2, *rd;
|
||
|
||
switch (op)
|
||
{
|
||
case 0:
|
||
rs2 = reg_names[insn.arith.rs2 + 32];
|
||
rd = reg_names[insn.arith.rd + 32];
|
||
if ((opcode ^ 0x2f) <= 0x2f)
|
||
{
|
||
switch (opcode)
|
||
{
|
||
case 0x1:
|
||
name = "fmovs";
|
||
break;
|
||
case 0x5:
|
||
name = "fnegs";
|
||
break;
|
||
case 0x9:
|
||
name = "fabss";
|
||
break;
|
||
case 0x29:
|
||
name = "fsqrts";
|
||
break;
|
||
case 0x2a:
|
||
name = "fsqrtd";
|
||
break;
|
||
case 0x2b:
|
||
name = "fsqrtx";
|
||
break;
|
||
}
|
||
fprintf (stream, "%s %s,%s", name, rs2, rd);
|
||
return;
|
||
}
|
||
if ((opcode ^ 0x5f) <= 0x5f)
|
||
{
|
||
rs1 = reg_names[insn.arith.rs1 + 32];
|
||
switch (opcode)
|
||
{
|
||
case 0x41:
|
||
name = "fadds";
|
||
break;
|
||
case 0x42:
|
||
name = "faddd";
|
||
break;
|
||
case 0x43:
|
||
name = "faddx";
|
||
break;
|
||
case 0x45:
|
||
name = "fsubs";
|
||
break;
|
||
case 0x46:
|
||
name = "fsubd";
|
||
break;
|
||
case 0x47:
|
||
name = "fsubx";
|
||
break;
|
||
case 0x49:
|
||
name = "fmuls";
|
||
break;
|
||
case 0x4a:
|
||
name = "fmuld";
|
||
break;
|
||
case 0x4b:
|
||
name = "fmulx";
|
||
break;
|
||
case 0x4d:
|
||
name = "fdivs";
|
||
break;
|
||
case 0x4e:
|
||
name = "fdivd";
|
||
break;
|
||
case 0x4f:
|
||
name = "fdivx";
|
||
break;
|
||
default:
|
||
goto unimplemented;
|
||
}
|
||
if ((opcode & 0x10) == 0)
|
||
fprintf (stream, "%s %s,%s,%s", name, rs1, rs2, rd);
|
||
else
|
||
fprintf (stream, "%s %s,%s", name, rs1, rs2);
|
||
return;
|
||
}
|
||
if ((opcode ^ 0xdf) <= 0xdf)
|
||
{
|
||
switch (opcode)
|
||
{
|
||
case 0xc4:
|
||
name = "fitos";
|
||
break;
|
||
case 0xc8:
|
||
name = "fitod";
|
||
break;
|
||
case 0xcc:
|
||
name = "fitox";
|
||
break;
|
||
case 0xd1:
|
||
name = "fstoi";
|
||
break;
|
||
case 0xd2:
|
||
name = "fdtoi";
|
||
break;
|
||
case 0xd3:
|
||
name = "fxtoi";
|
||
break;
|
||
case 0xc9:
|
||
name = "fstod";
|
||
break;
|
||
case 0xcd:
|
||
name = "fstox";
|
||
break;
|
||
case 0xc6:
|
||
name = "fdtos";
|
||
break;
|
||
case 0xce:
|
||
name = "fdtox";
|
||
break;
|
||
case 0xc7:
|
||
name = "fxtos";
|
||
break;
|
||
case 0xcb:
|
||
name = "fxtod";
|
||
break;
|
||
default:
|
||
goto unimplemented;
|
||
}
|
||
fprintf (stream, "%s %s,%s", name, rs2, rd);
|
||
return;
|
||
}
|
||
goto unimplemented;
|
||
|
||
case 1:
|
||
rs1 = reg_names[insn.arith.rs1 + 32];
|
||
rs2 = reg_names[insn.arith.rs2 + 32];
|
||
if ((opcode ^ 0x57) <= 0x57)
|
||
{
|
||
switch (opcode)
|
||
{
|
||
case 0x51:
|
||
name = "fcmps";
|
||
break;
|
||
case 0x52:
|
||
name = "fcmpd";
|
||
break;
|
||
case 0x53:
|
||
name = "fcmpx";
|
||
break;
|
||
case 0x55:
|
||
name = "fcmpes";
|
||
break;
|
||
case 0x56:
|
||
name = "fcmped";
|
||
break;
|
||
case 0x57:
|
||
name = "fcmpex";
|
||
break;
|
||
default:
|
||
goto unimplemented;
|
||
}
|
||
fprintf (stream, "%s %s,%s", name, rs1, rs2);
|
||
return;
|
||
}
|
||
else goto unimplemented;
|
||
|
||
case 2:
|
||
case 3:
|
||
goto unimplemented;
|
||
}
|
||
unimplemented:
|
||
fprintf (stream, "0x%08x (unimplemented fpop insn)", insn.intval);
|
||
}
|
||
|
||
/* Set *target if we find a branch */
|
||
branch_type
|
||
isabranch (addr, target)
|
||
CORE_ADDR addr, *target;
|
||
{
|
||
union insn_fmt instr;
|
||
branch_type val = not_branch;
|
||
long offset; /* Must be signed for sign-extend */
|
||
|
||
*target = 0;
|
||
instr.intval = read_memory_integer (addr, 4);
|
||
/* printf("intval = %x\n",instr.intval); */
|
||
switch (instr.op1.op1)
|
||
{
|
||
case 0: /* Format 2 */
|
||
switch(instr.op2.op2)
|
||
{
|
||
case 2: case 6: /* BICC & FBCC */
|
||
if (instr.branch.cond == 8)
|
||
val = instr.branch.a ? baa : ba;
|
||
else
|
||
val = instr.branch.a ? bicca : bicc;
|
||
/* 22 bits, sign extended */
|
||
offset = ((instr.branch.disp << 10) >> 10);
|
||
*target = addr + offset;
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
/*printf("isabranch ret: %d\n",val); */
|
||
return val;
|
||
}
|
||
|
||
CORE_ADDR skip_prologue (pc)
|
||
CORE_ADDR pc;
|
||
{
|
||
union
|
||
{
|
||
struct insn_fmt insn;
|
||
int i;
|
||
} x;
|
||
int dest = -1;
|
||
|
||
x.i = read_memory_integer (pc, 4);
|
||
if (x.insn.sethi.op == 0 && x.insn.sethi.op2 == 4)
|
||
{
|
||
dest = x.insn.sethi.rd;
|
||
pc += 4;
|
||
x.i = read_memory_integer (pc, 4);
|
||
}
|
||
if (x.insn.arith_imm.op == 2 && x.insn.arith_imm.i == 1
|
||
&& (x.insn.arith_imm.rd == 1 || x.insn.arith_imm.rd == dest))
|
||
{
|
||
pc += 4;
|
||
x.i = read_memory_integer (pc, 4);
|
||
}
|
||
if (x.insn.arith.op == 2 && (x.insn.arith.op3 ^ 32) == 28)
|
||
{
|
||
pc += 4;
|
||
}
|
||
return pc;
|
||
}
|
||
|
||
CORE_ADDR
|
||
frame_saved_pc (frame, next_frame)
|
||
CORE_ADDR frame;
|
||
CORE_ADDR next_frame;
|
||
{
|
||
CORE_ADDR prev_pc;
|
||
|
||
if (next_frame)
|
||
prev_pc = GET_RWINDOW_REG (next_frame, rw_in[7]);
|
||
else if (frame)
|
||
prev_pc = GET_RWINDOW_REG (read_register (SP_REGNUM), rw_in[7]);
|
||
else
|
||
error ("frame_saved_pc called without a frame");
|
||
|
||
return PC_ADJUST (prev_pc);
|
||
}
|