diff --git a/gdb/convx-opcode.h b/gdb/convx-opcode.h new file mode 100644 index 0000000000..523c8744c2 --- /dev/null +++ b/gdb/convx-opcode.h @@ -0,0 +1,1677 @@ +/* Include information for instruction dissasembly on the Convex. + Copyright (C) 1989, Free Software Foundation. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define xxx 0 +#define rrr 1 +#define rr 2 +#define rxr 3 +#define r 4 +#define nops 5 +#define nr 6 +#define pcrel 7 +#define lr 8 +#define rxl 9 +#define rlr 10 +#define rrl 11 +#define iml 12 +#define imr 13 +#define a1r 14 +#define a1l 15 +#define a2r 16 +#define a2l 17 +#define a3 18 +#define a4 19 +#define a5 20 +#define V 1 +#define S 2 +#define VM 3 +#define A 4 +#define VL 5 +#define VS 6 +#define VLS 7 +#define PSW 8 +/* Prevent an error during "make depend". */ +#if !defined (PC) +#define PC 9 +#endif +#define ITR 10 +#define VV 11 +#define ITSR 12 +#define TOC 13 +#define CIR 14 +#define TTR 15 +#define VMU 16 +#define VML 17 +#define ICR 18 +#define TCPU 19 +#define CPUID 20 +#define TID 21 +char *op[] = { + "", + "v0\0v1\0v2\0v3\0v4\0v5\0v6\0v7", + "s0\0s1\0s2\0s3\0s4\0s5\0s6\0s7", + "vm", + "sp\0a1\0a2\0a3\0a4\0a5\0ap\0fp", + "vl", + "vs", + "vls", + "psw", + "pc", + "itr", + "vv", + "itsr", + "toc", + "cir", + "ttr", + "vmu", + "vml", + "icr", + "tcpu", + "cpuid", + "tid", +}; +struct formstr format0[] = { + {0,0,rrr,V,S,S}, /* mov */ + {0,0,rrr,S,S,V}, /* mov */ + {1,1,rrr,V,V,V}, /* merg.t */ + {2,1,rrr,V,V,V}, /* mask.t */ + {1,2,rrr,V,S,V}, /* merg.f */ + {2,2,rrr,V,S,V}, /* mask.f */ + {1,1,rrr,V,S,V}, /* merg.t */ + {2,1,rrr,V,S,V}, /* mask.t */ + {3,3,rrr,V,V,V}, /* mul.s */ + {3,4,rrr,V,V,V}, /* mul.d */ + {4,3,rrr,V,V,V}, /* div.s */ + {4,4,rrr,V,V,V}, /* div.d */ + {3,3,rrr,V,S,V}, /* mul.s */ + {3,4,rrr,V,S,V}, /* mul.d */ + {4,3,rrr,V,S,V}, /* div.s */ + {4,4,rrr,V,S,V}, /* div.d */ + {5,0,rrr,V,V,V}, /* and */ + {6,0,rrr,V,V,V}, /* or */ + {7,0,rrr,V,V,V}, /* xor */ + {8,0,rrr,V,V,V}, /* shf */ + {5,0,rrr,V,S,V}, /* and */ + {6,0,rrr,V,S,V}, /* or */ + {7,0,rrr,V,S,V}, /* xor */ + {8,0,rrr,V,S,V}, /* shf */ + {9,3,rrr,V,V,V}, /* add.s */ + {9,4,rrr,V,V,V}, /* add.d */ + {10,3,rrr,V,V,V}, /* sub.s */ + {10,4,rrr,V,V,V}, /* sub.d */ + {9,3,rrr,V,S,V}, /* add.s */ + {9,4,rrr,V,S,V}, /* add.d */ + {10,3,rrr,V,S,V}, /* sub.s */ + {10,4,rrr,V,S,V}, /* sub.d */ + {9,5,rrr,V,V,V}, /* add.b */ + {9,6,rrr,V,V,V}, /* add.h */ + {9,7,rrr,V,V,V}, /* add.w */ + {9,8,rrr,V,V,V}, /* add.l */ + {9,5,rrr,V,S,V}, /* add.b */ + {9,6,rrr,V,S,V}, /* add.h */ + {9,7,rrr,V,S,V}, /* add.w */ + {9,8,rrr,V,S,V}, /* add.l */ + {10,5,rrr,V,V,V}, /* sub.b */ + {10,6,rrr,V,V,V}, /* sub.h */ + {10,7,rrr,V,V,V}, /* sub.w */ + {10,8,rrr,V,V,V}, /* sub.l */ + {10,5,rrr,V,S,V}, /* sub.b */ + {10,6,rrr,V,S,V}, /* sub.h */ + {10,7,rrr,V,S,V}, /* sub.w */ + {10,8,rrr,V,S,V}, /* sub.l */ + {3,5,rrr,V,V,V}, /* mul.b */ + {3,6,rrr,V,V,V}, /* mul.h */ + {3,7,rrr,V,V,V}, /* mul.w */ + {3,8,rrr,V,V,V}, /* mul.l */ + {3,5,rrr,V,S,V}, /* mul.b */ + {3,6,rrr,V,S,V}, /* mul.h */ + {3,7,rrr,V,S,V}, /* mul.w */ + {3,8,rrr,V,S,V}, /* mul.l */ + {4,5,rrr,V,V,V}, /* div.b */ + {4,6,rrr,V,V,V}, /* div.h */ + {4,7,rrr,V,V,V}, /* div.w */ + {4,8,rrr,V,V,V}, /* div.l */ + {4,5,rrr,V,S,V}, /* div.b */ + {4,6,rrr,V,S,V}, /* div.h */ + {4,7,rrr,V,S,V}, /* div.w */ + {4,8,rrr,V,S,V}, /* div.l */ +}; +struct formstr format1[] = { + {11,0,xxx,0,0,0}, /* exit */ + {12,0,a3,0,0,0}, /* jmp */ + {13,2,a3,0,0,0}, /* jmpi.f */ + {13,1,a3,0,0,0}, /* jmpi.t */ + {14,2,a3,0,0,0}, /* jmpa.f */ + {14,1,a3,0,0,0}, /* jmpa.t */ + {15,2,a3,0,0,0}, /* jmps.f */ + {15,1,a3,0,0,0}, /* jmps.t */ + {16,0,a3,0,0,0}, /* tac */ + {17,0,a1r,A,0,0}, /* ldea */ + {18,8,a1l,VLS,0,0}, /* ld.l */ + {18,9,a1l,VM,0,0}, /* ld.x */ + {19,0,a3,0,0,0}, /* tas */ + {20,0,a3,0,0,0}, /* pshea */ + {21,8,a2l,VLS,0,0}, /* st.l */ + {21,9,a2l,VM,0,0}, /* st.x */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {22,0,a3,0,0,0}, /* call */ + {23,0,a3,0,0,0}, /* calls */ + {24,0,a3,0,0,0}, /* callq */ + {25,0,a1r,A,0,0}, /* pfork */ + {26,5,a2r,S,0,0}, /* ste.b */ + {26,6,a2r,S,0,0}, /* ste.h */ + {26,7,a2r,S,0,0}, /* ste.w */ + {26,8,a2r,S,0,0}, /* ste.l */ + {18,5,a1r,A,0,0}, /* ld.b */ + {18,6,a1r,A,0,0}, /* ld.h */ + {18,7,a1r,A,0,0}, /* ld.w */ + {27,7,a1r,A,0,0}, /* incr.w */ + {21,5,a2r,A,0,0}, /* st.b */ + {21,6,a2r,A,0,0}, /* st.h */ + {21,7,a2r,A,0,0}, /* st.w */ + {27,8,a1r,S,0,0}, /* incr.l */ + {18,5,a1r,S,0,0}, /* ld.b */ + {18,6,a1r,S,0,0}, /* ld.h */ + {18,7,a1r,S,0,0}, /* ld.w */ + {18,8,a1r,S,0,0}, /* ld.l */ + {21,5,a2r,S,0,0}, /* st.b */ + {21,6,a2r,S,0,0}, /* st.h */ + {21,7,a2r,S,0,0}, /* st.w */ + {21,8,a2r,S,0,0}, /* st.l */ + {18,5,a1r,V,0,0}, /* ld.b */ + {18,6,a1r,V,0,0}, /* ld.h */ + {18,7,a1r,V,0,0}, /* ld.w */ + {18,8,a1r,V,0,0}, /* ld.l */ + {21,5,a2r,V,0,0}, /* st.b */ + {21,6,a2r,V,0,0}, /* st.h */ + {21,7,a2r,V,0,0}, /* st.w */ + {21,8,a2r,V,0,0}, /* st.l */ +}; +struct formstr format2[] = { + {28,5,rr,A,A,0}, /* cvtw.b */ + {28,6,rr,A,A,0}, /* cvtw.h */ + {29,7,rr,A,A,0}, /* cvtb.w */ + {30,7,rr,A,A,0}, /* cvth.w */ + {28,5,rr,S,S,0}, /* cvtw.b */ + {28,6,rr,S,S,0}, /* cvtw.h */ + {29,7,rr,S,S,0}, /* cvtb.w */ + {30,7,rr,S,S,0}, /* cvth.w */ + {28,3,rr,S,S,0}, /* cvtw.s */ + {31,7,rr,S,S,0}, /* cvts.w */ + {32,3,rr,S,S,0}, /* cvtd.s */ + {31,4,rr,S,S,0}, /* cvts.d */ + {31,8,rr,S,S,0}, /* cvts.l */ + {32,8,rr,S,S,0}, /* cvtd.l */ + {33,3,rr,S,S,0}, /* cvtl.s */ + {33,4,rr,S,S,0}, /* cvtl.d */ + {34,0,rr,A,A,0}, /* ldpa */ + {8,0,nr,A,0,0}, /* shf */ + {18,6,nr,A,0,0}, /* ld.h */ + {18,7,nr,A,0,0}, /* ld.w */ + {33,7,rr,S,S,0}, /* cvtl.w */ + {28,8,rr,S,S,0}, /* cvtw.l */ + {35,1,rr,S,S,0}, /* plc.t */ + {36,0,rr,S,S,0}, /* tzc */ + {37,6,rr,A,A,0}, /* eq.h */ + {37,7,rr,A,A,0}, /* eq.w */ + {37,6,nr,A,0,0}, /* eq.h */ + {37,7,nr,A,0,0}, /* eq.w */ + {37,5,rr,S,S,0}, /* eq.b */ + {37,6,rr,S,S,0}, /* eq.h */ + {37,7,rr,S,S,0}, /* eq.w */ + {37,8,rr,S,S,0}, /* eq.l */ + {38,6,rr,A,A,0}, /* leu.h */ + {38,7,rr,A,A,0}, /* leu.w */ + {38,6,nr,A,0,0}, /* leu.h */ + {38,7,nr,A,0,0}, /* leu.w */ + {38,5,rr,S,S,0}, /* leu.b */ + {38,6,rr,S,S,0}, /* leu.h */ + {38,7,rr,S,S,0}, /* leu.w */ + {38,8,rr,S,S,0}, /* leu.l */ + {39,6,rr,A,A,0}, /* ltu.h */ + {39,7,rr,A,A,0}, /* ltu.w */ + {39,6,nr,A,0,0}, /* ltu.h */ + {39,7,nr,A,0,0}, /* ltu.w */ + {39,5,rr,S,S,0}, /* ltu.b */ + {39,6,rr,S,S,0}, /* ltu.h */ + {39,7,rr,S,S,0}, /* ltu.w */ + {39,8,rr,S,S,0}, /* ltu.l */ + {40,6,rr,A,A,0}, /* le.h */ + {40,7,rr,A,A,0}, /* le.w */ + {40,6,nr,A,0,0}, /* le.h */ + {40,7,nr,A,0,0}, /* le.w */ + {40,5,rr,S,S,0}, /* le.b */ + {40,6,rr,S,S,0}, /* le.h */ + {40,7,rr,S,S,0}, /* le.w */ + {40,8,rr,S,S,0}, /* le.l */ + {41,6,rr,A,A,0}, /* lt.h */ + {41,7,rr,A,A,0}, /* lt.w */ + {41,6,nr,A,0,0}, /* lt.h */ + {41,7,nr,A,0,0}, /* lt.w */ + {41,5,rr,S,S,0}, /* lt.b */ + {41,6,rr,S,S,0}, /* lt.h */ + {41,7,rr,S,S,0}, /* lt.w */ + {41,8,rr,S,S,0}, /* lt.l */ + {9,7,rr,S,A,0}, /* add.w */ + {8,0,rr,A,A,0}, /* shf */ + {0,0,rr,A,A,0}, /* mov */ + {0,0,rr,S,A,0}, /* mov */ + {0,7,rr,S,S,0}, /* mov.w */ + {8,0,rr,S,S,0}, /* shf */ + {0,0,rr,S,S,0}, /* mov */ + {0,0,rr,A,S,0}, /* mov */ + {5,0,rr,A,A,0}, /* and */ + {6,0,rr,A,A,0}, /* or */ + {7,0,rr,A,A,0}, /* xor */ + {42,0,rr,A,A,0}, /* not */ + {5,0,rr,S,S,0}, /* and */ + {6,0,rr,S,S,0}, /* or */ + {7,0,rr,S,S,0}, /* xor */ + {42,0,rr,S,S,0}, /* not */ + {40,3,rr,S,S,0}, /* le.s */ + {40,4,rr,S,S,0}, /* le.d */ + {41,3,rr,S,S,0}, /* lt.s */ + {41,4,rr,S,S,0}, /* lt.d */ + {9,3,rr,S,S,0}, /* add.s */ + {9,4,rr,S,S,0}, /* add.d */ + {10,3,rr,S,S,0}, /* sub.s */ + {10,4,rr,S,S,0}, /* sub.d */ + {37,3,rr,S,S,0}, /* eq.s */ + {37,4,rr,S,S,0}, /* eq.d */ + {43,6,rr,A,A,0}, /* neg.h */ + {43,7,rr,A,A,0}, /* neg.w */ + {3,3,rr,S,S,0}, /* mul.s */ + {3,4,rr,S,S,0}, /* mul.d */ + {4,3,rr,S,S,0}, /* div.s */ + {4,4,rr,S,S,0}, /* div.d */ + {9,6,rr,A,A,0}, /* add.h */ + {9,7,rr,A,A,0}, /* add.w */ + {9,6,nr,A,0,0}, /* add.h */ + {9,7,nr,A,0,0}, /* add.w */ + {9,5,rr,S,S,0}, /* add.b */ + {9,6,rr,S,S,0}, /* add.h */ + {9,7,rr,S,S,0}, /* add.w */ + {9,8,rr,S,S,0}, /* add.l */ + {10,6,rr,A,A,0}, /* sub.h */ + {10,7,rr,A,A,0}, /* sub.w */ + {10,6,nr,A,0,0}, /* sub.h */ + {10,7,nr,A,0,0}, /* sub.w */ + {10,5,rr,S,S,0}, /* sub.b */ + {10,6,rr,S,S,0}, /* sub.h */ + {10,7,rr,S,S,0}, /* sub.w */ + {10,8,rr,S,S,0}, /* sub.l */ + {3,6,rr,A,A,0}, /* mul.h */ + {3,7,rr,A,A,0}, /* mul.w */ + {3,6,nr,A,0,0}, /* mul.h */ + {3,7,nr,A,0,0}, /* mul.w */ + {3,5,rr,S,S,0}, /* mul.b */ + {3,6,rr,S,S,0}, /* mul.h */ + {3,7,rr,S,S,0}, /* mul.w */ + {3,8,rr,S,S,0}, /* mul.l */ + {4,6,rr,A,A,0}, /* div.h */ + {4,7,rr,A,A,0}, /* div.w */ + {4,6,nr,A,0,0}, /* div.h */ + {4,7,nr,A,0,0}, /* div.w */ + {4,5,rr,S,S,0}, /* div.b */ + {4,6,rr,S,S,0}, /* div.h */ + {4,7,rr,S,S,0}, /* div.w */ + {4,8,rr,S,S,0}, /* div.l */ +}; +struct formstr format3[] = { + {32,3,rr,V,V,0}, /* cvtd.s */ + {31,4,rr,V,V,0}, /* cvts.d */ + {33,4,rr,V,V,0}, /* cvtl.d */ + {32,8,rr,V,V,0}, /* cvtd.l */ + {0,0,rrl,S,S,VM}, /* mov */ + {0,0,rlr,S,VM,S}, /* mov */ + {0,0,0,0,0,0}, + {44,0,rr,S,S,0}, /* lop */ + {36,0,rr,V,V,0}, /* tzc */ + {44,0,rr,V,V,0}, /* lop */ + {0,0,0,0,0,0}, + {42,0,rr,V,V,0}, /* not */ + {8,0,rr,S,V,0}, /* shf */ + {35,1,rr,V,V,0}, /* plc.t */ + {45,2,rr,V,V,0}, /* cprs.f */ + {45,1,rr,V,V,0}, /* cprs.t */ + {37,3,rr,V,V,0}, /* eq.s */ + {37,4,rr,V,V,0}, /* eq.d */ + {43,3,rr,V,V,0}, /* neg.s */ + {43,4,rr,V,V,0}, /* neg.d */ + {37,3,rr,S,V,0}, /* eq.s */ + {37,4,rr,S,V,0}, /* eq.d */ + {43,3,rr,S,S,0}, /* neg.s */ + {43,4,rr,S,S,0}, /* neg.d */ + {40,3,rr,V,V,0}, /* le.s */ + {40,4,rr,V,V,0}, /* le.d */ + {41,3,rr,V,V,0}, /* lt.s */ + {41,4,rr,V,V,0}, /* lt.d */ + {40,3,rr,S,V,0}, /* le.s */ + {40,4,rr,S,V,0}, /* le.d */ + {41,3,rr,S,V,0}, /* lt.s */ + {41,4,rr,S,V,0}, /* lt.d */ + {37,5,rr,V,V,0}, /* eq.b */ + {37,6,rr,V,V,0}, /* eq.h */ + {37,7,rr,V,V,0}, /* eq.w */ + {37,8,rr,V,V,0}, /* eq.l */ + {37,5,rr,S,V,0}, /* eq.b */ + {37,6,rr,S,V,0}, /* eq.h */ + {37,7,rr,S,V,0}, /* eq.w */ + {37,8,rr,S,V,0}, /* eq.l */ + {40,5,rr,V,V,0}, /* le.b */ + {40,6,rr,V,V,0}, /* le.h */ + {40,7,rr,V,V,0}, /* le.w */ + {40,8,rr,V,V,0}, /* le.l */ + {40,5,rr,S,V,0}, /* le.b */ + {40,6,rr,S,V,0}, /* le.h */ + {40,7,rr,S,V,0}, /* le.w */ + {40,8,rr,S,V,0}, /* le.l */ + {41,5,rr,V,V,0}, /* lt.b */ + {41,6,rr,V,V,0}, /* lt.h */ + {41,7,rr,V,V,0}, /* lt.w */ + {41,8,rr,V,V,0}, /* lt.l */ + {41,5,rr,S,V,0}, /* lt.b */ + {41,6,rr,S,V,0}, /* lt.h */ + {41,7,rr,S,V,0}, /* lt.w */ + {41,8,rr,S,V,0}, /* lt.l */ + {43,5,rr,V,V,0}, /* neg.b */ + {43,6,rr,V,V,0}, /* neg.h */ + {43,7,rr,V,V,0}, /* neg.w */ + {43,8,rr,V,V,0}, /* neg.l */ + {43,5,rr,S,S,0}, /* neg.b */ + {43,6,rr,S,S,0}, /* neg.h */ + {43,7,rr,S,S,0}, /* neg.w */ + {43,8,rr,S,S,0}, /* neg.l */ +}; +struct formstr format4[] = { + {46,0,nops,0,0,0}, /* nop */ + {47,0,pcrel,0,0,0}, /* br */ + {48,2,pcrel,0,0,0}, /* bri.f */ + {48,1,pcrel,0,0,0}, /* bri.t */ + {49,2,pcrel,0,0,0}, /* bra.f */ + {49,1,pcrel,0,0,0}, /* bra.t */ + {50,2,pcrel,0,0,0}, /* brs.f */ + {50,1,pcrel,0,0,0}, /* brs.t */ +}; +struct formstr format5[] = { + {51,5,rr,V,V,0}, /* ldvi.b */ + {51,6,rr,V,V,0}, /* ldvi.h */ + {51,7,rr,V,V,0}, /* ldvi.w */ + {51,8,rr,V,V,0}, /* ldvi.l */ + {28,3,rr,V,V,0}, /* cvtw.s */ + {31,7,rr,V,V,0}, /* cvts.w */ + {28,8,rr,V,V,0}, /* cvtw.l */ + {33,7,rr,V,V,0}, /* cvtl.w */ + {52,5,rxr,V,V,0}, /* stvi.b */ + {52,6,rxr,V,V,0}, /* stvi.h */ + {52,7,rxr,V,V,0}, /* stvi.w */ + {52,8,rxr,V,V,0}, /* stvi.l */ + {52,5,rxr,S,V,0}, /* stvi.b */ + {52,6,rxr,S,V,0}, /* stvi.h */ + {52,7,rxr,S,V,0}, /* stvi.w */ + {52,8,rxr,S,V,0}, /* stvi.l */ +}; +struct formstr format6[] = { + {53,0,r,A,0,0}, /* ldsdr */ + {54,0,r,A,0,0}, /* ldkdr */ + {55,3,r,S,0,0}, /* ln.s */ + {55,4,r,S,0,0}, /* ln.d */ + {56,0,nops,0,0,0}, /* patu */ + {57,0,r,A,0,0}, /* pate */ + {58,0,nops,0,0,0}, /* pich */ + {59,0,nops,0,0,0}, /* plch */ + {0,0,lr,PSW,A,0}, /* mov */ + {0,0,rxl,A,PSW,0}, /* mov */ + {0,0,lr,PC,A,0}, /* mov */ + {60,0,r,S,0,0}, /* idle */ + {0,0,lr,ITR,S,0}, /* mov */ + {0,0,rxl,S,ITR,0}, /* mov */ + {0,0,0,0,0,0}, + {0,0,rxl,S,ITSR,0}, /* mov */ + {61,0,nops,0,0,0}, /* rtnq */ + {62,0,nops,0,0,0}, /* cfork */ + {63,0,nops,0,0,0}, /* rtn */ + {64,0,nops,0,0,0}, /* wfork */ + {65,0,nops,0,0,0}, /* join */ + {66,0,nops,0,0,0}, /* rtnc */ + {67,3,r,S,0,0}, /* exp.s */ + {67,4,r,S,0,0}, /* exp.d */ + {68,3,r,S,0,0}, /* sin.s */ + {68,4,r,S,0,0}, /* sin.d */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {69,3,r,S,0,0}, /* cos.s */ + {69,4,r,S,0,0}, /* cos.d */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {70,7,r,A,0,0}, /* psh.w */ + {0,0,0,0,0,0}, + {71,7,r,A,0,0}, /* pop.w */ + {0,0,0,0,0,0}, + {70,7,r,S,0,0}, /* psh.w */ + {70,8,r,S,0,0}, /* psh.l */ + {71,7,r,S,0,0}, /* pop.w */ + {71,8,r,S,0,0}, /* pop.l */ + {72,0,nops,0,0,0}, /* eni */ + {73,0,nops,0,0,0}, /* dsi */ + {74,0,nops,0,0,0}, /* bkpt */ + {75,0,nops,0,0,0}, /* msync */ + {76,0,r,S,0,0}, /* mski */ + {77,0,r,S,0,0}, /* xmti */ + {0,0,rxl,S,VV,0}, /* mov */ + {78,0,nops,0,0,0}, /* tstvv */ + {0,0,lr,VS,A,0}, /* mov */ + {0,0,rxl,A,VS,0}, /* mov */ + {0,0,lr,VL,A,0}, /* mov */ + {0,0,rxl,A,VL,0}, /* mov */ + {0,7,lr,VS,S,0}, /* mov.w */ + {0,7,rxl,S,VS,0}, /* mov.w */ + {0,7,lr,VL,S,0}, /* mov.w */ + {0,7,rxl,S,VL,0}, /* mov.w */ + {79,0,r,A,0,0}, /* diag */ + {80,0,nops,0,0,0}, /* pbkpt */ + {81,3,r,S,0,0}, /* sqrt.s */ + {81,4,r,S,0,0}, /* sqrt.d */ + {82,0,nops,0,0,0}, /* casr */ + {0,0,0,0,0,0}, + {83,3,r,S,0,0}, /* atan.s */ + {83,4,r,S,0,0}, /* atan.d */ +}; +struct formstr format7[] = { + {84,5,r,V,0,0}, /* sum.b */ + {84,6,r,V,0,0}, /* sum.h */ + {84,7,r,V,0,0}, /* sum.w */ + {84,8,r,V,0,0}, /* sum.l */ + {85,0,r,V,0,0}, /* all */ + {86,0,r,V,0,0}, /* any */ + {87,0,r,V,0,0}, /* parity */ + {0,0,0,0,0,0}, + {88,5,r,V,0,0}, /* max.b */ + {88,6,r,V,0,0}, /* max.h */ + {88,7,r,V,0,0}, /* max.w */ + {88,8,r,V,0,0}, /* max.l */ + {89,5,r,V,0,0}, /* min.b */ + {89,6,r,V,0,0}, /* min.h */ + {89,7,r,V,0,0}, /* min.w */ + {89,8,r,V,0,0}, /* min.l */ + {84,3,r,V,0,0}, /* sum.s */ + {84,4,r,V,0,0}, /* sum.d */ + {90,3,r,V,0,0}, /* prod.s */ + {90,4,r,V,0,0}, /* prod.d */ + {88,3,r,V,0,0}, /* max.s */ + {88,4,r,V,0,0}, /* max.d */ + {89,3,r,V,0,0}, /* min.s */ + {89,4,r,V,0,0}, /* min.d */ + {90,5,r,V,0,0}, /* prod.b */ + {90,6,r,V,0,0}, /* prod.h */ + {90,7,r,V,0,0}, /* prod.w */ + {90,8,r,V,0,0}, /* prod.l */ + {35,2,lr,VM,S,0}, /* plc.f */ + {35,1,lr,VM,S,0}, /* plc.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; +struct formstr formatx[] = { + {0,0,0,0,0,0}, +}; +struct formstr format1a[] = { + {91,0,imr,A,0,0}, /* halt */ + {92,0,a4,0,0,0}, /* sysc */ + {18,6,imr,A,0,0}, /* ld.h */ + {18,7,imr,A,0,0}, /* ld.w */ + {5,0,imr,A,0,0}, /* and */ + {6,0,imr,A,0,0}, /* or */ + {7,0,imr,A,0,0}, /* xor */ + {8,0,imr,A,0,0}, /* shf */ + {9,6,imr,A,0,0}, /* add.h */ + {9,7,imr,A,0,0}, /* add.w */ + {10,6,imr,A,0,0}, /* sub.h */ + {10,7,imr,A,0,0}, /* sub.w */ + {3,6,imr,A,0,0}, /* mul.h */ + {3,7,imr,A,0,0}, /* mul.w */ + {4,6,imr,A,0,0}, /* div.h */ + {4,7,imr,A,0,0}, /* div.w */ + {18,7,iml,VL,0,0}, /* ld.w */ + {18,7,iml,VS,0,0}, /* ld.w */ + {0,0,0,0,0,0}, + {8,7,imr,S,0,0}, /* shf.w */ + {93,0,a5,0,0,0}, /* trap */ + {0,0,0,0,0,0}, + {37,6,imr,A,0,0}, /* eq.h */ + {37,7,imr,A,0,0}, /* eq.w */ + {38,6,imr,A,0,0}, /* leu.h */ + {38,7,imr,A,0,0}, /* leu.w */ + {39,6,imr,A,0,0}, /* ltu.h */ + {39,7,imr,A,0,0}, /* ltu.w */ + {40,6,imr,A,0,0}, /* le.h */ + {40,7,imr,A,0,0}, /* le.w */ + {41,6,imr,A,0,0}, /* lt.h */ + {41,7,imr,A,0,0}, /* lt.w */ +}; +struct formstr format1b[] = { + {18,4,imr,S,0,0}, /* ld.d */ + {18,10,imr,S,0,0}, /* ld.u */ + {18,8,imr,S,0,0}, /* ld.l */ + {18,7,imr,S,0,0}, /* ld.w */ + {5,0,imr,S,0,0}, /* and */ + {6,0,imr,S,0,0}, /* or */ + {7,0,imr,S,0,0}, /* xor */ + {8,0,imr,S,0,0}, /* shf */ + {9,6,imr,S,0,0}, /* add.h */ + {9,7,imr,S,0,0}, /* add.w */ + {10,6,imr,S,0,0}, /* sub.h */ + {10,7,imr,S,0,0}, /* sub.w */ + {3,6,imr,S,0,0}, /* mul.h */ + {3,7,imr,S,0,0}, /* mul.w */ + {4,6,imr,S,0,0}, /* div.h */ + {4,7,imr,S,0,0}, /* div.w */ + {9,3,imr,S,0,0}, /* add.s */ + {10,3,imr,S,0,0}, /* sub.s */ + {3,3,imr,S,0,0}, /* mul.s */ + {4,3,imr,S,0,0}, /* div.s */ + {40,3,imr,S,0,0}, /* le.s */ + {41,3,imr,S,0,0}, /* lt.s */ + {37,6,imr,S,0,0}, /* eq.h */ + {37,7,imr,S,0,0}, /* eq.w */ + {38,6,imr,S,0,0}, /* leu.h */ + {38,7,imr,S,0,0}, /* leu.w */ + {39,6,imr,S,0,0}, /* ltu.h */ + {39,7,imr,S,0,0}, /* ltu.w */ + {40,6,imr,S,0,0}, /* le.h */ + {40,7,imr,S,0,0}, /* le.w */ + {41,6,imr,S,0,0}, /* lt.h */ + {41,7,imr,S,0,0}, /* lt.w */ +}; +struct formstr e0_format0[] = { + {10,3,rrr,S,V,V}, /* sub.s */ + {10,4,rrr,S,V,V}, /* sub.d */ + {4,3,rrr,S,V,V}, /* div.s */ + {4,4,rrr,S,V,V}, /* div.d */ + {10,11,rrr,S,V,V}, /* sub.s.f */ + {10,12,rrr,S,V,V}, /* sub.d.f */ + {4,11,rrr,S,V,V}, /* div.s.f */ + {4,12,rrr,S,V,V}, /* div.d.f */ + {3,11,rrr,V,V,V}, /* mul.s.f */ + {3,12,rrr,V,V,V}, /* mul.d.f */ + {4,11,rrr,V,V,V}, /* div.s.f */ + {4,12,rrr,V,V,V}, /* div.d.f */ + {3,11,rrr,V,S,V}, /* mul.s.f */ + {3,12,rrr,V,S,V}, /* mul.d.f */ + {4,11,rrr,V,S,V}, /* div.s.f */ + {4,12,rrr,V,S,V}, /* div.d.f */ + {5,2,rrr,V,V,V}, /* and.f */ + {6,2,rrr,V,V,V}, /* or.f */ + {7,2,rrr,V,V,V}, /* xor.f */ + {8,2,rrr,V,V,V}, /* shf.f */ + {5,2,rrr,V,S,V}, /* and.f */ + {6,2,rrr,V,S,V}, /* or.f */ + {7,2,rrr,V,S,V}, /* xor.f */ + {8,2,rrr,V,S,V}, /* shf.f */ + {9,11,rrr,V,V,V}, /* add.s.f */ + {9,12,rrr,V,V,V}, /* add.d.f */ + {10,11,rrr,V,V,V}, /* sub.s.f */ + {10,12,rrr,V,V,V}, /* sub.d.f */ + {9,11,rrr,V,S,V}, /* add.s.f */ + {9,12,rrr,V,S,V}, /* add.d.f */ + {10,11,rrr,V,S,V}, /* sub.s.f */ + {10,12,rrr,V,S,V}, /* sub.d.f */ + {9,13,rrr,V,V,V}, /* add.b.f */ + {9,14,rrr,V,V,V}, /* add.h.f */ + {9,15,rrr,V,V,V}, /* add.w.f */ + {9,16,rrr,V,V,V}, /* add.l.f */ + {9,13,rrr,V,S,V}, /* add.b.f */ + {9,14,rrr,V,S,V}, /* add.h.f */ + {9,15,rrr,V,S,V}, /* add.w.f */ + {9,16,rrr,V,S,V}, /* add.l.f */ + {10,13,rrr,V,V,V}, /* sub.b.f */ + {10,14,rrr,V,V,V}, /* sub.h.f */ + {10,15,rrr,V,V,V}, /* sub.w.f */ + {10,16,rrr,V,V,V}, /* sub.l.f */ + {10,13,rrr,V,S,V}, /* sub.b.f */ + {10,14,rrr,V,S,V}, /* sub.h.f */ + {10,15,rrr,V,S,V}, /* sub.w.f */ + {10,16,rrr,V,S,V}, /* sub.l.f */ + {3,13,rrr,V,V,V}, /* mul.b.f */ + {3,14,rrr,V,V,V}, /* mul.h.f */ + {3,15,rrr,V,V,V}, /* mul.w.f */ + {3,16,rrr,V,V,V}, /* mul.l.f */ + {3,13,rrr,V,S,V}, /* mul.b.f */ + {3,14,rrr,V,S,V}, /* mul.h.f */ + {3,15,rrr,V,S,V}, /* mul.w.f */ + {3,16,rrr,V,S,V}, /* mul.l.f */ + {4,13,rrr,V,V,V}, /* div.b.f */ + {4,14,rrr,V,V,V}, /* div.h.f */ + {4,15,rrr,V,V,V}, /* div.w.f */ + {4,16,rrr,V,V,V}, /* div.l.f */ + {4,13,rrr,V,S,V}, /* div.b.f */ + {4,14,rrr,V,S,V}, /* div.h.f */ + {4,15,rrr,V,S,V}, /* div.w.f */ + {4,16,rrr,V,S,V}, /* div.l.f */ +}; +struct formstr e0_format1[] = { + {0,0,0,0,0,0}, + {94,0,a3,0,0,0}, /* tst */ + {95,0,a3,0,0,0}, /* lck */ + {96,0,a3,0,0,0}, /* ulk */ + {17,0,a1r,S,0,0}, /* ldea */ + {97,0,a1r,A,0,0}, /* spawn */ + {98,0,a1r,A,0,0}, /* ldcmr */ + {99,0,a2r,A,0,0}, /* stcmr */ + {100,0,a1r,A,0,0}, /* popr */ + {101,0,a2r,A,0,0}, /* pshr */ + {102,7,a1r,A,0,0}, /* rcvr.w */ + {103,7,a2r,A,0,0}, /* matm.w */ + {104,7,a2r,A,0,0}, /* sndr.w */ + {104,8,a2r,S,0,0}, /* sndr.l */ + {102,8,a1r,S,0,0}, /* rcvr.l */ + {103,8,a2r,S,0,0}, /* matm.l */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {105,7,a2r,A,0,0}, /* putr.w */ + {105,8,a2r,S,0,0}, /* putr.l */ + {106,7,a1r,A,0,0}, /* getr.w */ + {106,8,a1r,S,0,0}, /* getr.l */ + {26,13,a2r,S,0,0}, /* ste.b.f */ + {26,14,a2r,S,0,0}, /* ste.h.f */ + {26,15,a2r,S,0,0}, /* ste.w.f */ + {26,16,a2r,S,0,0}, /* ste.l.f */ + {107,7,a2r,A,0,0}, /* matr.w */ + {108,7,a2r,A,0,0}, /* mat.w */ + {109,7,a1r,A,0,0}, /* get.w */ + {110,7,a1r,A,0,0}, /* rcv.w */ + {0,0,0,0,0,0}, + {111,7,a1r,A,0,0}, /* inc.w */ + {112,7,a2r,A,0,0}, /* put.w */ + {113,7,a2r,A,0,0}, /* snd.w */ + {107,8,a2r,S,0,0}, /* matr.l */ + {108,8,a2r,S,0,0}, /* mat.l */ + {109,8,a1r,S,0,0}, /* get.l */ + {110,8,a1r,S,0,0}, /* rcv.l */ + {0,0,0,0,0,0}, + {111,8,a1r,S,0,0}, /* inc.l */ + {112,8,a2r,S,0,0}, /* put.l */ + {113,8,a2r,S,0,0}, /* snd.l */ + {18,13,a1r,V,0,0}, /* ld.b.f */ + {18,14,a1r,V,0,0}, /* ld.h.f */ + {18,15,a1r,V,0,0}, /* ld.w.f */ + {18,16,a1r,V,0,0}, /* ld.l.f */ + {21,13,a2r,V,0,0}, /* st.b.f */ + {21,14,a2r,V,0,0}, /* st.h.f */ + {21,15,a2r,V,0,0}, /* st.w.f */ + {21,16,a2r,V,0,0}, /* st.l.f */ +}; +struct formstr e0_format2[] = { + {28,5,rr,V,V,0}, /* cvtw.b */ + {28,6,rr,V,V,0}, /* cvtw.h */ + {29,7,rr,V,V,0}, /* cvtb.w */ + {30,7,rr,V,V,0}, /* cvth.w */ + {28,13,rr,V,V,0}, /* cvtw.b.f */ + {28,14,rr,V,V,0}, /* cvtw.h.f */ + {29,15,rr,V,V,0}, /* cvtb.w.f */ + {30,15,rr,V,V,0}, /* cvth.w.f */ + {31,8,rr,V,V,0}, /* cvts.l */ + {32,7,rr,V,V,0}, /* cvtd.w */ + {33,3,rr,V,V,0}, /* cvtl.s */ + {28,4,rr,V,V,0}, /* cvtw.d */ + {31,16,rr,V,V,0}, /* cvts.l.f */ + {32,15,rr,V,V,0}, /* cvtd.w.f */ + {33,11,rr,V,V,0}, /* cvtl.s.f */ + {28,12,rr,V,V,0}, /* cvtw.d.f */ + {114,0,rr,S,S,0}, /* enal */ + {8,7,rr,S,S,0}, /* shf.w */ + {115,0,rr,S,S,0}, /* enag */ + {0,0,0,0,0,0}, + {28,4,rr,S,S,0}, /* cvtw.d */ + {32,7,rr,S,S,0}, /* cvtd.w */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {116,3,rr,S,S,0}, /* frint.s */ + {116,4,rr,S,S,0}, /* frint.d */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {116,3,rr,V,V,0}, /* frint.s */ + {116,4,rr,V,V,0}, /* frint.d */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {116,11,rr,V,V,0}, /* frint.s.f */ + {116,12,rr,V,V,0}, /* frint.d.f */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {81,3,rr,V,V,0}, /* sqrt.s */ + {81,4,rr,V,V,0}, /* sqrt.d */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {81,11,rr,V,V,0}, /* sqrt.s.f */ + {81,12,rr,V,V,0}, /* sqrt.d.f */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; +struct formstr e0_format3[] = { + {32,11,rr,V,V,0}, /* cvtd.s.f */ + {31,12,rr,V,V,0}, /* cvts.d.f */ + {33,12,rr,V,V,0}, /* cvtl.d.f */ + {32,16,rr,V,V,0}, /* cvtd.l.f */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {36,2,rr,V,V,0}, /* tzc.f */ + {44,2,rr,V,V,0}, /* lop.f */ + {117,2,rr,V,V,0}, /* xpnd.f */ + {42,2,rr,V,V,0}, /* not.f */ + {8,2,rr,S,V,0}, /* shf.f */ + {35,17,rr,V,V,0}, /* plc.t.f */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {37,11,rr,V,V,0}, /* eq.s.f */ + {37,12,rr,V,V,0}, /* eq.d.f */ + {43,11,rr,V,V,0}, /* neg.s.f */ + {43,12,rr,V,V,0}, /* neg.d.f */ + {37,11,rr,S,V,0}, /* eq.s.f */ + {37,12,rr,S,V,0}, /* eq.d.f */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {40,11,rr,V,V,0}, /* le.s.f */ + {40,12,rr,V,V,0}, /* le.d.f */ + {41,11,rr,V,V,0}, /* lt.s.f */ + {41,12,rr,V,V,0}, /* lt.d.f */ + {40,11,rr,S,V,0}, /* le.s.f */ + {40,12,rr,S,V,0}, /* le.d.f */ + {41,11,rr,S,V,0}, /* lt.s.f */ + {41,12,rr,S,V,0}, /* lt.d.f */ + {37,13,rr,V,V,0}, /* eq.b.f */ + {37,14,rr,V,V,0}, /* eq.h.f */ + {37,15,rr,V,V,0}, /* eq.w.f */ + {37,16,rr,V,V,0}, /* eq.l.f */ + {37,13,rr,S,V,0}, /* eq.b.f */ + {37,14,rr,S,V,0}, /* eq.h.f */ + {37,15,rr,S,V,0}, /* eq.w.f */ + {37,16,rr,S,V,0}, /* eq.l.f */ + {40,13,rr,V,V,0}, /* le.b.f */ + {40,14,rr,V,V,0}, /* le.h.f */ + {40,15,rr,V,V,0}, /* le.w.f */ + {40,16,rr,V,V,0}, /* le.l.f */ + {40,13,rr,S,V,0}, /* le.b.f */ + {40,14,rr,S,V,0}, /* le.h.f */ + {40,15,rr,S,V,0}, /* le.w.f */ + {40,16,rr,S,V,0}, /* le.l.f */ + {41,13,rr,V,V,0}, /* lt.b.f */ + {41,14,rr,V,V,0}, /* lt.h.f */ + {41,15,rr,V,V,0}, /* lt.w.f */ + {41,16,rr,V,V,0}, /* lt.l.f */ + {41,13,rr,S,V,0}, /* lt.b.f */ + {41,14,rr,S,V,0}, /* lt.h.f */ + {41,15,rr,S,V,0}, /* lt.w.f */ + {41,16,rr,S,V,0}, /* lt.l.f */ + {43,13,rr,V,V,0}, /* neg.b.f */ + {43,14,rr,V,V,0}, /* neg.h.f */ + {43,15,rr,V,V,0}, /* neg.w.f */ + {43,16,rr,V,V,0}, /* neg.l.f */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; +struct formstr e0_format4[] = { + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; +struct formstr e0_format5[] = { + {51,13,rr,V,V,0}, /* ldvi.b.f */ + {51,14,rr,V,V,0}, /* ldvi.h.f */ + {51,15,rr,V,V,0}, /* ldvi.w.f */ + {51,16,rr,V,V,0}, /* ldvi.l.f */ + {28,11,rr,V,V,0}, /* cvtw.s.f */ + {31,15,rr,V,V,0}, /* cvts.w.f */ + {28,16,rr,V,V,0}, /* cvtw.l.f */ + {33,15,rr,V,V,0}, /* cvtl.w.f */ + {52,13,rxr,V,V,0}, /* stvi.b.f */ + {52,14,rxr,V,V,0}, /* stvi.h.f */ + {52,15,rxr,V,V,0}, /* stvi.w.f */ + {52,16,rxr,V,V,0}, /* stvi.l.f */ + {52,13,rxr,S,V,0}, /* stvi.b.f */ + {52,14,rxr,S,V,0}, /* stvi.h.f */ + {52,15,rxr,S,V,0}, /* stvi.w.f */ + {52,16,rxr,S,V,0}, /* stvi.l.f */ +}; +struct formstr e0_format6[] = { + {0,0,rxl,S,CIR,0}, /* mov */ + {0,0,lr,CIR,S,0}, /* mov */ + {0,0,lr,TOC,S,0}, /* mov */ + {0,0,lr,CPUID,S,0}, /* mov */ + {0,0,rxl,S,TTR,0}, /* mov */ + {0,0,lr,TTR,S,0}, /* mov */ + {118,0,nops,0,0,0}, /* ctrsl */ + {119,0,nops,0,0,0}, /* ctrsg */ + {0,0,rxl,S,VMU,0}, /* mov */ + {0,0,lr,VMU,S,0}, /* mov */ + {0,0,rxl,S,VML,0}, /* mov */ + {0,0,lr,VML,S,0}, /* mov */ + {0,0,rxl,S,ICR,0}, /* mov */ + {0,0,lr,ICR,S,0}, /* mov */ + {0,0,rxl,S,TCPU,0}, /* mov */ + {0,0,lr,TCPU,S,0}, /* mov */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {120,0,nops,0,0,0}, /* stop */ + {0,0,0,0,0,0}, + {0,0,rxl,S,TID,0}, /* mov */ + {0,0,lr,TID,S,0}, /* mov */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; +struct formstr e0_format7[] = { + {84,13,r,V,0,0}, /* sum.b.f */ + {84,14,r,V,0,0}, /* sum.h.f */ + {84,15,r,V,0,0}, /* sum.w.f */ + {84,16,r,V,0,0}, /* sum.l.f */ + {85,2,r,V,0,0}, /* all.f */ + {86,2,r,V,0,0}, /* any.f */ + {87,2,r,V,0,0}, /* parity.f */ + {0,0,0,0,0,0}, + {88,13,r,V,0,0}, /* max.b.f */ + {88,14,r,V,0,0}, /* max.h.f */ + {88,15,r,V,0,0}, /* max.w.f */ + {88,16,r,V,0,0}, /* max.l.f */ + {89,13,r,V,0,0}, /* min.b.f */ + {89,14,r,V,0,0}, /* min.h.f */ + {89,15,r,V,0,0}, /* min.w.f */ + {89,16,r,V,0,0}, /* min.l.f */ + {84,11,r,V,0,0}, /* sum.s.f */ + {84,12,r,V,0,0}, /* sum.d.f */ + {90,11,r,V,0,0}, /* prod.s.f */ + {90,12,r,V,0,0}, /* prod.d.f */ + {88,11,r,V,0,0}, /* max.s.f */ + {88,12,r,V,0,0}, /* max.d.f */ + {89,11,r,V,0,0}, /* min.s.f */ + {89,12,r,V,0,0}, /* min.d.f */ + {90,13,r,V,0,0}, /* prod.b.f */ + {90,14,r,V,0,0}, /* prod.h.f */ + {90,15,r,V,0,0}, /* prod.w.f */ + {90,16,r,V,0,0}, /* prod.l.f */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; +struct formstr e1_format0[] = { + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {10,18,rrr,S,V,V}, /* sub.s.t */ + {10,19,rrr,S,V,V}, /* sub.d.t */ + {4,18,rrr,S,V,V}, /* div.s.t */ + {4,19,rrr,S,V,V}, /* div.d.t */ + {3,18,rrr,V,V,V}, /* mul.s.t */ + {3,19,rrr,V,V,V}, /* mul.d.t */ + {4,18,rrr,V,V,V}, /* div.s.t */ + {4,19,rrr,V,V,V}, /* div.d.t */ + {3,18,rrr,V,S,V}, /* mul.s.t */ + {3,19,rrr,V,S,V}, /* mul.d.t */ + {4,18,rrr,V,S,V}, /* div.s.t */ + {4,19,rrr,V,S,V}, /* div.d.t */ + {5,1,rrr,V,V,V}, /* and.t */ + {6,1,rrr,V,V,V}, /* or.t */ + {7,1,rrr,V,V,V}, /* xor.t */ + {8,1,rrr,V,V,V}, /* shf.t */ + {5,1,rrr,V,S,V}, /* and.t */ + {6,1,rrr,V,S,V}, /* or.t */ + {7,1,rrr,V,S,V}, /* xor.t */ + {8,1,rrr,V,S,V}, /* shf.t */ + {9,18,rrr,V,V,V}, /* add.s.t */ + {9,19,rrr,V,V,V}, /* add.d.t */ + {10,18,rrr,V,V,V}, /* sub.s.t */ + {10,19,rrr,V,V,V}, /* sub.d.t */ + {9,18,rrr,V,S,V}, /* add.s.t */ + {9,19,rrr,V,S,V}, /* add.d.t */ + {10,18,rrr,V,S,V}, /* sub.s.t */ + {10,19,rrr,V,S,V}, /* sub.d.t */ + {9,20,rrr,V,V,V}, /* add.b.t */ + {9,21,rrr,V,V,V}, /* add.h.t */ + {9,22,rrr,V,V,V}, /* add.w.t */ + {9,23,rrr,V,V,V}, /* add.l.t */ + {9,20,rrr,V,S,V}, /* add.b.t */ + {9,21,rrr,V,S,V}, /* add.h.t */ + {9,22,rrr,V,S,V}, /* add.w.t */ + {9,23,rrr,V,S,V}, /* add.l.t */ + {10,20,rrr,V,V,V}, /* sub.b.t */ + {10,21,rrr,V,V,V}, /* sub.h.t */ + {10,22,rrr,V,V,V}, /* sub.w.t */ + {10,23,rrr,V,V,V}, /* sub.l.t */ + {10,20,rrr,V,S,V}, /* sub.b.t */ + {10,21,rrr,V,S,V}, /* sub.h.t */ + {10,22,rrr,V,S,V}, /* sub.w.t */ + {10,23,rrr,V,S,V}, /* sub.l.t */ + {3,20,rrr,V,V,V}, /* mul.b.t */ + {3,21,rrr,V,V,V}, /* mul.h.t */ + {3,22,rrr,V,V,V}, /* mul.w.t */ + {3,23,rrr,V,V,V}, /* mul.l.t */ + {3,20,rrr,V,S,V}, /* mul.b.t */ + {3,21,rrr,V,S,V}, /* mul.h.t */ + {3,22,rrr,V,S,V}, /* mul.w.t */ + {3,23,rrr,V,S,V}, /* mul.l.t */ + {4,20,rrr,V,V,V}, /* div.b.t */ + {4,21,rrr,V,V,V}, /* div.h.t */ + {4,22,rrr,V,V,V}, /* div.w.t */ + {4,23,rrr,V,V,V}, /* div.l.t */ + {4,20,rrr,V,S,V}, /* div.b.t */ + {4,21,rrr,V,S,V}, /* div.h.t */ + {4,22,rrr,V,S,V}, /* div.w.t */ + {4,23,rrr,V,S,V}, /* div.l.t */ +}; +struct formstr e1_format1[] = { + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {26,20,a2r,S,0,0}, /* ste.b.t */ + {26,21,a2r,S,0,0}, /* ste.h.t */ + {26,22,a2r,S,0,0}, /* ste.w.t */ + {26,23,a2r,S,0,0}, /* ste.l.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {18,20,a1r,V,0,0}, /* ld.b.t */ + {18,21,a1r,V,0,0}, /* ld.h.t */ + {18,22,a1r,V,0,0}, /* ld.w.t */ + {18,23,a1r,V,0,0}, /* ld.l.t */ + {21,20,a2r,V,0,0}, /* st.b.t */ + {21,21,a2r,V,0,0}, /* st.h.t */ + {21,22,a2r,V,0,0}, /* st.w.t */ + {21,23,a2r,V,0,0}, /* st.l.t */ +}; +struct formstr e1_format2[] = { + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {28,20,rr,V,V,0}, /* cvtw.b.t */ + {28,21,rr,V,V,0}, /* cvtw.h.t */ + {29,22,rr,V,V,0}, /* cvtb.w.t */ + {30,22,rr,V,V,0}, /* cvth.w.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {31,23,rr,V,V,0}, /* cvts.l.t */ + {32,22,rr,V,V,0}, /* cvtd.w.t */ + {33,18,rr,V,V,0}, /* cvtl.s.t */ + {28,19,rr,V,V,0}, /* cvtw.d.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {116,18,rr,V,V,0}, /* frint.s.t */ + {116,19,rr,V,V,0}, /* frint.d.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {81,18,rr,V,V,0}, /* sqrt.s.t */ + {81,19,rr,V,V,0}, /* sqrt.d.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; +struct formstr e1_format3[] = { + {32,18,rr,V,V,0}, /* cvtd.s.t */ + {31,19,rr,V,V,0}, /* cvts.d.t */ + {33,19,rr,V,V,0}, /* cvtl.d.t */ + {32,23,rr,V,V,0}, /* cvtd.l.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {36,1,rr,V,V,0}, /* tzc.t */ + {44,1,rr,V,V,0}, /* lop.t */ + {117,1,rr,V,V,0}, /* xpnd.t */ + {42,1,rr,V,V,0}, /* not.t */ + {8,1,rr,S,V,0}, /* shf.t */ + {35,24,rr,V,V,0}, /* plc.t.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {37,18,rr,V,V,0}, /* eq.s.t */ + {37,19,rr,V,V,0}, /* eq.d.t */ + {43,18,rr,V,V,0}, /* neg.s.t */ + {43,19,rr,V,V,0}, /* neg.d.t */ + {37,18,rr,S,V,0}, /* eq.s.t */ + {37,19,rr,S,V,0}, /* eq.d.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {40,18,rr,V,V,0}, /* le.s.t */ + {40,19,rr,V,V,0}, /* le.d.t */ + {41,18,rr,V,V,0}, /* lt.s.t */ + {41,19,rr,V,V,0}, /* lt.d.t */ + {40,18,rr,S,V,0}, /* le.s.t */ + {40,19,rr,S,V,0}, /* le.d.t */ + {41,18,rr,S,V,0}, /* lt.s.t */ + {41,19,rr,S,V,0}, /* lt.d.t */ + {37,20,rr,V,V,0}, /* eq.b.t */ + {37,21,rr,V,V,0}, /* eq.h.t */ + {37,22,rr,V,V,0}, /* eq.w.t */ + {37,23,rr,V,V,0}, /* eq.l.t */ + {37,20,rr,S,V,0}, /* eq.b.t */ + {37,21,rr,S,V,0}, /* eq.h.t */ + {37,22,rr,S,V,0}, /* eq.w.t */ + {37,23,rr,S,V,0}, /* eq.l.t */ + {40,20,rr,V,V,0}, /* le.b.t */ + {40,21,rr,V,V,0}, /* le.h.t */ + {40,22,rr,V,V,0}, /* le.w.t */ + {40,23,rr,V,V,0}, /* le.l.t */ + {40,20,rr,S,V,0}, /* le.b.t */ + {40,21,rr,S,V,0}, /* le.h.t */ + {40,22,rr,S,V,0}, /* le.w.t */ + {40,23,rr,S,V,0}, /* le.l.t */ + {41,20,rr,V,V,0}, /* lt.b.t */ + {41,21,rr,V,V,0}, /* lt.h.t */ + {41,22,rr,V,V,0}, /* lt.w.t */ + {41,23,rr,V,V,0}, /* lt.l.t */ + {41,20,rr,S,V,0}, /* lt.b.t */ + {41,21,rr,S,V,0}, /* lt.h.t */ + {41,22,rr,S,V,0}, /* lt.w.t */ + {41,23,rr,S,V,0}, /* lt.l.t */ + {43,20,rr,V,V,0}, /* neg.b.t */ + {43,21,rr,V,V,0}, /* neg.h.t */ + {43,22,rr,V,V,0}, /* neg.w.t */ + {43,23,rr,V,V,0}, /* neg.l.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; +struct formstr e1_format4[] = { + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; +struct formstr e1_format5[] = { + {51,20,rr,V,V,0}, /* ldvi.b.t */ + {51,21,rr,V,V,0}, /* ldvi.h.t */ + {51,22,rr,V,V,0}, /* ldvi.w.t */ + {51,23,rr,V,V,0}, /* ldvi.l.t */ + {28,18,rr,V,V,0}, /* cvtw.s.t */ + {31,22,rr,V,V,0}, /* cvts.w.t */ + {28,23,rr,V,V,0}, /* cvtw.l.t */ + {33,22,rr,V,V,0}, /* cvtl.w.t */ + {52,20,rxr,V,V,0}, /* stvi.b.t */ + {52,21,rxr,V,V,0}, /* stvi.h.t */ + {52,22,rxr,V,V,0}, /* stvi.w.t */ + {52,23,rxr,V,V,0}, /* stvi.l.t */ + {52,20,rxr,S,V,0}, /* stvi.b.t */ + {52,21,rxr,S,V,0}, /* stvi.h.t */ + {52,22,rxr,S,V,0}, /* stvi.w.t */ + {52,23,rxr,S,V,0}, /* stvi.l.t */ +}; +struct formstr e1_format6[] = { + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; +struct formstr e1_format7[] = { + {84,20,r,V,0,0}, /* sum.b.t */ + {84,21,r,V,0,0}, /* sum.h.t */ + {84,22,r,V,0,0}, /* sum.w.t */ + {84,23,r,V,0,0}, /* sum.l.t */ + {85,1,r,V,0,0}, /* all.t */ + {86,1,r,V,0,0}, /* any.t */ + {87,1,r,V,0,0}, /* parity.t */ + {0,0,0,0,0,0}, + {88,20,r,V,0,0}, /* max.b.t */ + {88,21,r,V,0,0}, /* max.h.t */ + {88,22,r,V,0,0}, /* max.w.t */ + {88,23,r,V,0,0}, /* max.l.t */ + {89,20,r,V,0,0}, /* min.b.t */ + {89,21,r,V,0,0}, /* min.h.t */ + {89,22,r,V,0,0}, /* min.w.t */ + {89,23,r,V,0,0}, /* min.l.t */ + {84,18,r,V,0,0}, /* sum.s.t */ + {84,19,r,V,0,0}, /* sum.d.t */ + {90,18,r,V,0,0}, /* prod.s.t */ + {90,19,r,V,0,0}, /* prod.d.t */ + {88,18,r,V,0,0}, /* max.s.t */ + {88,19,r,V,0,0}, /* max.d.t */ + {89,18,r,V,0,0}, /* min.s.t */ + {89,19,r,V,0,0}, /* min.d.t */ + {90,20,r,V,0,0}, /* prod.b.t */ + {90,21,r,V,0,0}, /* prod.h.t */ + {90,22,r,V,0,0}, /* prod.w.t */ + {90,23,r,V,0,0}, /* prod.l.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; +char *lop[] = { + "mov", /* 0 */ + "merg", /* 1 */ + "mask", /* 2 */ + "mul", /* 3 */ + "div", /* 4 */ + "and", /* 5 */ + "or", /* 6 */ + "xor", /* 7 */ + "shf", /* 8 */ + "add", /* 9 */ + "sub", /* 10 */ + "exit", /* 11 */ + "jmp", /* 12 */ + "jmpi", /* 13 */ + "jmpa", /* 14 */ + "jmps", /* 15 */ + "tac", /* 16 */ + "ldea", /* 17 */ + "ld", /* 18 */ + "tas", /* 19 */ + "pshea", /* 20 */ + "st", /* 21 */ + "call", /* 22 */ + "calls", /* 23 */ + "callq", /* 24 */ + "pfork", /* 25 */ + "ste", /* 26 */ + "incr", /* 27 */ + "cvtw", /* 28 */ + "cvtb", /* 29 */ + "cvth", /* 30 */ + "cvts", /* 31 */ + "cvtd", /* 32 */ + "cvtl", /* 33 */ + "ldpa", /* 34 */ + "plc", /* 35 */ + "tzc", /* 36 */ + "eq", /* 37 */ + "leu", /* 38 */ + "ltu", /* 39 */ + "le", /* 40 */ + "lt", /* 41 */ + "not", /* 42 */ + "neg", /* 43 */ + "lop", /* 44 */ + "cprs", /* 45 */ + "nop", /* 46 */ + "br", /* 47 */ + "bri", /* 48 */ + "bra", /* 49 */ + "brs", /* 50 */ + "ldvi", /* 51 */ + "stvi", /* 52 */ + "ldsdr", /* 53 */ + "ldkdr", /* 54 */ + "ln", /* 55 */ + "patu", /* 56 */ + "pate", /* 57 */ + "pich", /* 58 */ + "plch", /* 59 */ + "idle", /* 60 */ + "rtnq", /* 61 */ + "cfork", /* 62 */ + "rtn", /* 63 */ + "wfork", /* 64 */ + "join", /* 65 */ + "rtnc", /* 66 */ + "exp", /* 67 */ + "sin", /* 68 */ + "cos", /* 69 */ + "psh", /* 70 */ + "pop", /* 71 */ + "eni", /* 72 */ + "dsi", /* 73 */ + "bkpt", /* 74 */ + "msync", /* 75 */ + "mski", /* 76 */ + "xmti", /* 77 */ + "tstvv", /* 78 */ + "diag", /* 79 */ + "pbkpt", /* 80 */ + "sqrt", /* 81 */ + "casr", /* 82 */ + "atan", /* 83 */ + "sum", /* 84 */ + "all", /* 85 */ + "any", /* 86 */ + "parity", /* 87 */ + "max", /* 88 */ + "min", /* 89 */ + "prod", /* 90 */ + "halt", /* 91 */ + "sysc", /* 92 */ + "trap", /* 93 */ + "tst", /* 94 */ + "lck", /* 95 */ + "ulk", /* 96 */ + "spawn", /* 97 */ + "ldcmr", /* 98 */ + "stcmr", /* 99 */ + "popr", /* 100 */ + "pshr", /* 101 */ + "rcvr", /* 102 */ + "matm", /* 103 */ + "sndr", /* 104 */ + "putr", /* 105 */ + "getr", /* 106 */ + "matr", /* 107 */ + "mat", /* 108 */ + "get", /* 109 */ + "rcv", /* 110 */ + "inc", /* 111 */ + "put", /* 112 */ + "snd", /* 113 */ + "enal", /* 114 */ + "enag", /* 115 */ + "frint", /* 116 */ + "xpnd", /* 117 */ + "ctrsl", /* 118 */ + "ctrsg", /* 119 */ + "stop", /* 120 */ +}; +char *rop[] = { + "", /* 0 */ + ".t", /* 1 */ + ".f", /* 2 */ + ".s", /* 3 */ + ".d", /* 4 */ + ".b", /* 5 */ + ".h", /* 6 */ + ".w", /* 7 */ + ".l", /* 8 */ + ".x", /* 9 */ + ".u", /* 10 */ + ".s.f", /* 11 */ + ".d.f", /* 12 */ + ".b.f", /* 13 */ + ".h.f", /* 14 */ + ".w.f", /* 15 */ + ".l.f", /* 16 */ + ".t.f", /* 17 */ + ".s.t", /* 18 */ + ".d.t", /* 19 */ + ".b.t", /* 20 */ + ".h.t", /* 21 */ + ".w.t", /* 22 */ + ".l.t", /* 23 */ + ".t.t", /* 24 */ +}; diff --git a/gdb/doc/all.m4 b/gdb/doc/all.m4 new file mode 100644 index 0000000000..4d97fbee6c --- /dev/null +++ b/gdb/doc/all.m4 @@ -0,0 +1,18 @@ +_divert__(-1) +_define__(<_ALL_ARCH__>,<1>) +_define__(<_GENERIC__>,<1>) In case none.m4 changes its mind abt default + +_define__(<_AOUT__>,<1>) +_define__(<_BOUT__>,<1>) +_define__(<_COFF__>,<1>) +_define__(<_ELF__>,<1>) + +_define__(<_AMD29K__>,<1>) +_define__(<_I80386__>,<1>) +_define__(<_I960__>,<1>) +_define__(<_M680X0__>,<1>) +_define__(<_SPARC__>,<1>) +_define__(<_VAX__>,<1>) +_define__(<_VXWORKS__>,<1>) + +_divert__<> \ No newline at end of file diff --git a/gdb/doc/amd29k.m4 b/gdb/doc/amd29k.m4 new file mode 100644 index 0000000000..cf3ba386c2 --- /dev/null +++ b/gdb/doc/amd29k.m4 @@ -0,0 +1,5 @@ +_divert__(-1) +_define__(<_AMD29K__>,<1>) +_define__(<_HOST__>,) +_define__(<_MACH_DEP__>, +_divert__<> \ No newline at end of file diff --git a/gdb/doc/gen.m4 b/gdb/doc/gen.m4 new file mode 100644 index 0000000000..be995bf5b7 --- /dev/null +++ b/gdb/doc/gen.m4 @@ -0,0 +1,13 @@ +_divert__(-1) +_define__(<_GENERIC__>,<1>) In case none.m4 changes its mind abt default + +_define__(<_AOUT__>,<1>) +_define__(<_COFF__>,<1>) +_define__(<_ELF__>,<1>) + +_define__(<_I80386__>,<1>) +_define__(<_M680X0__>,<1>) +_define__(<_SPARC__>,<1>) +_define__(<_VAX__>,<1>) + +_divert__<> \ No newline at end of file diff --git a/gdb/doc/i80386.m4 b/gdb/doc/i80386.m4 new file mode 100644 index 0000000000..d8293d1479 --- /dev/null +++ b/gdb/doc/i80386.m4 @@ -0,0 +1,5 @@ +_divert__(-1) +_define__(<_I80386__>,<1>) +_define__(<_HOST__>,) +_define__(<_MACH_DEP__>,<80386 Dependent> +_divert__<> \ No newline at end of file diff --git a/gdb/doc/i960.m4 b/gdb/doc/i960.m4 new file mode 100644 index 0000000000..e98155df6c --- /dev/null +++ b/gdb/doc/i960.m4 @@ -0,0 +1,12 @@ +_divert__(-1) +_define__(<_I960__>,<1>) +_define__(<_AOUT__>,<0>) +_define__(<_BOUT__>,<1>) +_define__(<_COFF__>,<1>) +_define__(<_AS__>,) +_define__(<_GCC__>,) +_define__(<_LD__>,) +_define__(<_GDB__>,) +_define__(<_HOST__>,) +_define__(<_MACH_DEP__>,) +_divert__<> \ No newline at end of file diff --git a/gdb/doc/m680x0.m4 b/gdb/doc/m680x0.m4 new file mode 100644 index 0000000000..e5f83b6f11 --- /dev/null +++ b/gdb/doc/m680x0.m4 @@ -0,0 +1,5 @@ +_divert__(-1) +_define__(<_M680X0__>,<1>) +_define__(<_HOST__>,) +_define__(<_MACH_DEP__>,) +_divert__<> \ No newline at end of file diff --git a/gdb/doc/none.m4 b/gdb/doc/none.m4 new file mode 100644 index 0000000000..940245c04b --- /dev/null +++ b/gdb/doc/none.m4 @@ -0,0 +1,49 @@ +_divert__(-1) + +Switches: + +_define__(<_ALL_ARCH__>,<0>) (Meant as most inclusive; file turning + it on is expected to also turn on + all arch-related switches including + "_GENERIC__") +_define__(<_GENERIC__>,<1>) (may not be quite all configs; + meant for "most vanilla" manual) +_define__(<_INTERNALS__>,<0>) + +_define__(<_AOUT__>,<1>) Object formats. Note we turn on one. +_define__(<_BOUT__>,<0>) +_define__(<_COFF__>,<0>) +_define__(<_ELF__>,<0>) + +_define__(<_AMD29K__>,<0>) Specific architectures. Note none +_define__(<_I80386__>,<0>) starts out on. +_define__(<_I960__>,<0>) +_define__(<_M680X0__>,<0>) +_define__(<_SPARC__>,<0>) +_define__(<_VAX__>,<0>) +_define__(<_VXWORKS__>,<0>) + +Text: + +Default names; individual configs may override +Assembler: +_define__(<_AS__>,) +C Compiler: +_define__(<_GCC__>,) +Linker: +_define__(<_LD__>,) +Debugger name: +_define__(<_GDBN__>,) +Debugger program: +_define__(<_GDBP__>,) +Debugger init file: +_define__(<_GDBINIT__>,<.gdbinit>) + +Text for host; individual configs *should* override, but this may +catch some flubs +_define__(<_HOST__>,) + +"Machine Dependent" nodename +_define__(<_MACH_DEP__>,) + +_divert__<> \ No newline at end of file diff --git a/gdb/doc/pretex.m4 b/gdb/doc/pretex.m4 new file mode 100644 index 0000000000..3fe9e0507f --- /dev/null +++ b/gdb/doc/pretex.m4 @@ -0,0 +1,252 @@ +divert(-1) -*-Text-*- + +I. INTRODUCTION + +This collection of M4 macros is meant to help in pre-processing texinfo +files to allow configuring them by hosts; for example, the reader of an +as manual who only has access to a 386 may not really want to see crud about +VAXen. + +A preprocessor is used, rather than extending texinfo, because this +way we can hack the conditionals in only one place; otherwise we would +have to write TeX macros, update makeinfo, and update the Emacs +info-formatting functions. + +II. COMPATIBILITY + +These macros should work with GNU m4 and System V m4; they do not work +with Sun or Berkeley M4. + +III. USAGE + +A. M4 INVOCATION +Assume this file is called "pretex.m4". Then, to preprocess a +document "mybook.texinfo" you might do something like the following: + + m4 pretex.m4 none.m4 PARTIC.m4 mybook.texinfo >mybook-PARTIC.texinfo + +---where your path is set to find GNU or SysV "m4", and the other m4 +files mentioned are as follows: + + none.m4: A file that defines, as 0, all the options you might + want to turn on using the conditionals defined below. + Unlike the C preprocessor, m4 does not default + undefined macros to 0. For example, here is a "none.m4" + I have been using: + _divert__(-1) + + _define__(<_ALL_ARCH__>,<0>) + _define__(<_INTERNALS__>,<0>) + + _define__(<_AMD29K__>,<0>) + _define__(<_I80386__>,<0>) + _define__(<_I960__>,<0>) + _define__(<_M680X0__>,<0>) + _define__(<_SPARC__>,<0>) + _define__(<_VAX__>,<0>) + + _divert__<> + + PARTIC.m4: A file that turns on whichever options you actually + want the manual configured for, in this particular + instance. Its contents are similar to one or more of + the lines in "none.m4", but of course the second + argument to _define__ is <1> rather than <0>. + + This is also a convenient place to define any macros + that you want to expand to different text for + different configurations---for example, the name of + the program being described. + +Naturally, these are just suggested conventions; you could put your macro +definitions in any files or combinations of files you like. + +These macros use the characters < and > as m4 quotes; if you need +these characters in your text, you will also want to use the macros +_0__ and _1__ from this package---see the description of "Quote +Handling" in the "Implementation" section below. + +B. WHAT GOES IN THE PRE-TEXINFO SOURCE + +For the most part, the text of your book. In addition, you can +include text that is included only conditionally, using the macros +_if__ and _fi__ defined below. They BOTH take an argument! This is +primarily meant for readability (so a human can more easily see what +conditional end matches what conditional beginning), but the argument +is actually used in the _fi__ as well as the _if__ implementation. +You should always give a _fi__ the same argument as its matching +_if__. Other arguments may appear to work for a while, but are almost +certain to produce the wrong output for some configurations. + +For example, here is an excerpt from the very beginning of the +documentation for GNU as, to name the info file appropriately for +different configurations: + _if__(_ALL_ARCH__) + @setfilename as.info + _fi__(_ALL_ARCH__) + _if__(_M680X0__ && !_ALL_ARCH__) + @setfilename as-m680x0.info + _fi__(_M680X0__ && !_ALL_ARCH__) + _if__(_AMD29K__ && !_ALL_ARCH__) + @setfilename as-29k.info + _fi__(_AMD29K__ && !_ALL_ARCH__) + +Note that you can use Boolean expressions in the arguments; the +expression language is that of the builtin m4 macro "eval", described +in the m4 manual. + +IV. IMPLEMENTATION + +A.PRIMITIVE RENAMING +First, we redefine m4's built-ins to avoid conflict with plain text. +The naming convention used is that our macros all begin with a single +underbar and end with two underbars. The asymmetry is meant to avoid +conflict with some other conventions (which we may want to document) that +are intended to avoid conflict, like ANSI C predefined macros. + +define(`_undefine__',defn(`undefine')) +define(`_define__',defn(`define')) +define(`_defn__',defn(`defn')) +define(`_ppf__',`_define__(`_$1__',_defn__(`$1'))_undefine__(`$1')') +_ppf__(`builtin') +_ppf__(`changecom') +_ppf__(`changequote') +_ppf__(`decr') +_ppf__(`define') +_ppf__(`defn') +_ppf__(`divert') +_ppf__(`dnl') +_ppf__(`dumpdef') +_ppf__(`errprint') +_ppf__(`eval') +_ppf__(`ifdef') +_ppf__(`ifelse') +_ppf__(`include') +_ppf__(`incr') +_ppf__(`index') +_ppf__(`len') +_ppf__(`m4exit') +_ppf__(`m4wrap') +_ppf__(`maketemp') +_ppf__(`popdef') +_ppf__(`pushdef') +_ppf__(`shift') +_ppf__(`sinclude') +_ppf__(`substr') +_ppf__(`syscmd') +_ppf__(`sysval') +_ppf__(`traceoff') +_ppf__(`traceon') +_ppf__(`translit') +_ppf__(`undefine') +_ppf__(`undivert') + +B. QUOTE HANDLING. + +The characters used as quotes by M4, by default, are unfortunately +quite likely to occur in ordinary text. To avoid surprises, we will +use the characters <> ---which are just as suggestive (more so to +Francophones, perhaps) but a little less common in text (save for +those poor Francophones. You win some, you lose some). Still, we +expect also to have to set < and > occasionally in text; to do that, +we define a macro to turn off quote handling (_0__) and a macro to +turn it back on (_1__), according to our convention. + + BEWARE: This seems to make < and > unusable as relational operations + in calls to the builtin "eval". So far I've gotten + along without; but a better choice may be possible. + +Note that we postponed this for a while, for convenience in discussing +the issue and in the primitive renaming---not to mention in defining +_0__ and _1__ themselves! However, the quote redefinitions MUST +precede the _if__ / _fi__ definitions, because M4 will expand the text +as given---if we use the wrong quotes here, we will get the wrong +quotes when we use the conditionals. + +_define__(_0__,`_changequote__(,)')_define__(_1__,`_changequote__(<,>)') +_1__ + +C. CONDITIONALS + +We define two macros, _if__ and _fi__. BOTH take arguments! This is +meant both to help the human reader match up a _fi__ with its +corresponding _if__ and to aid in the implementation. You may use the +full expression syntax supported by M4 (see docn of `eval' builtin in +the m4 manual). + +The conditional macros are carefully defined to avoid introducing +extra whitespace (i.e., blank lines or blank characters). One side +effect exists--- + + BEWARE: text following an `_if__' on the same line is + DISCARDED even if the condition is true; text + following a `_fi__' on the same line is also + always discarded. + +The recommended convention is to always place _if__ and _fi__ on a +line by themselves. This will also aid the human reader. TeX won't +care about the line breaks; as for info, you may want to insert calls +to `@refill' at the end of paragraphs containing conditionalized text, +where you don't want line breaks separating unconditional from +conditional text. info formatting will then give you nice looking +paragraphs in the info file. + +Nesting: conditionals are designed to nest, in the following way: +*nothing* is output between an outer pair of false conditionals, even +if there are true conditionals inside. A false conditional "defeats" +all conditionals within it. The counter _IF_FS__ is used to +implement this; kindly avoid redefining it directly. + +_define__(<_IF_FS__>,<0>) +_define__( + <_pushf__>, + <_define__(<_IF_FS__>, + _incr__(_IF_FS__))>) +_define__( + <_popf__>, + <_ifelse__(0,_IF_FS__, + <<>_dnl__<>>, + <_define__(<_IF_FS__>,_decr__(_IF_FS__))>)>) + +_define__( + <_if__>, + <_ifelse__(1,_eval__( ($1) ), + <<>_dnl__<>>, + <_pushf__<>_divert__(-1)>)>) +_define__( + <_fi__>, + <_ifelse__(1,_eval__( ($1) ), + <<>_dnl__<>>, + <_popf__<>_ifelse__(0,_IF_FS__, + <_divert__<>_dnl__<>>,<>)>)>) + +D. CHAPTER/SECTION MACRO +In a parametrized manual, the heading level may need to be calculated; +for example, a manual that has a chapter on machine dependencies +should be conditionally structured as follows: + - IF the manual is configured for a SINGLE machine type, use +the chapter heading for that machine type, and run headings down +from there (top level for a particular machine is chapter, then within +that we have section, subsection etc); + - ELSE, if MANY machine types are described in the chapter, +use a generic chapter heading such as "@chapter Machine Dependencies", +use "section" for the top level description of EACH machine, and run +headings down from there (top level for a particular machine is +section, then within that we have subsection, subsubsection etc). + +The macro <_CHAPSEC__> is for this purpose: its argument is evaluated (so +you can construct expressions to express choices such as above), then +expands as follows: + 0: @chapter + 1: @section + 2: @subsection + 3: @subsubsection + ...and so on. + +_define__(<_CHAPSEC__>,<@_cs__(_eval__($1))>) +_define__(<_cs__>,<_ifelse__( + 0, $1, , + 1, $1,
, + _cs__(_eval__($1 - 1))>)>) + +_divert__<>_dnl__<> diff --git a/gdb/doc/sparc.m4 b/gdb/doc/sparc.m4 new file mode 100644 index 0000000000..8cc6a3e46d --- /dev/null +++ b/gdb/doc/sparc.m4 @@ -0,0 +1,5 @@ +_divert__(-1) +_define__(<_SPARC__>,<1>) +_define__(<_HOST__>,) +_define__(<_MACH_DEP__>,) +_divert__<> \ No newline at end of file diff --git a/gdb/doc/vax.m4 b/gdb/doc/vax.m4 new file mode 100644 index 0000000000..59cb2ab126 --- /dev/null +++ b/gdb/doc/vax.m4 @@ -0,0 +1,5 @@ +_divert__(-1) +_define__(<_VAX__>,<1>) +_define__(<_HOST__>,) +_define__(<_MACH_DEP__>,) +_divert__<> \ No newline at end of file diff --git a/gdb/hp300ux-xdep.c b/gdb/hp300ux-xdep.c new file mode 100644 index 0000000000..f7f1cf0810 --- /dev/null +++ b/gdb/hp300ux-xdep.c @@ -0,0 +1,230 @@ +/* HP/UX interface for HP 300's, for GDB when running under Unix. + Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" + +/* Defining this means some system include files define some extra stuff. */ +#define WOPR +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "gdbcore.h" + +#include +#include + +#define INFERIOR_AR0(u) \ + ((ptrace \ + (PT_RUAREA, inferior_pid, ((char *) &u.u_ar0 - (char *) &u), 0)) \ + - KERNEL_U_ADDR) + +static void +fetch_inferior_register (regno, regaddr) + register int regno; + register unsigned int regaddr; +{ +#ifndef HPUX_VERSION_5 + if (regno == PS_REGNUM) + { + union { int i; short s[2]; } ps_val; + int regval; + + ps_val.i = (ptrace (PT_RUAREA, inferior_pid, regaddr, 0)); + regval = ps_val.s[0]; + supply_register (regno, ®val); + } + else +#endif /* not HPUX_VERSION_5 */ + { + char buf[MAX_REGISTER_RAW_SIZE]; + register int i; + + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int)) + { + *(int *) &buf[i] = ptrace (PT_RUAREA, inferior_pid, regaddr, 0); + regaddr += sizeof (int); + } + supply_register (regno, buf); + } + return; +} + +static void +store_inferior_register_1 (regno, regaddr, value) + int regno; + unsigned int regaddr; + int value; +{ + errno = 0; + ptrace (PT_WUAREA, inferior_pid, regaddr, value); +#if 0 + /* HP-UX randomly sets errno to non-zero for regno == 25. + However, the value is correctly written, so ignore errno. */ + if (errno != 0) + { + char string_buf[64]; + + sprintf (string_buf, "writing register number %d", regno); + perror_with_name (string_buf); + } +#endif + return; +} + +static void +store_inferior_register (regno, regaddr) + register int regno; + register unsigned int regaddr; +{ +#ifndef HPUX_VERSION_5 + if (regno == PS_REGNUM) + { + union { int i; short s[2]; } ps_val; + + ps_val.i = (ptrace (PT_RUAREA, inferior_pid, regaddr, 0)); + ps_val.s[0] = (read_register (regno)); + store_inferior_register_1 (regno, regaddr, ps_val.i); + } + else +#endif /* not HPUX_VERSION_5 */ + { + char buf[MAX_REGISTER_RAW_SIZE]; + register int i; + extern char registers[]; + + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int)) + { + store_inferior_register_1 + (regno, regaddr, + (*(int *) ®isters[(REGISTER_BYTE (regno)) + i])); + regaddr += sizeof (int); + } + } + return; +} + +void +fetch_inferior_registers (regno) + int regno; +{ + struct user u; + register int regno; + register unsigned int ar0_offset; + + ar0_offset = (INFERIOR_AR0 (u)); + if (regno == -1) + { + for (regno = 0; (regno < FP0_REGNUM); regno++) + fetch_inferior_register (regno, (REGISTER_ADDR (ar0_offset, regno))); + for (; (regno < NUM_REGS); regno++) + fetch_inferior_register (regno, (FP_REGISTER_ADDR (u, regno))); + } + else + fetch_inferior_register (regno, + (regno < FP0_REGNUM + ? REGISTER_ADDR (ar0_offset, regno) + : FP_REGISTER_ADDR (u, regno))); +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +store_inferior_registers (regno) + register int regno; +{ + struct user u; + register unsigned int ar0_offset; + extern char registers[]; + + if (regno >= FP0_REGNUM) + { + store_inferior_register (regno, (FP_REGISTER_ADDR (u, regno))); + return; + } + + ar0_offset = (INFERIOR_AR0 (u)); + if (regno >= 0) + { + store_inferior_register (regno, (REGISTER_ADDR (ar0_offset, regno))); + return; + } + + for (regno = 0; (regno < FP0_REGNUM); regno++) + store_inferior_register (regno, (REGISTER_ADDR (ar0_offset, regno))); + for (; (regno < NUM_REGS); regno++) + store_inferior_register (regno, (FP_REGISTER_ADDR (u, regno))); + return; +} + + +/* Take the register values out of a core file and store + them where `read_register' will find them. */ + +#ifdef HPUX_VERSION_5 +#define e_PS e_regs[PS] +#define e_PC e_regs[PC] +#endif /* HPUX_VERSION_5 */ + +void +fetch_core_registers (core_reg_sect, core_reg_size, which) + char *core_reg_sect; + int core_reg_size; + int which; +{ + int val, regno; + struct user u; + struct exception_stack *pes = (struct exception_stack *) core_reg_sect; +#define es (*pes) + char *buf; + + if (which == 0) { + if (core_reg_size < + ((char *) &es.e_offset - (char *) &es.e_regs[R0])) + error ("Not enough registers in core file"); + for (regno = 0; (regno < PS_REGNUM); regno++) + supply_register (regno, &es.e_regs[regno + R0]); + val = es.e_PS; + supply_register (regno++, &val); + supply_register (regno++, &es.e_PC); + + } else if (which == 2) { + + /* FIXME: This may not work if the float regs and control regs are + discontinuous. */ + for (regno = FP0_REGNUM, buf = core_reg_sect; + (regno < NUM_REGS); + buf += REGISTER_RAW_SIZE (regno), regno++) + { + supply_register (regno, buf); + } + } +} diff --git a/gdb/infrun.hacked.c b/gdb/infrun.hacked.c new file mode 100644 index 0000000000..a1b5926f75 --- /dev/null +++ b/gdb/infrun.hacked.c @@ -0,0 +1,1707 @@ +/* Start and stop the inferior process, for GDB. + Copyright (C) 1986, 1987, 1988, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Notes on the algorithm used in wait_for_inferior to determine if we + just did a subroutine call when stepping. We have the following + information at that point: + + Current and previous (just before this step) pc. + Current and previous sp. + Current and previous start of current function. + + If the start's of the functions don't match, then + + a) We did a subroutine call. + + In this case, the pc will be at the beginning of a function. + + b) We did a subroutine return. + + Otherwise. + + c) We did a longjmp. + + If we did a longjump, we were doing "nexti", since a next would + have attempted to skip over the assembly language routine in which + the longjmp is coded and would have simply been the equivalent of a + continue. I consider this ok behaivior. We'd like one of two + things to happen if we are doing a nexti through the longjmp() + routine: 1) It behaves as a stepi, or 2) It acts like a continue as + above. Given that this is a special case, and that anybody who + thinks that the concept of sub calls is meaningful in the context + of a longjmp, I'll take either one. Let's see what happens. + + Acts like a subroutine return. I can handle that with no problem + at all. + + -->So: If the current and previous beginnings of the current + function don't match, *and* the pc is at the start of a function, + we've done a subroutine call. If the pc is not at the start of a + function, we *didn't* do a subroutine call. + + -->If the beginnings of the current and previous function do match, + either: + + a) We just did a recursive call. + + In this case, we would be at the very beginning of a + function and 1) it will have a prologue (don't jump to + before prologue, or 2) (we assume here that it doesn't have + a prologue) there will have been a change in the stack + pointer over the last instruction. (Ie. it's got to put + the saved pc somewhere. The stack is the usual place. In + a recursive call a register is only an option if there's a + prologue to do something with it. This is even true on + register window machines; the prologue sets up the new + window. It might not be true on a register window machine + where the call instruction moved the register window + itself. Hmmm. One would hope that the stack pointer would + also change. If it doesn't, somebody send me a note, and + I'll work out a more general theory. + bug-gdb@prep.ai.mit.edu). This is true (albeit slipperly + so) on all machines I'm aware of: + + m68k: Call changes stack pointer. Regular jumps don't. + + sparc: Recursive calls must have frames and therefor, + prologues. + + vax: All calls have frames and hence change the + stack pointer. + + b) We did a return from a recursive call. I don't see that we + have either the ability or the need to distinguish this + from an ordinary jump. The stack frame will be printed + when and if the frame pointer changes; if we are in a + function without a frame pointer, it's the users own + lookout. + + c) We did a jump within a function. We assume that this is + true if we didn't do a recursive call. + + d) We are in no-man's land ("I see no symbols here"). We + don't worry about this; it will make calls look like simple + jumps (and the stack frames will be printed when the frame + pointer moves), which is a reasonably non-violent response. + +#if 0 + We skip this; it causes more problems than it's worth. +#ifdef SUN4_COMPILER_FEATURE + We do a special ifdef for the sun 4, forcing it to single step + into calls which don't have prologues. This means that we can't + nexti over leaf nodes, we can probably next over them (since they + won't have debugging symbols, usually), and we can next out of + functions returning structures (with a "call .stret4" at the end). +#endif +#endif +*/ + + + + + +#include +#include +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "frame.h" +#include "inferior.h" +#include "breakpoint.h" +#include "wait.h" +#include "gdbcore.h" +#include "signame.h" +#include "command.h" +#include "terminal.h" /* For #ifdef TIOCGPGRP and new_tty */ +#include "target.h" + +#include + +/* unistd.h is needed to #define X_OK */ +#ifdef USG +#include +#else +#include +#endif + +#ifdef SET_STACK_LIMIT_HUGE +extern int original_stack_limit; +#endif /* SET_STACK_LIMIT_HUGE */ + +/* Required by . */ +#include +/* Required by , at least on system V. */ +#include +/* Needed by IN_SIGTRAMP on some machines (e.g. vax). */ +#include +/* Needed by IN_SIGTRAMP on some machines (e.g. vax). */ +#include + +extern int errno; +extern char *getenv (); + +extern struct target_ops child_ops; /* In inftarg.c */ + +/* Copy of inferior_io_terminal when inferior was last started. */ + +extern char *inferior_thisrun_terminal; + + +/* Sigtramp is a routine that the kernel calls (which then calls the + signal handler). On most machines it is a library routine that + is linked into the executable. + + This macro, given a program counter value and the name of the + function in which that PC resides (which can be null if the + name is not known), returns nonzero if the PC and name show + that we are in sigtramp. + + On most machines just see if the name is sigtramp (and if we have + no name, assume we are not in sigtramp). */ +#if !defined (IN_SIGTRAMP) +#define IN_SIGTRAMP(pc, name) \ + name && !strcmp ("_sigtramp", name) +#endif + +/* Tables of how to react to signals; the user sets them. */ + +static char signal_stop[NSIG]; +static char signal_print[NSIG]; +static char signal_program[NSIG]; + +/* Nonzero if breakpoints are now inserted in the inferior. */ +/* Nonstatic for initialization during xxx_create_inferior. FIXME. */ + +/*static*/ int breakpoints_inserted; + +/* Function inferior was in as of last step command. */ + +static struct symbol *step_start_function; + +/* Nonzero => address for special breakpoint for resuming stepping. */ + +static CORE_ADDR step_resume_break_address; + +/* Pointer to orig contents of the byte where the special breakpoint is. */ + +static char step_resume_break_shadow[BREAKPOINT_MAX]; + +/* Nonzero means the special breakpoint is a duplicate + so it has not itself been inserted. */ + +static int step_resume_break_duplicate; + +/* Nonzero if we are expecting a trace trap and should proceed from it. */ + +static int trap_expected; + +/* Nonzero if the next time we try to continue the inferior, it will + step one instruction and generate a spurious trace trap. + This is used to compensate for a bug in HP-UX. */ + +static int trap_expected_after_continue; + +/* Nonzero means expecting a trace trap + and should stop the inferior and return silently when it happens. */ + +int stop_after_trap; + +/* Nonzero means expecting a trap and caller will handle it themselves. + It is used after attach, due to attaching to a process; + when running in the shell before the child program has been exec'd; + and when running some kinds of remote stuff (FIXME?). */ + +int stop_soon_quietly; + +/* Nonzero if pc has been changed by the debugger + since the inferior stopped. */ + +int pc_changed; + +/* Nonzero if proceed is being used for a "finish" command or a similar + situation when stop_registers should be saved. */ + +int proceed_to_finish; + +/* Save register contents here when about to pop a stack dummy frame, + if-and-only-if proceed_to_finish is set. + Thus this contains the return value from the called function (assuming + values are returned in a register). */ + +char stop_registers[REGISTER_BYTES]; + +/* Nonzero if program stopped due to error trying to insert breakpoints. */ + +static int breakpoints_failed; + +/* Nonzero after stop if current stack frame should be printed. */ + +static int stop_print_frame; + +#ifdef NO_SINGLE_STEP +extern int one_stepped; /* From machine dependent code */ +extern void single_step (); /* Same. */ +#endif /* NO_SINGLE_STEP */ + +static void insert_step_breakpoint (); +static void remove_step_breakpoint (); +/*static*/ void wait_for_inferior (); +void init_wait_for_inferior (); +static void normal_stop (); + + +/* Clear out all variables saying what to do when inferior is continued. + First do this, then set the ones you want, then call `proceed'. */ + +void +clear_proceed_status () +{ + trap_expected = 0; + step_range_start = 0; + step_range_end = 0; + step_frame_address = 0; + step_over_calls = -1; + step_resume_break_address = 0; + stop_after_trap = 0; + stop_soon_quietly = 0; + proceed_to_finish = 0; + breakpoint_proceeded = 1; /* We're about to proceed... */ + + /* Discard any remaining commands or status from previous stop. */ + bpstat_clear (&stop_bpstat); +} + +/* Basic routine for continuing the program in various fashions. + + ADDR is the address to resume at, or -1 for resume where stopped. + SIGGNAL is the signal to give it, or 0 for none, + or -1 for act according to how it stopped. + STEP is nonzero if should trap after one instruction. + -1 means return after that and print nothing. + You should probably set various step_... variables + before calling here, if you are stepping. + + You should call clear_proceed_status before calling proceed. */ + +void +proceed (addr, siggnal, step) + CORE_ADDR addr; + int siggnal; + int step; +{ + int oneproc = 0; + + if (step > 0) + step_start_function = find_pc_function (read_pc ()); + if (step < 0) + stop_after_trap = 1; + + if (addr == -1) + { + /* If there is a breakpoint at the address we will resume at, + step one instruction before inserting breakpoints + so that we do not stop right away. */ + + if (!pc_changed && breakpoint_here_p (read_pc ())) + oneproc = 1; + } + else + { + write_register (PC_REGNUM, addr); +#ifdef NPC_REGNUM + write_register (NPC_REGNUM, addr + 4); +#ifdef NNPC_REGNUM + write_register (NNPC_REGNUM, addr + 8); +#endif +#endif + } + + if (trap_expected_after_continue) + { + /* If (step == 0), a trap will be automatically generated after + the first instruction is executed. Force step one + instruction to clear this condition. This should not occur + if step is nonzero, but it is harmless in that case. */ + oneproc = 1; + trap_expected_after_continue = 0; + } + + if (oneproc) + /* We will get a trace trap after one instruction. + Continue it automatically and insert breakpoints then. */ + trap_expected = 1; + else + { + int temp = insert_breakpoints (); + if (temp) + { + print_sys_errmsg ("ptrace", temp); + error ("Cannot insert breakpoints.\n\ +The same program may be running in another process."); + } + breakpoints_inserted = 1; + } + + /* Install inferior's terminal modes. */ + target_terminal_inferior (); + + if (siggnal >= 0) + stop_signal = siggnal; + /* If this signal should not be seen by program, + give it zero. Used for debugging signals. */ + else if (stop_signal < NSIG && !signal_program[stop_signal]) + stop_signal= 0; + + /* Handle any optimized stores to the inferior NOW... */ +#ifdef DO_DEFERRED_STORES + DO_DEFERRED_STORES; +#endif + + /* Resume inferior. */ + target_resume (oneproc || step || bpstat_should_step (), stop_signal); + + /* Wait for it to stop (if not standalone) + and in any case decode why it stopped, and act accordingly. */ + + wait_for_inferior (); + normal_stop (); +} + +#if 0 +/* This might be useful (not sure), but isn't currently used. See also + write_pc(). */ +/* Writing the inferior pc as a register calls this function + to inform infrun that the pc has been set in the debugger. */ + +void +writing_pc (val) + CORE_ADDR val; +{ + stop_pc = val; + pc_changed = 1; +} +#endif + +/* Record the pc and sp of the program the last time it stopped. + These are just used internally by wait_for_inferior, but need + to be preserved over calls to it and cleared when the inferior + is started. */ +static CORE_ADDR prev_pc; +static CORE_ADDR prev_sp; +static CORE_ADDR prev_func_start; +static char *prev_func_name; + +/* Start an inferior Unix child process and sets inferior_pid to its pid. + EXEC_FILE is the file to run. + ALLARGS is a string containing the arguments to the program. + ENV is the environment vector to pass. Errors reported with error(). */ + +#ifndef SHELL_FILE +#define SHELL_FILE "/bin/sh" +#endif + +void +child_create_inferior (exec_file, allargs, env) + char *exec_file; + char *allargs; + char **env; +{ + int pid; + char *shell_command; + extern int sys_nerr; + extern char *sys_errlist[]; + extern int errno; + char *shell_file; + static char default_shell_file[] = SHELL_FILE; + int len; + int pending_execs; + /* Set debug_fork then attach to the child while it sleeps, to debug. */ + static int debug_fork = 0; + /* This is set to the result of setpgrp, which if vforked, will be visible + to you in the parent process. It's only used by humans for debugging. */ + static int debug_setpgrp = 657473; + + /* The user might want tilde-expansion, and in general probably wants + the program to behave the same way as if run from + his/her favorite shell. So we let the shell run it for us. + FIXME, this should probably search the local environment (as + modified by the setenv command), not the env gdb inherited. */ + shell_file = getenv ("SHELL"); + if (shell_file == NULL) + shell_file = default_shell_file; + + len = 5 + strlen (exec_file) + 1 + strlen (allargs) + 1 + /*slop*/ 10; + /* If desired, concat something onto the front of ALLARGS. + SHELL_COMMAND is the result. */ +#ifdef SHELL_COMMAND_CONCAT + shell_command = (char *) alloca (strlen (SHELL_COMMAND_CONCAT) + len); + strcpy (shell_command, SHELL_COMMAND_CONCAT); +#else + shell_command = (char *) alloca (len); + shell_command[0] = '\0'; +#endif + strcat (shell_command, "exec "); + strcat (shell_command, exec_file); + strcat (shell_command, " "); + strcat (shell_command, allargs); + + /* exec is said to fail if the executable is open. */ + close_exec_file (); + +#if defined(USG) && !defined(HAVE_VFORK) + pid = fork (); +#else + if (debug_fork) + pid = fork (); + else + pid = vfork (); +#endif + + if (pid < 0) + perror_with_name ("vfork"); + + if (pid == 0) + { + if (debug_fork) + sleep (debug_fork); + +#ifdef TIOCGPGRP + /* Run inferior in a separate process group. */ + debug_setpgrp = setpgrp (getpid (), getpid ()); + if (0 != debug_setpgrp) + perror("setpgrp failed in child"); +#endif /* TIOCGPGRP */ + +#ifdef SET_STACK_LIMIT_HUGE + /* Reset the stack limit back to what it was. */ + { + struct rlimit rlim; + + getrlimit (RLIMIT_STACK, &rlim); + rlim.rlim_cur = original_stack_limit; + setrlimit (RLIMIT_STACK, &rlim); + } +#endif /* SET_STACK_LIMIT_HUGE */ + + /* Tell the terminal handling subsystem what tty we plan to run on; + it will now switch to that one if non-null. */ + + new_tty (inferior_io_terminal); + + /* Changing the signal handlers for the inferior after + a vfork can also change them for the superior, so we don't mess + with signals here. See comments in + initialize_signals for how we get the right signal handlers + for the inferior. */ + + call_ptrace (0, 0, 0, 0); /* "Trace me, Dr. Memory!" */ + execle (shell_file, shell_file, "-c", shell_command, (char *)0, env); + + fprintf (stderr, "Cannot exec %s: %s.\n", shell_file, + errno < sys_nerr ? sys_errlist[errno] : "unknown error"); + fflush (stderr); + _exit (0177); + } + + /* Now that we have a child process, make it our target. */ + push_target (&child_ops); + +#ifdef CREATE_INFERIOR_HOOK + CREATE_INFERIOR_HOOK (pid); +#endif + +/* The process was started by the fork that created it, + but it will have stopped one instruction after execing the shell. + Here we must get it up to actual execution of the real program. */ + + inferior_pid = pid; /* Needed for wait_for_inferior stuff below */ + + clear_proceed_status (); + +#if defined (START_INFERIOR_HOOK) + START_INFERIOR_HOOK (); +#endif + + /* We will get a trace trap after one instruction. + Continue it automatically. Eventually (after shell does an exec) + it will get another trace trap. Then insert breakpoints and continue. */ + +#ifdef START_INFERIOR_TRAPS_EXPECTED + pending_execs = START_INFERIOR_TRAPS_EXPECTED; +#else + pending_execs = 2; +#endif + + init_wait_for_inferior (); + + /* Set up the "saved terminal modes" of the inferior + based on what modes we are starting it with. */ + target_terminal_init (); + + /* Install inferior's terminal modes. */ + target_terminal_inferior (); + + while (1) + { + stop_soon_quietly = 1; /* Make wait_for_inferior be quiet */ + wait_for_inferior (); + if (stop_signal != SIGTRAP) + { + /* Let shell child handle its own signals in its own way */ + /* FIXME, what if child has exit()ed? Must exit loop somehow */ + target_resume (0, stop_signal); + } + else + { + /* We handle SIGTRAP, however; it means child did an exec. */ + if (0 == --pending_execs) + break; + target_resume (0, 0); /* Just make it go on */ + } + } + stop_soon_quietly = 0; + + /* Should this perhaps just be a "proceed" call? FIXME */ + insert_step_breakpoint (); + breakpoints_failed = insert_breakpoints (); + if (!breakpoints_failed) + { + breakpoints_inserted = 1; + target_terminal_inferior(); + /* Start the child program going on its first instruction, single- + stepping if we need to. */ + target_resume (bpstat_should_step (), 0); + wait_for_inferior (); + normal_stop (); + } +} + +/* Start remote-debugging of a machine over a serial link. */ + +void +start_remote () +{ + init_wait_for_inferior (); + clear_proceed_status (); + stop_soon_quietly = 1; + trap_expected = 0; +} + +/* Initialize static vars when a new inferior begins. */ + +void +init_wait_for_inferior () +{ + /* These are meaningless until the first time through wait_for_inferior. */ + prev_pc = 0; + prev_sp = 0; + prev_func_start = 0; + prev_func_name = NULL; + + trap_expected_after_continue = 0; + breakpoints_inserted = 0; + mark_breakpoints_out (); +} + + +/* Attach to process PID, then initialize for debugging it + and wait for the trace-trap that results from attaching. */ + +void +child_open (args, from_tty) + char *args; + int from_tty; +{ + char *exec_file; + int pid; + + dont_repeat(); + + if (!args) + error_no_arg ("process-id to attach"); + +#ifndef ATTACH_DETACH + error ("Can't attach to a process on this machine."); +#else + pid = atoi (args); + + if (target_has_execution) + { + if (query ("A program is being debugged already. Kill it? ")) + target_kill ((char *)0, from_tty); + else + error ("Inferior not killed."); + } + + exec_file = (char *) get_exec_file (1); + + if (from_tty) + { + printf ("Attaching program: %s pid %d\n", + exec_file, pid); + fflush (stdout); + } + + attach (pid); + inferior_pid = pid; + push_target (&child_ops); + + mark_breakpoints_out (); + target_terminal_init (); + clear_proceed_status (); + stop_soon_quietly = 1; + /*proceed (-1, 0, -2);*/ + target_terminal_inferior (); + wait_for_inferior (); + normal_stop (); +#endif /* ATTACH_DETACH */ +} + +/* Wait for control to return from inferior to debugger. + If inferior gets a signal, we may decide to start it up again + instead of returning. That is why there is a loop in this function. + When this function actually returns it means the inferior + should be left stopped and GDB should read more commands. */ + +void +wait_for_inferior () +{ + WAITTYPE w; + int another_trap; + int random_signal; + CORE_ADDR stop_sp; + CORE_ADDR stop_func_start; + char *stop_func_name; + CORE_ADDR prologue_pc; + int stop_step_resume_break; + struct symtab_and_line sal; + int remove_breakpoints_on_following_step = 0; + +#if 0 + /* This no longer works now that read_register is lazy; + it might try to ptrace when the process is not stopped. */ + prev_pc = read_pc (); + (void) find_pc_partial_function (prev_pc, &prev_func_name, + &prev_func_start); + prev_func_start += FUNCTION_START_OFFSET; + prev_sp = read_register (SP_REGNUM); +#endif /* 0 */ + + while (1) + { + /* Clean up saved state that will become invalid. */ + pc_changed = 0; + flush_cached_frames (); + registers_changed (); + + target_wait (&w); + + /* See if the process still exists; clean up if it doesn't. */ + if (WIFEXITED (w)) + { + target_terminal_ours_for_output (); + if (WEXITSTATUS (w)) + printf ("\nProgram exited with code 0%o.\n", + (unsigned int)WEXITSTATUS (w)); + else + if (!batch_mode()) + printf ("\nProgram exited normally.\n"); + fflush (stdout); + target_mourn_inferior (); +#ifdef NO_SINGLE_STEP + one_stepped = 0; +#endif + stop_print_frame = 0; + break; + } + else if (!WIFSTOPPED (w)) + { + target_kill ((char *)0, 0); + stop_print_frame = 0; + stop_signal = WTERMSIG (w); + target_terminal_ours_for_output (); + printf ("\nProgram terminated with signal %d, %s\n", + stop_signal, + stop_signal < NSIG + ? sys_siglist[stop_signal] + : "(undocumented)"); + printf ("The inferior process no longer exists.\n"); + fflush (stdout); +#ifdef NO_SINGLE_STEP + one_stepped = 0; +#endif + break; + } + +#ifdef NO_SINGLE_STEP + if (one_stepped) + single_step (0); /* This actually cleans up the ss */ +#endif /* NO_SINGLE_STEP */ + + stop_pc = read_pc (); + set_current_frame ( create_new_frame (read_register (FP_REGNUM), + read_pc ())); + + stop_frame_address = FRAME_FP (get_current_frame ()); + stop_sp = read_register (SP_REGNUM); + stop_func_start = 0; + stop_func_name = 0; + /* Don't care about return value; stop_func_start and stop_func_name + will both be 0 if it doesn't work. */ + (void) find_pc_partial_function (stop_pc, &stop_func_name, + &stop_func_start); + stop_func_start += FUNCTION_START_OFFSET; + another_trap = 0; + bpstat_clear (&stop_bpstat); + stop_step = 0; + stop_stack_dummy = 0; + stop_print_frame = 1; + stop_step_resume_break = 0; + random_signal = 0; + stopped_by_random_signal = 0; + breakpoints_failed = 0; + + /* Look at the cause of the stop, and decide what to do. + The alternatives are: + 1) break; to really stop and return to the debugger, + 2) drop through to start up again + (set another_trap to 1 to single step once) + 3) set random_signal to 1, and the decision between 1 and 2 + will be made according to the signal handling tables. */ + + stop_signal = WSTOPSIG (w); + + /* First, distinguish signals caused by the debugger from signals + that have to do with the program's own actions. + Note that breakpoint insns may cause SIGTRAP or SIGILL + or SIGEMT, depending on the operating system version. + Here we detect when a SIGILL or SIGEMT is really a breakpoint + and change it to SIGTRAP. */ + + if (stop_signal == SIGTRAP + || (breakpoints_inserted && + (stop_signal == SIGILL + || stop_signal == SIGEMT)) + || stop_soon_quietly) + { + if (stop_signal == SIGTRAP && stop_after_trap) + { + stop_print_frame = 0; + break; + } + if (stop_soon_quietly) + break; + + /* Don't even think about breakpoints + if just proceeded over a breakpoint. + + However, if we are trying to proceed over a breakpoint + and end up in sigtramp, then step_resume_break_address + will be set and we should check whether we've hit the + step breakpoint. */ + if (stop_signal == SIGTRAP && trap_expected + && step_resume_break_address == NULL) + bpstat_clear (&stop_bpstat); + else + { + /* See if there is a breakpoint at the current PC. */ +#if DECR_PC_AFTER_BREAK + /* Notice the case of stepping through a jump + that leads just after a breakpoint. + Don't confuse that with hitting the breakpoint. + What we check for is that 1) stepping is going on + and 2) the pc before the last insn does not match + the address of the breakpoint before the current pc. */ + if (!(prev_pc != stop_pc - DECR_PC_AFTER_BREAK + && step_range_end && !step_resume_break_address)) +#endif /* DECR_PC_AFTER_BREAK not zero */ + { + /* See if we stopped at the special breakpoint for + stepping over a subroutine call. */ + if (stop_pc - DECR_PC_AFTER_BREAK + == step_resume_break_address) + { + stop_step_resume_break = 1; + if (DECR_PC_AFTER_BREAK) + { + stop_pc -= DECR_PC_AFTER_BREAK; + write_register (PC_REGNUM, stop_pc); + pc_changed = 0; + } + } + else + { + stop_bpstat = + bpstat_stop_status (&stop_pc, stop_frame_address); + /* Following in case break condition called a + function. */ + stop_print_frame = 1; + } + } + } + + if (stop_signal == SIGTRAP) + random_signal + = !(bpstat_explains_signal (stop_bpstat) + || trap_expected + || stop_step_resume_break + || PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address) + || (step_range_end && !step_resume_break_address)); + else + { + random_signal + = !(bpstat_explains_signal (stop_bpstat) + || stop_step_resume_break + /* End of a stack dummy. Some systems (e.g. Sony + news) give another signal besides SIGTRAP, + so check here as well as above. */ + || (stop_sp INNER_THAN stop_pc + && stop_pc INNER_THAN stop_frame_address) + ); + if (!random_signal) + stop_signal = SIGTRAP; + } + } + else + random_signal = 1; + + /* For the program's own signals, act according to + the signal handling tables. */ + + if (random_signal) + { + /* Signal not for debugging purposes. */ + int printed = 0; + + stopped_by_random_signal = 1; + + if (stop_signal >= NSIG + || signal_print[stop_signal]) + { + printed = 1; + target_terminal_ours_for_output (); +#ifdef PRINT_RANDOM_SIGNAL + PRINT_RANDOM_SIGNAL (stop_signal); +#else + printf ("\nProgram received signal %d, %s\n", + stop_signal, + stop_signal < NSIG + ? sys_siglist[stop_signal] + : "(undocumented)"); +#endif /* PRINT_RANDOM_SIGNAL */ + fflush (stdout); + } + if (stop_signal >= NSIG + || signal_stop[stop_signal]) + break; + /* If not going to stop, give terminal back + if we took it away. */ + else if (printed) + target_terminal_inferior (); + } + + /* Handle cases caused by hitting a user breakpoint. */ + + if (!random_signal && bpstat_explains_signal (stop_bpstat)) + { + /* Does a breakpoint want us to stop? */ + if (bpstat_stop (stop_bpstat)) + { + stop_print_frame = bpstat_should_print (stop_bpstat); + break; + } + + /* Otherwise we continue. Must remove breakpoints and single-step + to get us past the one we hit. Possibly we also were stepping + and should stop for that. So fall through and + test for stepping. But, if not stepping, + do not stop. */ + else + { + remove_breakpoints (); + remove_step_breakpoint (); /* FIXME someday, do we need this? */ + breakpoints_inserted = 0; + another_trap = 1; + } + } + + /* Handle cases caused by hitting a step-resumption breakpoint. */ + + else if (!random_signal && stop_step_resume_break) + { + /* We have hit the step-resumption breakpoint. + If we aren't in a recursive call that hit it again + before returning from the original call, remove it; + it has done its job getting us here. We then resume + the stepping we were doing before the function call. + + If we are in a recursive call, just proceed from this + breakpoint as usual, keeping it around to catch the final + return of interest. + + There used to be an sp test to make sure that we don't get hung + up in recursive calls in functions without frame + pointers. If the stack pointer isn't outside of + where the breakpoint was set (within a routine to be + stepped over), we're in the middle of a recursive + call. Not true for reg window machines (sparc) + because they must change frames to call things and + the stack pointer doesn't have to change if + the bp was set in a routine without a frame (pc can + be stored in some other window). + + The removal of the sp test is to allow calls to + alloca. Nasty things were happening. Oh, well, + gdb can only handle one level deep of lack of + frame pointer. */ + if (step_frame_address == 0 + || (stop_frame_address == step_frame_address)) + { + /* We really hit it: not a recursive call. */ + remove_step_breakpoint (); + step_resume_break_address = 0; + + /* If we're waiting for a trap, hitting the step_resume_break + doesn't count as getting it. */ + if (trap_expected) + another_trap = 1; + /* Fall through to resume stepping... */ + } + else + { + /* Otherwise, it's the recursive call case. */ + remove_breakpoints (); + remove_step_breakpoint (); + breakpoints_inserted = 0; + another_trap = 1; + /* Fall through to continue executing at full speed + (with a possible single-step lurch over the step-resumption + breakpoint as we start.) */ + } + } + + /* If this is the breakpoint at the end of a stack dummy, + just stop silently. */ + if (PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address)) + { + stop_print_frame = 0; + stop_stack_dummy = 1; +#ifdef HP_OS_BUG + trap_expected_after_continue = 1; +#endif + break; + } + + if (step_resume_break_address) + /* Having a step-resume breakpoint overrides anything + else having to do with stepping commands until + that breakpoint is reached. */ + ; + /* If stepping through a line, keep going if still within it. */ + else if (!random_signal + && step_range_end + && stop_pc >= step_range_start + && stop_pc < step_range_end + /* The step range might include the start of the + function, so if we are at the start of the + step range and either the stack or frame pointers + just changed, we've stepped outside */ + && !(stop_pc == step_range_start + && stop_frame_address + && (stop_sp INNER_THAN prev_sp + || stop_frame_address != step_frame_address))) + { +#if 0 + /* When "next"ing through a function, + This causes an extra stop at the end. + Is there any reason for this? + It's confusing to the user. */ + /* Don't step through the return from a function + unless that is the first instruction stepped through. */ + if (ABOUT_TO_RETURN (stop_pc)) + { + stop_step = 1; + break; + } +#endif + } + + /* We stepped out of the stepping range. See if that was due + to a subroutine call that we should proceed to the end of. */ + else if (!random_signal && step_range_end) + { + if (stop_func_start) + { + prologue_pc = stop_func_start; + SKIP_PROLOGUE (prologue_pc); + } + + /* Did we just take a signal? */ + if (IN_SIGTRAMP (stop_pc, stop_func_name) + && !IN_SIGTRAMP (prev_pc, prev_func_name)) + { + /* This code is needed at least in the following case: + The user types "next" and then a signal arrives (before + the "next" is done). */ + /* We've just taken a signal; go until we are back to + the point where we took it and one more. */ + step_resume_break_address = prev_pc; + step_resume_break_duplicate = + breakpoint_here_p (step_resume_break_address); + if (breakpoints_inserted) + insert_step_breakpoint (); + /* Make sure that the stepping range gets us past + that instruction. */ + if (step_range_end == 1) + step_range_end = (step_range_start = prev_pc) + 1; + remove_breakpoints_on_following_step = 1; + } + + /* ==> See comments at top of file on this algorithm. <==*/ + + else if (stop_pc == stop_func_start + && (stop_func_start != prev_func_start + || prologue_pc != stop_func_start + || stop_sp != prev_sp)) + { + /* It's a subroutine call */ + if (step_over_calls > 0 + || (step_over_calls && find_pc_function (stop_pc) == 0)) + { + /* A subroutine call has happened. */ + /* Set a special breakpoint after the return */ + step_resume_break_address = + ADDR_BITS_REMOVE + (SAVED_PC_AFTER_CALL (get_current_frame ())); + step_resume_break_duplicate + = breakpoint_here_p (step_resume_break_address); + if (breakpoints_inserted) + insert_step_breakpoint (); + } + /* Subroutine call with source code we should not step over. + Do step to the first line of code in it. */ + else if (step_over_calls) + { + SKIP_PROLOGUE (stop_func_start); + sal = find_pc_line (stop_func_start, 0); + /* Use the step_resume_break to step until + the end of the prologue, even if that involves jumps + (as it seems to on the vax under 4.2). */ + /* If the prologue ends in the middle of a source line, + continue to the end of that source line. + Otherwise, just go to end of prologue. */ +#ifdef PROLOGUE_FIRSTLINE_OVERLAP + /* no, don't either. It skips any code that's + legitimately on the first line. */ +#else + if (sal.end && sal.pc != stop_func_start) + stop_func_start = sal.end; +#endif + + if (stop_func_start == stop_pc) + { + /* We are already there: stop now. */ + stop_step = 1; + break; + } + else + /* Put the step-breakpoint there and go until there. */ + { + step_resume_break_address = stop_func_start; + + step_resume_break_duplicate + = breakpoint_here_p (step_resume_break_address); + if (breakpoints_inserted) + insert_step_breakpoint (); + /* Do not specify what the fp should be when we stop + since on some machines the prologue + is where the new fp value is established. */ + step_frame_address = 0; + /* And make sure stepping stops right away then. */ + step_range_end = step_range_start; + } + } + else + { + /* We get here only if step_over_calls is 0 and we + just stepped into a subroutine. I presume + that step_over_calls is only 0 when we're + supposed to be stepping at the assembly + language level.*/ + stop_step = 1; + break; + } + } + /* No subroutine call; stop now. */ + else + { + stop_step = 1; + break; + } + } + + else if (trap_expected + && IN_SIGTRAMP (stop_pc, stop_func_name) + && !IN_SIGTRAMP (prev_pc, prev_func_name)) + { + /* What has happened here is that we have just stepped the inferior + with a signal (because it is a signal which shouldn't make + us stop), thus stepping into sigtramp. + + So we need to set a step_resume_break_address breakpoint + and continue until we hit it, and then step. */ + step_resume_break_address = prev_pc; + /* Always 1, I think, but it's probably easier to have + the step_resume_break as usual rather than trying to + re-use the breakpoint which is already there. */ + step_resume_break_duplicate = + breakpoint_here_p (step_resume_break_address); + if (breakpoints_inserted) + insert_step_breakpoint (); + remove_breakpoints_on_following_step = 1; + another_trap = 1; + } + + /* Save the pc before execution, to compare with pc after stop. */ + prev_pc = read_pc (); /* Might have been DECR_AFTER_BREAK */ + prev_func_start = stop_func_start; /* Ok, since if DECR_PC_AFTER + BREAK is defined, the + original pc would not have + been at the start of a + function. */ + prev_func_name = stop_func_name; + prev_sp = stop_sp; + + /* If we did not do break;, it means we should keep + running the inferior and not return to debugger. */ + + if (trap_expected && stop_signal != SIGTRAP) + { + /* We took a signal (which we are supposed to pass through to + the inferior, else we'd have done a break above) and we + haven't yet gotten our trap. Simply continue. */ + target_resume ((step_range_end && !step_resume_break_address) + || (trap_expected && !step_resume_break_address) + || bpstat_should_step (), + stop_signal); + } + else + { + /* Either the trap was not expected, but we are continuing + anyway (the user asked that this signal be passed to the + child) + -- or -- + The signal was SIGTRAP, e.g. it was our signal, but we + decided we should resume from it. + + We're going to run this baby now! + + Insert breakpoints now, unless we are trying + to one-proceed past a breakpoint. */ + /* If we've just finished a special step resume and we don't + want to hit a breakpoint, pull em out. */ + if (!step_resume_break_address && + remove_breakpoints_on_following_step) + { + remove_breakpoints_on_following_step = 0; + remove_breakpoints (); + breakpoints_inserted = 0; + } + else if (!breakpoints_inserted && + (step_resume_break_address != NULL || !another_trap)) + { + insert_step_breakpoint (); + breakpoints_failed = insert_breakpoints (); + if (breakpoints_failed) + break; + breakpoints_inserted = 1; + } + + trap_expected = another_trap; + + if (stop_signal == SIGTRAP) + stop_signal = 0; + +#ifdef SHIFT_INST_REGS + /* I'm not sure when this following segment applies. I do know, now, + that we shouldn't rewrite the regs when we were stopped by a + random signal from the inferior process. */ + + if (!stop_breakpoint && (stop_signal != SIGCLD) + && !stopped_by_random_signal) + { + CORE_ADDR pc_contents = read_register (PC_REGNUM); + CORE_ADDR npc_contents = read_register (NPC_REGNUM); + if (pc_contents != npc_contents) + { + write_register (NNPC_REGNUM, npc_contents); + write_register (NPC_REGNUM, pc_contents); + } + } +#endif /* SHIFT_INST_REGS */ + + target_resume ((step_range_end && !step_resume_break_address) + || (trap_expected && !step_resume_break_address) + || bpstat_should_step (), + stop_signal); + } + } + if (target_has_execution) + { + /* Assuming the inferior still exists, set these up for next + time, just like we did above if we didn't break out of the + loop. */ + prev_pc = read_pc (); + prev_func_start = stop_func_start; + prev_func_name = stop_func_name; + prev_sp = stop_sp; + } +} + +/* Here to return control to GDB when the inferior stops for real. + Print appropriate messages, remove breakpoints, give terminal our modes. + + STOP_PRINT_FRAME nonzero means print the executing frame + (pc, function, args, file, line number and line text). + BREAKPOINTS_FAILED nonzero means stop was due to error + attempting to insert breakpoints. */ + +static void +normal_stop () +{ + /* Make sure that the current_frame's pc is correct. This + is a correction for setting up the frame info before doing + DECR_PC_AFTER_BREAK */ + if (target_has_execution) + (get_current_frame ())->pc = read_pc (); + + if (breakpoints_failed) + { + target_terminal_ours_for_output (); + print_sys_errmsg ("ptrace", breakpoints_failed); + printf ("Stopped; cannot insert breakpoints.\n\ +The same program may be running in another process.\n"); + } + + if (target_has_execution) + remove_step_breakpoint (); + + if (target_has_execution && breakpoints_inserted) + if (remove_breakpoints ()) + { + target_terminal_ours_for_output (); + printf ("Cannot remove breakpoints because program is no longer writable.\n\ +It must be running in another process.\n\ +Further execution is probably impossible.\n"); + } + + breakpoints_inserted = 0; + + /* Delete the breakpoint we stopped at, if it wants to be deleted. + Delete any breakpoint that is to be deleted at the next stop. */ + + breakpoint_auto_delete (stop_bpstat); + + /* If an auto-display called a function and that got a signal, + delete that auto-display to avoid an infinite recursion. */ + + if (stopped_by_random_signal) + disable_current_display (); + + if (step_multi && stop_step) + return; + + target_terminal_ours (); + + if (!target_has_stack) + return; + + /* Select innermost stack frame except on return from a stack dummy routine, + or if the program has exited. */ + if (!stop_stack_dummy) + { + select_frame (get_current_frame (), 0); + + if (stop_print_frame) + { + int source_only = bpstat_print (stop_bpstat); + print_sel_frame + (source_only + || (stop_step + && step_frame_address == stop_frame_address + && step_start_function == find_pc_function (stop_pc))); + + /* Display the auto-display expressions. */ + do_displays (); + } + } + + /* Save the function value return registers, if we care. + We might be about to restore their previous contents. */ + if (proceed_to_finish) + read_register_bytes (0, stop_registers, REGISTER_BYTES); + + if (stop_stack_dummy) + { + /* Pop the empty frame that contains the stack dummy. + POP_FRAME ends with a setting of the current frame, so we + can use that next. */ + POP_FRAME; + select_frame (get_current_frame (), 0); + } +} + +static void +insert_step_breakpoint () +{ + if (step_resume_break_address && !step_resume_break_duplicate) + target_insert_breakpoint (step_resume_break_address, + step_resume_break_shadow); +} + +static void +remove_step_breakpoint () +{ + if (step_resume_break_address && !step_resume_break_duplicate) + target_remove_breakpoint (step_resume_break_address, + step_resume_break_shadow); +} + +static void +sig_print_header () +{ + printf_filtered ("Signal\t\tStop\tPrint\tPass to program\tDescription\n"); +} + +static void +sig_print_info (number) + int number; +{ + char *abbrev = sig_abbrev(number); + if (abbrev == NULL) + printf_filtered ("%d\t\t", number); + else + printf_filtered ("SIG%s (%d)\t", abbrev, number); + printf_filtered ("%s\t", signal_stop[number] ? "Yes" : "No"); + printf_filtered ("%s\t", signal_print[number] ? "Yes" : "No"); + printf_filtered ("%s\t\t", signal_program[number] ? "Yes" : "No"); + printf_filtered ("%s\n", sys_siglist[number]); +} + +/* Specify how various signals in the inferior should be handled. */ + +static void +handle_command (args, from_tty) + char *args; + int from_tty; +{ + register char *p = args; + int signum = 0; + register int digits, wordlen; + char *nextarg; + + if (!args) + error_no_arg ("signal to handle"); + + while (*p) + { + /* Find the end of the next word in the args. */ + for (wordlen = 0; + p[wordlen] && p[wordlen] != ' ' && p[wordlen] != '\t'; + wordlen++); + /* Set nextarg to the start of the word after the one we just + found, and null-terminate this one. */ + if (p[wordlen] == '\0') + nextarg = p + wordlen; + else + { + p[wordlen] = '\0'; + nextarg = p + wordlen + 1; + } + + + for (digits = 0; p[digits] >= '0' && p[digits] <= '9'; digits++); + + if (signum == 0) + { + /* It is the first argument--must be the signal to operate on. */ + if (digits == wordlen) + { + /* Numeric. */ + signum = atoi (p); + if (signum <= 0 || signum >= NSIG) + { + p[wordlen] = '\0'; + error ("Invalid signal %s given as argument to \"handle\".", p); + } + } + else + { + /* Symbolic. */ + signum = sig_number (p); + if (signum == -1) + error ("No such signal \"%s\"", p); + } + + if (signum == SIGTRAP || signum == SIGINT) + { + if (!query ("SIG%s is used by the debugger.\nAre you sure you want to change it? ", sig_abbrev (signum))) + error ("Not confirmed."); + } + } + /* Else, if already got a signal number, look for flag words + saying what to do for it. */ + else if (!strncmp (p, "stop", wordlen)) + { + signal_stop[signum] = 1; + signal_print[signum] = 1; + } + else if (wordlen >= 2 && !strncmp (p, "print", wordlen)) + signal_print[signum] = 1; + else if (wordlen >= 2 && !strncmp (p, "pass", wordlen)) + signal_program[signum] = 1; + else if (!strncmp (p, "ignore", wordlen)) + signal_program[signum] = 0; + else if (wordlen >= 3 && !strncmp (p, "nostop", wordlen)) + signal_stop[signum] = 0; + else if (wordlen >= 4 && !strncmp (p, "noprint", wordlen)) + { + signal_print[signum] = 0; + signal_stop[signum] = 0; + } + else if (wordlen >= 4 && !strncmp (p, "nopass", wordlen)) + signal_program[signum] = 0; + else if (wordlen >= 3 && !strncmp (p, "noignore", wordlen)) + signal_program[signum] = 1; + /* Not a number and not a recognized flag word => complain. */ + else + { + error ("Unrecognized flag word: \"%s\".", p); + } + + /* Find start of next word. */ + p = nextarg; + while (*p == ' ' || *p == '\t') p++; + } + + if (from_tty) + { + /* Show the results. */ + sig_print_header (); + sig_print_info (signum); + } +} + +/* Print current contents of the tables set by the handle command. */ + +static void +signals_info (signum_exp) + char *signum_exp; +{ + register int i; + sig_print_header (); + + if (signum_exp) + { + /* First see if this is a symbol name. */ + i = sig_number (signum_exp); + if (i == -1) + { + /* Nope, maybe it's an address which evaluates to a signal + number. */ + i = parse_and_eval_address (signum_exp); + if (i >= NSIG || i < 0) + error ("Signal number out of bounds."); + } + sig_print_info (i); + return; + } + + printf_filtered ("\n"); + for (i = 0; i < NSIG; i++) + { + QUIT; + + sig_print_info (i); + } + + printf_filtered ("\nUse the \"handle\" command to change these tables.\n"); +} + +/* Save all of the information associated with the inferior<==>gdb + connection. INF_STATUS is a pointer to a "struct inferior_status" + (defined in inferior.h). */ + +void +save_inferior_status (inf_status, restore_stack_info) + struct inferior_status *inf_status; + int restore_stack_info; +{ + inf_status->pc_changed = pc_changed; + inf_status->stop_signal = stop_signal; + inf_status->stop_pc = stop_pc; + inf_status->stop_frame_address = stop_frame_address; + inf_status->stop_step = stop_step; + inf_status->stop_stack_dummy = stop_stack_dummy; + inf_status->stopped_by_random_signal = stopped_by_random_signal; + inf_status->trap_expected = trap_expected; + inf_status->step_range_start = step_range_start; + inf_status->step_range_end = step_range_end; + inf_status->step_frame_address = step_frame_address; + inf_status->step_over_calls = step_over_calls; + inf_status->step_resume_break_address = step_resume_break_address; + inf_status->stop_after_trap = stop_after_trap; + inf_status->stop_soon_quietly = stop_soon_quietly; + /* Save original bpstat chain here; replace it with copy of chain. + If caller's caller is walking the chain, they'll be happier if we + hand them back the original chain when restore_i_s is called. */ + inf_status->stop_bpstat = stop_bpstat; + stop_bpstat = bpstat_copy (stop_bpstat); + inf_status->breakpoint_proceeded = breakpoint_proceeded; + inf_status->restore_stack_info = restore_stack_info; + inf_status->proceed_to_finish = proceed_to_finish; + + bcopy (stop_registers, inf_status->stop_registers, REGISTER_BYTES); + + record_selected_frame (&(inf_status->selected_frame_address), + &(inf_status->selected_level)); + return; +} + +void +restore_inferior_status (inf_status) + struct inferior_status *inf_status; +{ + FRAME fid; + int level = inf_status->selected_level; + + pc_changed = inf_status->pc_changed; + stop_signal = inf_status->stop_signal; + stop_pc = inf_status->stop_pc; + stop_frame_address = inf_status->stop_frame_address; + stop_step = inf_status->stop_step; + stop_stack_dummy = inf_status->stop_stack_dummy; + stopped_by_random_signal = inf_status->stopped_by_random_signal; + trap_expected = inf_status->trap_expected; + step_range_start = inf_status->step_range_start; + step_range_end = inf_status->step_range_end; + step_frame_address = inf_status->step_frame_address; + step_over_calls = inf_status->step_over_calls; + step_resume_break_address = inf_status->step_resume_break_address; + stop_after_trap = inf_status->stop_after_trap; + stop_soon_quietly = inf_status->stop_soon_quietly; + bpstat_clear (&stop_bpstat); + stop_bpstat = inf_status->stop_bpstat; + breakpoint_proceeded = inf_status->breakpoint_proceeded; + proceed_to_finish = inf_status->proceed_to_finish; + + bcopy (inf_status->stop_registers, stop_registers, REGISTER_BYTES); + + /* The inferior can be gone if the user types "print exit(0)" + (and perhaps other times). */ + if (target_has_stack && inf_status->restore_stack_info) + { + fid = find_relative_frame (get_current_frame (), + &level); + + if (fid == 0 || + FRAME_FP (fid) != inf_status->selected_frame_address || + level != 0) + { +#if 0 + /* I'm not sure this error message is a good idea. I have + only seen it occur after "Can't continue previously + requested operation" (we get called from do_cleanups), in + which case it just adds insult to injury (one confusing + error message after another. Besides which, does the + user really care if we can't restore the previously + selected frame? */ + fprintf (stderr, "Unable to restore previously selected frame.\n"); +#endif + select_frame (get_current_frame (), 0); + return; + } + + select_frame (fid, inf_status->selected_level); + } +} + + +void +_initialize_infrun () +{ + register int i; + + add_info ("signals", signals_info, + "What debugger does when program gets various signals.\n\ +Specify a signal number as argument to print info on that signal only."); + + add_com ("handle", class_run, handle_command, + "Specify how to handle a signal.\n\ +Args are signal number followed by flags.\n\ +Flags allowed are \"stop\", \"print\", \"pass\",\n\ + \"nostop\", \"noprint\" or \"nopass\".\n\ +Print means print a message if this signal happens.\n\ +Stop means reenter debugger if this signal happens (implies print).\n\ +Pass means let program see this signal; otherwise program doesn't know.\n\ +Pass and Stop may be combined."); + + for (i = 0; i < NSIG; i++) + { + signal_stop[i] = 1; + signal_print[i] = 1; + signal_program[i] = 1; + } + + /* Signals caused by debugger's own actions + should not be given to the program afterwards. */ + signal_program[SIGTRAP] = 0; + signal_program[SIGINT] = 0; + + /* Signals that are not errors should not normally enter the debugger. */ +#ifdef SIGALRM + signal_stop[SIGALRM] = 0; + signal_print[SIGALRM] = 0; +#endif /* SIGALRM */ +#ifdef SIGVTALRM + signal_stop[SIGVTALRM] = 0; + signal_print[SIGVTALRM] = 0; +#endif /* SIGVTALRM */ +#ifdef SIGPROF + signal_stop[SIGPROF] = 0; + signal_print[SIGPROF] = 0; +#endif /* SIGPROF */ +#ifdef SIGCHLD + signal_stop[SIGCHLD] = 0; + signal_print[SIGCHLD] = 0; +#endif /* SIGCHLD */ +#ifdef SIGCLD + signal_stop[SIGCLD] = 0; + signal_print[SIGCLD] = 0; +#endif /* SIGCLD */ +#ifdef SIGIO + signal_stop[SIGIO] = 0; + signal_print[SIGIO] = 0; +#endif /* SIGIO */ +#ifdef SIGURG + signal_stop[SIGURG] = 0; + signal_print[SIGURG] = 0; +#endif /* SIGURG */ +} + diff --git a/gdb/mtrace.awk b/gdb/mtrace.awk new file mode 100755 index 0000000000..d7689cec3f --- /dev/null +++ b/gdb/mtrace.awk @@ -0,0 +1,36 @@ +# +# Awk program to analyze mtrace.c output. +# +$1 == "+" { if (allocated[$2] != "") + print "+", $2, "Alloc", NR, "duplicate:", allocated[$2]; + else + allocated[$2] = $3; + } +$1 == "-" { if (allocated[$2] != "") { + allocated[$2] = ""; + if (allocated[$2] != "") + print "DELETE FAILED", $2, allocated[$2]; + } else + print "-", $2, "Free", NR, "was never alloc'd"; + } +$1 == "<" { if (allocated[$2] != "") + allocated[$2] = ""; + else + print "-", $2, "Realloc", NR, "was never alloc'd"; + } +$1 == ">" { if (allocated[$2] != "") + print "+", $2, "Realloc", NR, "duplicate:", allocated[$2]; + else + allocated[$2] = $3; + } + +# Ignore "= Start" +$1 == "=" { } +# Ignore failed realloc attempts for now +$1 == "!" { } + + +END { for (x in allocated) + if (allocated[x] != "") + print "+", x, allocated[x]; + } diff --git a/gdb/mtrace.c b/gdb/mtrace.c new file mode 100755 index 0000000000..2b8222f285 --- /dev/null +++ b/gdb/mtrace.c @@ -0,0 +1,129 @@ +/* More debugging hooks for `malloc'. + Copyright 1991 Free Software Foundation + Written April 2, 1991 by John Gilmore of Cygnus Support + Based on mcheck.c by Mike Haertel. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#include +#include "ansidecl.h" +#include +#include "gmalloc.h" + +extern char *getenv(); + +FILE *mallstream; +char mallenv[] = "MALLOC_TRACE"; +static char mallbuf[BUFSIZ]; /* Buffer for the output */ + +/* Address to breakpoint on accesses to... */ +PTR mallwatch; + +/* Old hook values. */ +static void EXFUN((*old_free_hook), (PTR ptr)); +static PTR EXFUN((*old_malloc_hook), (size_t size)); +static PTR EXFUN((*old_realloc_hook), (PTR ptr, size_t size)); + +/* This function is called when the block being alloc'd, realloc'd, or + freed has an address matching the variable "mallwatch". In a debugger, + set "mallwatch" to the address of interest, then put a breakpoint on + tr_break. */ + +void +tr_break() +{ + ; +} + +static void +DEFUN(tr_freehook, (ptr), PTR ptr) +{ + fprintf(mallstream, "- %08x\n", ptr); /* Be sure to print it first */ + if (ptr == mallwatch) + tr_break(); + __free_hook = old_free_hook; + free(ptr); + __free_hook = tr_freehook; +} + +static PTR +DEFUN(tr_mallochook, (size), size_t size) +{ + PTR hdr; + + __malloc_hook = old_malloc_hook; + hdr = malloc(size); + __malloc_hook = tr_mallochook; + + /* We could be printing a NULL here; that's OK */ + fprintf (mallstream, "+ %08x %x\n", hdr, size); + + if (hdr == mallwatch) + tr_break(); + + return hdr; +} + +static PTR +DEFUN(tr_reallochook, (ptr, size), PTR ptr AND size_t size) +{ + PTR hdr; + + if (ptr == mallwatch) + tr_break(); + + __free_hook = old_free_hook; + __malloc_hook = old_malloc_hook; + __realloc_hook = old_realloc_hook; + hdr = realloc(ptr, size); + __free_hook = tr_freehook; + __malloc_hook = tr_mallochook; + __realloc_hook = tr_reallochook; + if (hdr == NULL) { + fprintf (mallstream, "! %08x %x\n", ptr, size); /* Failed realloc */ + } else { + fprintf (mallstream, "< %08x\n> %08x %x\n", ptr, hdr, size); + } + + if (hdr == mallwatch) + tr_break(); + + return hdr; +} + +void +mtrace() +{ + char *mallfile; + + mallfile = getenv (mallenv); + if (mallfile) { + mallstream = fopen (mallfile, "w"); + if (mallstream) { + /* Be sure it doesn't malloc its buffer! */ + setbuf (mallstream, mallbuf); + fprintf (mallstream, "= Start\n"); + old_free_hook = __free_hook; + __free_hook = tr_freehook; + old_malloc_hook = __malloc_hook; + __malloc_hook = tr_mallochook; + old_realloc_hook = __realloc_hook; + __realloc_hook = tr_reallochook; + } + } +} diff --git a/gdb/rem-m68k.shar b/gdb/rem-m68k.shar new file mode 100755 index 0000000000..aeb76e5d85 --- /dev/null +++ b/gdb/rem-m68k.shar @@ -0,0 +1,893 @@ +# This is a shell archive. Remove anything before this line, +# then unpack it by saving it in a file and typing "sh file". +# +# Wrapped by Glenn Engel on Mon Jun 12 15:19:20 1989 +# +# This archive contains: +# remcom.c +# + +LANG=""; export LANG +PATH=/bin:/usr/bin:$PATH; export PATH + +echo x - remcom.c +cat >remcom.c <<'@EOF' + +/**************************************************************************** + + THIS SOFTWARE IS NOT COPYRIGHTED + + HP offers the following for use in the public domain. HP makes no + warranty with regard to the software or it's performance and the + user accepts the software "AS IS" with all faults. + + HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD + TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +****************************************************************************/ + +/**************************************************************************** + * $Header$ + * + * $Module name: remcom.c $ + * $Revision$ + * $Date$ + * $Contributor: Lake Stevens Instrument Division$ + * + * $Description: low level support for gdb debugger. $ + * + * $Considerations: only works on target hardware $ + * + * $Written by: Glenn Engel $ + * $ModuleState: Experimental $ + * + * $NOTES: See Below $ + * + * To enable debugger support, two things need to happen. One, a + * call to set_debug_traps() is necessary in order to allow any breakpoints + * or error conditions to be properly intercepted and reported to gdb. + * Two, a breakpoint needs to be generated to begin communication. This + * is most easily accomplished by a call to breakpoint(). Breakpoint() + * simulates a breakpoint by executing a trap #1. + * + * Some explanation is probably necessary to explain how exceptions are + * handled. When an exception is encountered the 68000 pushes the current + * program counter and status register onto the supervisor stack and then + * transfers execution to a location specified in it's vector table. + * The handlers for the exception vectors are hardwired to jmp to an address + * given by the relation: (exception - 256) * 6. These are decending + * addresses starting from -6, -12, -18, ... By allowing 6 bytes for + * each entry, a jsr, jmp, bsr, ... can be used to enter the exception + * handler. Using a jsr to handle an exception has an added benefit of + * allowing a single handler to service several exceptions and use the + * return address as the key differentiation. The vector number can be + * computed from the return address by [ exception = (addr + 1530) / 6 ]. + * The sole purpose of the routine _catchException is to compute the + * exception number and push it on the stack in place of the return address. + * The external function exceptionHandler() is + * used to attach a specific handler to a specific 68k exception. + * For 68020 machines, the ability to have a return address around just + * so the vector can be determined is not necessary because the '020 pushes an + * extra word onto the stack containing the vector offset + * + * Because gdb will sometimes write to the stack area to execute function + * calls, this program cannot rely on using the supervisor stack so it + * uses it's own stack area reserved in the int array remcomStack. + * + ************* + * + * The following gdb commands are supported: + * + * command function Return value + * + * g return the value of the CPU registers hex data or ENN + * G set the value of the CPU registers OK or ENN + * + * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN + * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN + * + * c Resume at current address SNN ( signal NN) + * cAA..AA Continue at address AA..AA SNN + * + * s Step one instruction SNN + * sAA..AA Step one instruction from AA..AA SNN + * + * k kill + * + * ? What was the last sigval ? SNN (signal NN) + * + * All commands and responses are sent with a packet which includes a + * checksum. A packet consists of + * + * $#. + * + * where + * :: + * :: < two hex digits computed as modulo 256 sum of > + * + * When a packet is received, it is first acknowledged with either '+' or '-'. + * '+' indicates a successful transfer. '-' indicates a failed transfer. + * + * Example: + * + * Host: Reply: + * $m0,10#2a +$00010203040506070809101112131415#42 + * + ****************************************************************************/ + +#include +#include +#include + +/************************************************************************ + * + * external low-level support routines + */ +typedef void (*ExceptionHook)(int); /* pointer to function with int parm */ +typedef void (*Function)(); /* pointer to a function */ + +extern putDebugChar(); /* write a single character */ +extern getDebugChar(); /* read and return a single char */ + +extern Function exceptionHandler(); /* assign an exception handler */ +extern ExceptionHook exceptionHook; /* hook variable for errors/exceptions */ + + +/************************************************************************/ +/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/ +/* at least NUMREGBYTES*2 are needed for register packets */ +#define BUFMAX 400 + +static char initialized; /* boolean flag. != 0 means we've been initialized */ + +int remote_debug = 0; +/* debug > 0 prints ill-formed commands in valid packets & checksum errors */ + +char hexchars[]="0123456789abcdef"; + +/* there are 180 bytes of registers on a 68020 w/68881 */ +/* many of the fpa registers are 12 byte (96 bit) registers */ +#define NUMREGBYTES 180 +enum regnames {D0,D1,D2,D3,D4,D5,D6,D7, + A0,A1,A2,A3,A4,A5,A6,A7, + PS,PC, + FP0,FP1,FP2,FP3,FP4,FP5,FP6,FP7, + FPCONTROL,FPSTATUS,FPIADDR + }; + +typedef struct FrameStruct +{ + struct FrameStruct *previous; + int exceptionPC; /* pc value when this frame created */ + int exceptionVector; /* cpu vector causing exception */ + short frameSize; /* size of cpu frame in words */ + short sr; /* for 68000, this not always sr */ + int pc; + short format; + int fsaveHeader; + int morejunk[0]; /* exception frame, fp save... */ +} Frame; + +#define FRAMESIZE 500 +static Frame *lastFrame; +static int frameStack[FRAMESIZE]; + +/* + * these should not be static cuz they can be used outside this module + */ +int registers[NUMREGBYTES/4]; +int superStack; + +static int remcomStack[400]; +static int* stackPtr = &remcomStack[399]; + +/* + * In many cases, the system will want to continue exception processing + * when a continue command is given. + * oldExceptionHook is a function to invoke in this case. + */ + +static ExceptionHook oldExceptionHook; + +/* the size of the exception stack on the 68020 varies with the type of + * exception. The following table is the number of WORDS used + * for each exception format. + */ +static short exceptionSize[] = { 4,4,6,4,4,4,4,4,29,10,16,46,4,4,4,4 }; + +/************* jump buffer used for setjmp/longjmp **************************/ +jmp_buf env; + +/*************************** ASSEMBLY CODE MACROS *************************/ +/* */ + +#ifdef __HAVE_68881__ +/* do an fsave, then remember the address to begin a restore from */ +#define SAVE_FP_REGS() asm(" fsave a0@-"); \ + asm(" fmovemx fp0-fp7,_registers+72"); \ + asm(" fmoveml fpcr/fpsr/fpi,_registers+168"); +#define RESTORE_FP_REGS() asm(" fmoveml _registers+168,fpcr/fpsr/fpi"); \ + asm(" fmovemx _registers+72,fp0-fp7"); \ + asm(" frestore a0@+"); +#else +#define SAVE_FP_REGS() +#define RESTORE_FP_REGS() +#endif /* __HAVE_68881__ */ + +asm(" +.text +.globl _return_to_super +_return_to_super: + movel _registers+60,sp /* get new stack pointer */ + movel _lastFrame,a0 /* get last frame info */ + bra return_to_any + +.globl _return_to_user +_return_to_user: + movel _registers+60,a0 /* get usp */ + movel a0,usp /* set usp */ + movel _superStack,sp /* get original stack pointer */ + +return_to_any: + movel _lastFrame,a0 /* get last frame info */ + movel a0@+,_lastFrame /* link in previous frame */ + addql #8,a0 /* skip over pc, vector#*/ + movew a0@+,d0 /* get # of words in cpu frame */ + addw d0,a0 /* point to end of data */ + addw d0,a0 /* point to end of data */ + movel a0,a1 +# +# copy the stack frame + subql #1,d0 +copyUserLoop: + movew a1@-,sp@- + dbf d0,copyUserLoop +"); + RESTORE_FP_REGS() + asm(" moveml _registers,d0-d7/a0-a6"); + asm(" rte"); /* pop and go! */ + +#define DISABLE_INTERRUPTS() asm(" oriw #0x0700,sr"); +#define BREAKPOINT() asm(" trap #1"); + +/* this function is called immediately when a level 7 interrupt occurs */ +/* if the previous interrupt level was 7 then we're already servicing */ +/* this interrupt and an rte is in order to return to the debugger. */ +/* For the 68000, the offset for sr is 6 due to the jsr return address */ +asm(" +.text +.globl __debug_level7 +__debug_level7: + movew d0,sp@-"); +#ifdef mc68020 +asm(" movew sp@(2),d0"); +#else +asm(" movew sp@(6),d0"); +#endif +asm(" andiw #0x700,d0 + cmpiw #0x700,d0 + beq _already7 + movew sp@+,d0 + bra __catchException +_already7: + movew sp@+,d0"); +#ifndef mc68020 +asm(" lea sp@(4),sp"); /* pull off 68000 return address */ +#endif +asm(" rte"); + +extern void _catchException(); + +#ifdef mc68020 +/* This function is called when a 68020 exception occurs. It saves + * all the cpu and fpcp regs in the _registers array, creates a frame on a + * linked list of frames which has the cpu and fpcp stack frames needed + * to properly restore the context of these processors, and invokes + * an exception handler (remcom_handler). + * + * stack on entry: stack on exit: + * N bytes of junk exception # MSWord + * Exception Format Word exception # MSWord + * Program counter LSWord + * Program counter MSWord + * Status Register + * + * + */ +asm(" +.text +.globl __catchException +__catchException:"); +DISABLE_INTERRUPTS(); +asm(" + moveml d0-d7/a0-a6,_registers /* save registers */ + movel _lastFrame,a0 /* last frame pointer */ +"); +SAVE_FP_REGS(); +asm(" + lea _registers,a5 /* get address of registers */ + movew sp@,d1 /* get status register */ + movew d1,a5@(66) /* save sr */ + movel sp@(2),a4 /* save pc in a4 for later use */ + movel a4,a5@(68) /* save pc in _regisers[] */ + +# +# figure out how many bytes in the stack frame + movew sp@(6),d0 /* get '020 exception format */ + movew d0,d2 /* make a copy of format word */ + andiw #0xf000,d0 /* mask off format type */ + rolw #5,d0 /* rotate into the low byte *2 */ + lea _exceptionSize,a1 + addw d0,a1 /* index into the table */ + movew a1@,d0 /* get number of words in frame */ + movew d0,d3 /* save it */ + subw d0,a0 /* adjust save pointer */ + subw d0,a0 /* adjust save pointer(bytes) */ + movel a0,a1 /* copy save pointer */ + subql #1,d0 /* predecrement loop counter */ +# +# copy the frame +saveFrameLoop: + movew sp@+,a1@+ + dbf d0,saveFrameLoop +# +# now that the stack has been clenaed, +# save the a7 in use at time of exception + movel sp,_superStack /* save supervisor sp */ + andiw #0x2000,d1 /* were we in supervisor mode ? */ + beq userMode + movel a7,a5@(60) /* save a7 */ + bra a7saveDone +userMode: + movel usp,a1 + movel a1,a5@(60) /* save user stack pointer */ +a7saveDone: + +# +# save size of frame + movew d3,a0@- + +# +# compute exception number + andl #0xfff,d2 /* mask off vector offset */ + lsrw #2,d2 /* divide by 4 to get vect num */ + movel d2,a0@- /* save it */ +# +# save pc causing exception + movel a4,a0@- +# +# save old frame link and set the new value + movel _lastFrame,a1 /* last frame pointer */ + movel a1,a0@- /* save pointer to prev frame */ + movel a0,_lastFrame + + movel d2,sp@- /* push exception num */ + movel _exceptionHook,a0 /* get address of handler */ + jbsr a0@ /* and call it */ + jmp __returnFromException /* now, return */ +"); +#else /* mc68000 */ +/* This function is called when an exception occurs. It translates the + * return address found on the stack into an exception vector # which + * is then handled by either handle_exception or a system handler. + * _catchException provides a front end for both. + * + * stack on entry: stack on exit: + * Program counter MSWord exception # MSWord + * Program counter LSWord exception # MSWord + * Status Register + * Return Address MSWord + * Return Address LSWord + */ +asm(" +.text +.globl __catchException +__catchException:"); +DISABLE_INTERRUPTS(); +asm(" + moveml d0-d7/a0-a6,_registers /* save registers */ + movel _lastFrame,a0 /* last frame pointer */ +"); +SAVE_FP_REGS(); +asm(" + lea _registers,a5 /* get address of registers */ + movel sp@+,d2 /* pop return address */ + addl #1530,d2 /* convert return addr to */ + divs #6,d2 /* exception number */ + extl d2 + + moveql #3,d3 /* assume a three word frame */ + + cmpiw #3,d2 /* bus error or address error ? */ + bgt normal /* if >3 then normal error */ + movel sp@+,a0@- /* copy error info to frame buff*/ + movel sp@+,a0@- /* these are never used */ + moveql #7,d3 /* this is a 7 word frame */ + +normal: + movew sp@+,d1 /* pop status register */ + movel sp@+,a4 /* pop program counter */ + movew d1,a5@(66) /* save sr */ + movel a4,a5@(68) /* save pc in _regisers[] */ + movel a4,a0@- /* copy pc to frame buffer */ + movew d1,a0@- /* copy sr to frame buffer */ + + movel sp,_superStack /* save supervisor sp */ + + andiw #0x2000,d1 /* were we in supervisor mode ? */ + beq userMode + movel a7,a5@(60) /* save a7 */ + bra saveDone +userMode: + movel usp,a1 /* save user stack pointer */ + movel a1,a5@(60) /* save user stack pointer */ +saveDone: + + movew d3,a0@- /* push frame size in words */ + movel d2,a0@- /* push vector number */ + movel a4,a0@- /* push exception pc */ + +# +# save old frame link and set the new value + movel _lastFrame,a1 /* last frame pointer */ + movel a1,a0@- /* save pointer to prev frame */ + movel a0,_lastFrame + + movel d2,sp@- /* push exception num */ + movel _exceptionHook,a0 /* get address of handler */ + jbsr a0@ /* and call it */ + jmp __returnFromException /* now, return */ +"); +#endif + + +/* + * remcomHandler is a front end for handle_exception. It moves the + * stack pointer into an area reserved for debugger use in case the + * breakpoint happened in supervisor mode. + */ +asm("_remcomHandler:"); +asm(" addl #4,sp"); /* pop off return address */ +asm(" movel sp@+,d0"); /* get the exception number */ +asm(" movel _stackPtr,sp"); /* move to remcom stack area */ +asm(" movel d0,sp@-"); /* push exception onto stack */ +asm(" jbsr _handle_exception"); /* this never returns */ +asm(" rts"); /* return */ + +void _returnFromException( Frame *frame ) +{ + /* if no existing frame, dummy one up */ + if (! frame) + { + frame = lastFrame -1; + frame->frameSize = 4; + frame->format = 0; + frame->fsaveHeader = 0; + frame->previous = lastFrame; + } + +#ifndef mc68020 + /* a 68000 cannot use the internal info pushed onto a bus error + * or address error frame when doing an RTE so don't put this info + * onto the stack or the stack will creep every time this happens. + */ + frame->frameSize=3; +#endif + + /* throw away any frames in the list after this frame */ + lastFrame = frame; + + frame->sr = registers[(int) PS]; + frame->pc = registers[(int) PC]; + + if (registers[(int) PS] & 0x2000) + { + /* return to supervisor mode... */ + return_to_super(); + } + else + { /* return to user mode */ + return_to_user(); + } +} + +int hex(ch) +char ch; +{ + if ((ch >= 'a') && (ch <= 'f')) return (ch-'a'+10); + if ((ch >= '0') && (ch <= '9')) return (ch-'0'); + return (0); +} + + +/* scan for the sequence $# */ +void getpacket(buffer) +char * buffer; +{ + unsigned char checksum; + unsigned char xmitcsum; + int i; + int count; + char ch; + + do { + /* wait around for the start character, ignore all other characters */ + while ((ch = getDebugChar()) != '$'); + checksum = 0; + count = 0; + + /* now, read until a # or end of buffer is found */ + while (count < BUFMAX) { + ch = getDebugChar(); + if (ch == '#') break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = 0; + + if (ch == '#') { + xmitcsum = hex(getDebugChar()) << 4; + xmitcsum += hex(getDebugChar()); + if ((remote_debug ) && (checksum != xmitcsum)) { + fprintf(stderr,"bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n", + checksum,xmitcsum,buffer); + } + + if (checksum != xmitcsum) putDebugChar('-'); /* failed checksum */ + else { + putDebugChar('+'); /* successful transfer */ + /* if a sequence char is present, reply the sequence ID */ + if (buffer[2] == ':') { + putDebugChar( buffer[0] ); + putDebugChar( buffer[1] ); + /* remove sequence chars from buffer */ + count = strlen(buffer); + for (i=3; i <= count; i++) buffer[i-3] = buffer[i]; + } + } + } + } while (checksum != xmitcsum); + +} + +/* send the packet in buffer. The host get's one chance to read it. + This routine does not wait for a positive acknowledge. */ + + +void putpacket(buffer) +char * buffer; +{ + unsigned char checksum; + int count; + char ch; + + /* $#. */ + do { + putDebugChar('$'); + checksum = 0; + count = 0; + + while (ch=buffer[count]) { + if (! putDebugChar(ch)) return; + checksum += ch; + count += 1; + } + + putDebugChar('#'); + putDebugChar(hexchars[checksum >> 4]); + putDebugChar(hexchars[checksum % 16]); + + } while (1 == 0); /* (getDebugChar() != '+'); */ + +} + +static char inbuffer[BUFMAX]; +static char outbuffer[BUFMAX]; +static short error; + + +void debug_error(format, parm) +char * format; +char * parm; +{ + if (remote_debug) fprintf(stderr,format,parm); +} + +/* convert the memory pointed to by mem into hex, placing result in buf */ +/* return a pointer to the last char put in buf (null) */ +char* mem2hex(mem, buf, count) +char* mem; +char* buf; +int count; +{ + int i; + unsigned char ch; + for (i=0;i> 4]; + *buf++ = hexchars[ch % 16]; + } + *buf = 0; + return(buf); +} + +/* convert the hex array pointed to by buf into binary to be placed in mem */ +/* return a pointer to the character AFTER the last byte written */ +char* hex2mem(buf, mem, count) +char* buf; +char* mem; +int count; +{ + int i; + unsigned char ch; + for (i=0;iexceptionPC, + frame->exceptionVector); + if (frame->exceptionPC == newPC) break; /* bingo! a match */ + /* + * for a breakpoint instruction, the saved pc may + * be off by two due to re-executing the instruction + * replaced by the trap instruction. Check for this. + */ + if ((frame->exceptionVector == 33) && + (frame->exceptionPC == (newPC+2))) break; + frame = frame->previous; + } + + /* + * If we found a match for the PC AND we are not returning + * as a result of a breakpoint (33), + * trace exception (9), nmi (31), jmp to + * the old exception handler as if this code never ran. + */ + if (frame) + { + if ((frame->exceptionVector != 9) && + (frame->exceptionVector != 31) && + (frame->exceptionVector != 33)) + { + /* + * invoke the previous handler. + */ + if (oldExceptionHook) + (*oldExceptionHook) (frame->exceptionVector); + newPC = registers[ PC ]; /* pc may have changed */ + if (newPC != frame->exceptionPC) + { + if (remote_debug) + printf("frame at 0x%x has pc=0x%x, except#=%d\n", + frame,frame->exceptionPC, + frame->exceptionVector); + /* dispose of this frame, we're skipping it (longjump?)*/ + lastFrame = frame->previous; + frame = (Frame *) 0; + } + } + } + + _returnFromException( frame ); + + break; + + /* kill the program */ + case 'k' : /* do nothing */ + break; + } /* switch */ + + /* reply to the request */ + putpacket(outbuffer); + } +} + + +/* this function is used to set up exception handlers for tracing and + breakpoints */ +void set_debug_traps() +{ +extern void _debug_level7(); +extern void remcomHandler(); +int exception; + + for (exception = 2; exception <= 23; exception++) + exceptionHandler(exception,_catchException); + + /* level 7 interrupt */ + exceptionHandler(31,_debug_level7); + + /* breakpoint exception (trap #1) */ + exceptionHandler(33,_catchException); + + /* floating point error (trap #8) */ + exceptionHandler(40,_catchException); + + /* 48 to 54 are floating point coprocessor errors */ + for (exception = 48; exception <= 54; exception++) + exceptionHandler(exception,_catchException); + + if (oldExceptionHook != remcomHandler) + { + oldExceptionHook = exceptionHook; + exceptionHook = remcomHandler; + } + + initialized = 1; + + lastFrame = (Frame *) &frameStack[FRAMESIZE-1]; + lastFrame->previous = (Frame *) 0; +} + +/* This function will generate a breakpoint exception. It is used at the + beginning of a program to sync up with a debugger and can be used + otherwise as a quick means to stop program execution and "break" into + the debugger. */ + +void breakpoint() +{ + if (initialized) BREAKPOINT(); +} + +@EOF + +chmod 444 remcom.c + +exit 0 + diff --git a/gdb/rem-multi.shar b/gdb/rem-multi.shar new file mode 100644 index 0000000000..86c9cf0217 --- /dev/null +++ b/gdb/rem-multi.shar @@ -0,0 +1,1313 @@ +#!/bin/sh +# This is a shell archive. +# Run the file through sh to extract its contents. +# shar: Shell Archiver +# Run the following text with /bin/sh to create: +# Remote_Makefile +# remote_gutils.c +# remote_inflow.c +# remote_server.c +# remote_utils.c +# This archive created: Fri Jun 23 17:06:55 1989 +cat << \SHAR_EOF > Remote_Makefile +# Makefile for the remote server for GDB, the GNU debugger. +# Copyright (C) 1986, 1989 Free Software Foundation, Inc. +# +# This file is part of GDB. +# +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. +# +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +CFLAGS = -g +CC = cc + +SERVER = remote_server.o\ + remote_inflow.o\ + remote_utils.o\ + remote_gutils.o + +prog : $(SERVER) + $(CC) -g -o serve $(SERVER) +SHAR_EOF +cat << \SHAR_EOF > remote_gutils.c +/* General utility routines for the remote server for GDB, the GNU debugger. + Copyright (C) 1986, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include "defs.h" + +void error (); +void fatal (); + +/* Chain of cleanup actions established with make_cleanup, + to be executed if an error happens. */ + +static struct cleanup *cleanup_chain; + +/* Nonzero means a quit has been requested. */ + +int quit_flag; + +/* Nonzero means quit immediately if Control-C is typed now, + rather than waiting until QUIT is executed. */ + +int immediate_quit; + +/* Add a new cleanup to the cleanup_chain, + and return the previous chain pointer + to be passed later to do_cleanups or discard_cleanups. + Args are FUNCTION to clean up with, and ARG to pass to it. */ + +struct cleanup * +make_cleanup (function, arg) + void (*function) (); + int arg; +{ + register struct cleanup *new + = (struct cleanup *) xmalloc (sizeof (struct cleanup)); + register struct cleanup *old_chain = cleanup_chain; + + new->next = cleanup_chain; + new->function = function; + new->arg = arg; + cleanup_chain = new; + + return old_chain; +} + +/* Discard cleanups and do the actions they describe + until we get back to the point OLD_CHAIN in the cleanup_chain. */ + +void +do_cleanups (old_chain) + register struct cleanup *old_chain; +{ + register struct cleanup *ptr; + while ((ptr = cleanup_chain) != old_chain) + { + (*ptr->function) (ptr->arg); + cleanup_chain = ptr->next; + free (ptr); + } +} + +/* Discard cleanups, not doing the actions they describe, + until we get back to the point OLD_CHAIN in the cleanup_chain. */ + +void +discard_cleanups (old_chain) + register struct cleanup *old_chain; +{ + register struct cleanup *ptr; + while ((ptr = cleanup_chain) != old_chain) + { + cleanup_chain = ptr->next; + free (ptr); + } +} + +/* This function is useful for cleanups. + Do + + foo = xmalloc (...); + old_chain = make_cleanup (free_current_contents, &foo); + + to arrange to free the object thus allocated. */ + +void +free_current_contents (location) + char **location; +{ + free (*location); +} + +/* Generally useful subroutines used throughout the program. */ + +/* Like malloc but get error if no storage available. */ + +char * +xmalloc (size) + long size; +{ + register char *val = (char *) malloc (size); + if (!val) + fatal ("virtual memory exhausted.", 0); + return val; +} + +/* Like realloc but get error if no storage available. */ + +char * +xrealloc (ptr, size) + char *ptr; + long size; +{ + register char *val = (char *) realloc (ptr, size); + if (!val) + fatal ("virtual memory exhausted.", 0); + return val; +} + +/* Print the system error message for errno, and also mention STRING + as the file name for which the error was encountered. + Then return to command level. */ + +void +perror_with_name (string) + char *string; +{ + extern int sys_nerr; + extern char *sys_errlist[]; + extern int errno; + char *err; + char *combined; + + if (errno < sys_nerr) + err = sys_errlist[errno]; + else + err = "unknown error"; + + combined = (char *) alloca (strlen (err) + strlen (string) + 3); + strcpy (combined, string); + strcat (combined, ": "); + strcat (combined, err); + + error ("%s.", combined); +} + +/* Print the system error message for ERRCODE, and also mention STRING + as the file name for which the error was encountered. */ + +void +print_sys_errmsg (string, errcode) + char *string; + int errcode; +{ + extern int sys_nerr; + extern char *sys_errlist[]; + char *err; + char *combined; + + if (errcode < sys_nerr) + err = sys_errlist[errcode]; + else + err = "unknown error"; + + combined = (char *) alloca (strlen (err) + strlen (string) + 3); + strcpy (combined, string); + strcat (combined, ": "); + strcat (combined, err); + + printf ("%s.\n", combined); +} + +void +quit () +{ + fflush (stdout); + ioctl (fileno (stdout), TIOCFLUSH, 0); + error ("Quit"); +} + +/* Control C comes here */ + +void +request_quit () +{ + quit_flag = 1; + if (immediate_quit) + quit (); +} + +/* Print an error message and return to command level. + STRING is the error message, used as a fprintf string, + and ARG is passed as an argument to it. */ + +void +error (string, arg1, arg2, arg3) + char *string; + int arg1, arg2, arg3; +{ + fflush (stdout); + fprintf (stderr, string, arg1, arg2, arg3); + fprintf (stderr, "\n"); + /************return_to_top_level ();************/ +} + +/* Print an error message and exit reporting failure. + This is for a error that we cannot continue from. + STRING and ARG are passed to fprintf. */ + +void +fatal (string, arg) + char *string; + int arg; +{ + fprintf (stderr, "gdb: "); + fprintf (stderr, string, arg); + fprintf (stderr, "\n"); + exit (1); +} + +/* Make a copy of the string at PTR with SIZE characters + (and add a null character at the end in the copy). + Uses malloc to get the space. Returns the address of the copy. */ + +char * +savestring (ptr, size) + char *ptr; + int size; +{ + register char *p = (char *) xmalloc (size + 1); + bcopy (ptr, p, size); + p[size] = 0; + return p; +} + +char * +concat (s1, s2, s3) + char *s1, *s2, *s3; +{ + register int len = strlen (s1) + strlen (s2) + strlen (s3) + 1; + register char *val = (char *) xmalloc (len); + strcpy (val, s1); + strcat (val, s2); + strcat (val, s3); + return val; +} + +void +print_spaces (n, file) + register int n; + register FILE *file; +{ + while (n-- > 0) + fputc (' ', file); +} + +/* Ask user a y-or-n question and return 1 iff answer is yes. + Takes three args which are given to printf to print the question. + The first, a control string, should end in "? ". + It should not say how to answer, because we do that. */ + +int +query (ctlstr, arg1, arg2) + char *ctlstr; +{ + register int answer; + + /* Automatically answer "yes" if input is not from a terminal. */ + /***********if (!input_from_terminal_p ()) + return 1; *************************/ + + while (1) + { + printf (ctlstr, arg1, arg2); + printf ("(y or n) "); + fflush (stdout); + answer = fgetc (stdin); + clearerr (stdin); /* in case of C-d */ + if (answer != '\n') + while (fgetc (stdin) != '\n') clearerr (stdin); + if (answer >= 'a') + answer -= 040; + if (answer == 'Y') + return 1; + if (answer == 'N') + return 0; + printf ("Please answer y or n.\n"); + } +} + +/* Parse a C escape sequence. STRING_PTR points to a variable + containing a pointer to the string to parse. That pointer + is updated past the characters we use. The value of the + escape sequence is returned. + + A negative value means the sequence \ newline was seen, + which is supposed to be equivalent to nothing at all. + + If \ is followed by a null character, we return a negative + value and leave the string pointer pointing at the null character. + + If \ is followed by 000, we return 0 and leave the string pointer + after the zeros. A value of 0 does not mean end of string. */ + +int +parse_escape (string_ptr) + char **string_ptr; +{ + register int c = *(*string_ptr)++; + switch (c) + { + case 'a': + return '\a'; + case 'b': + return '\b'; + case 'e': + return 033; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'v': + return '\v'; + case '\n': + return -2; + case 0: + (*string_ptr)--; + return 0; + case '^': + c = *(*string_ptr)++; + if (c == '\\') + c = parse_escape (string_ptr); + if (c == '?') + return 0177; + return (c & 0200) | (c & 037); + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + register int i = c - '0'; + register int count = 0; + while (++count < 3) + { + if ((c = *(*string_ptr)++) >= '0' && c <= '7') + { + i *= 8; + i += c - '0'; + } + else + { + (*string_ptr)--; + break; + } + } + return i; + } + default: + return c; + } +} + +void +printchar (ch, stream) + unsigned char ch; + FILE *stream; +{ + register int c = ch; + if (c < 040 || c >= 0177) + { + if (c == '\n') + fprintf (stream, "\\n"); + else if (c == '\b') + fprintf (stream, "\\b"); + else if (c == '\t') + fprintf (stream, "\\t"); + else if (c == '\f') + fprintf (stream, "\\f"); + else if (c == '\r') + fprintf (stream, "\\r"); + else if (c == 033) + fprintf (stream, "\\e"); + else if (c == '\a') + fprintf (stream, "\\a"); + else + fprintf (stream, "\\%03o", c); + } + else + { + if (c == '\\' || c == '"' || c == '\'') + fputc ('\\', stream); + fputc (c, stream); + } +} +SHAR_EOF +cat << \SHAR_EOF > remote_inflow.c +/* Low level interface to ptrace, for GDB when running under Unix. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. +*/ + +#include "defs.h" +#include "param.h" +#include "wait.h" +#include "frame.h" +#include "inferior.h" +/*************************** +#include "initialize.h" +****************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +/***************Begin MY defs*********************/ +int quit_flag = 0; +char registers[REGISTER_BYTES]; + +/* Index within `registers' of the first byte of the space for + register N. */ + + +char buf2[MAX_REGISTER_RAW_SIZE]; +/***************End MY defs*********************/ + +#ifdef NEW_SUN_PTRACE +#include +#include +#endif + +extern char **environ; +extern int errno; +extern int inferior_pid; +void error(), quit(), perror_with_name(); +int query(); +void supply_register(), write_register(); +CORE_ADDR read_register(); + +/* Nonzero if we are debugging an attached outside process + rather than an inferior. */ + + +/* Start an inferior process and returns its pid. + ALLARGS is a vector of program-name and args. + ENV is the environment vector to pass. */ + +int +create_inferior (allargs, env) + char **allargs; + char **env; +{ + int pid; + extern int sys_nerr; + extern char *sys_errlist[]; + extern int errno; + + /* exec is said to fail if the executable is open. */ + /****************close_exec_file ();*****************/ + + pid = vfork (); + if (pid < 0) + perror_with_name ("vfork"); + + if (pid == 0) + { + /* Run inferior in a separate process group. */ + setpgrp (getpid (), getpid ()); + +/* Not needed on Sun, at least, and loses there + because it clobbers the superior. */ +/*??? signal (SIGQUIT, SIG_DFL); + signal (SIGINT, SIG_DFL); */ + + errno = 0; + ptrace (0); + + execle ("/bin/sh", "sh", "-c", allargs, 0, env); + + fprintf (stderr, "Cannot exec /bin/sh: %s.\n", + errno < sys_nerr ? sys_errlist[errno] : "unknown error"); + fflush (stderr); + _exit (0177); + } + return pid; +} + +/* Kill the inferior process. Make us have no inferior. */ + +kill_inferior () +{ + if (inferior_pid == 0) + return; + ptrace (8, inferior_pid, 0, 0); + wait (0); + /*************inferior_died ();****VK**************/ +} + +/* Resume execution of the inferior process. + If STEP is nonzero, single-step it. + If SIGNAL is nonzero, give it that signal. */ + +unsigned char +resume (step, signal,status) + int step; + int signal; + char *status; +{ + int pid ; + WAITTYPE w; + + errno = 0; + ptrace (step ? 9 : 7, inferior_pid, 1, signal); + if (errno) + perror_with_name ("ptrace"); + pid = wait(&w); + if(pid != inferior_pid) + perror_with_name ("wait"); + + if(WIFEXITED(w)) + { + printf("\nchild exited with retcode = %x \n",WRETCODE(w)); + *status = 'E'; + return((unsigned char) WRETCODE(w)); + } + else if(!WIFSTOPPED(w)) + { + printf("\nchild did terminated with signal = %x \n",WTERMSIG(w)); + *status = 'T'; + return((unsigned char) WTERMSIG(w)); + } + else + { + printf("\nchild stopped with signal = %x \n",WSTOPSIG(w)); + *status = 'S'; + return((unsigned char) WSTOPSIG(w)); + } + +} + + +#ifdef NEW_SUN_PTRACE + +void +fetch_inferior_registers () +{ + struct regs inferior_registers; + struct fp_status inferior_fp_registers; + extern char registers[]; + + ptrace (PTRACE_GETREGS, inferior_pid, &inferior_registers); + if (errno) + perror_with_name ("ptrace"); + /**********debugging begin **********/ + print_some_registers(&inferior_registers); + /**********debugging end **********/ + ptrace (PTRACE_GETFPREGS, inferior_pid, &inferior_fp_registers); + if (errno) + perror_with_name ("ptrace"); + + bcopy (&inferior_registers, registers, 16 * 4); + bcopy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof inferior_fp_registers.fps_regs); + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps; + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc; + bcopy (&inferior_fp_registers.fps_control, + ®isters[REGISTER_BYTE (FPC_REGNUM)], + sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs); +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +store_inferior_registers (regno) + int regno; +{ + struct regs inferior_registers; + struct fp_status inferior_fp_registers; + extern char registers[]; + + bcopy (registers, &inferior_registers, 16 * 4); + bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers, + sizeof inferior_fp_registers.fps_regs); + inferior_registers.r_ps = *(int *)®isters[REGISTER_BYTE (PS_REGNUM)]; + inferior_registers.r_pc = *(int *)®isters[REGISTER_BYTE (PC_REGNUM)]; + bcopy (®isters[REGISTER_BYTE (FPC_REGNUM)], + &inferior_fp_registers.fps_control, + sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs); + + ptrace (PTRACE_SETREGS, inferior_pid, &inferior_registers); + if (errno) + perror_with_name ("ptrace"); + ptrace (PTRACE_SETFPREGS, inferior_pid, &inferior_fp_registers); + if (errno) + perror_with_name ("ptrace"); +} + +#endif /* not NEW_SUN_PTRACE */ + + +/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory + in the NEW_SUN_PTRACE case. + It ought to be straightforward. But it appears that writing did + not write the data that I specified. I cannot understand where + it got the data that it actually did write. */ + +/* Copy LEN bytes from inferior's memory starting at MEMADDR + to debugger memory starting at MYADDR. */ + +read_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & - sizeof (int); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca (count * sizeof (int)); + + /* Read all the longwords */ + for (i = 0; i < count; i++, addr += sizeof (int)) + { + buffer[i] = ptrace (1, inferior_pid, addr, 0); + } + + /* Copy appropriate bytes out of the buffer. */ + bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len); +} + +/* Copy LEN bytes of data from debugger memory at MYADDR + to inferior's memory at MEMADDR. + On failure (cannot write the inferior) + returns the value of errno. */ + +int +write_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & - sizeof (int); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca (count * sizeof (int)); + extern int errno; + + /* Fill start and end extra bytes of buffer with existing memory data. */ + + buffer[0] = ptrace (1, inferior_pid, addr, 0); + + if (count > 1) + { + buffer[count - 1] + = ptrace (1, inferior_pid, + addr + (count - 1) * sizeof (int), 0); + } + + /* Copy data to be written over corresponding part of buffer */ + + bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len); + + /* Write the entire buffer. */ + + for (i = 0; i < count; i++, addr += sizeof (int)) + { + errno = 0; + ptrace (4, inferior_pid, addr, buffer[i]); + if (errno) + return errno; + } + + return 0; +} + +void +try_writing_regs_command () +{ + register int i; + register int value; + extern int errno; + + if (inferior_pid == 0) + error ("There is no inferior process now."); + + fetch_inferior_registers(); + for (i = 0;i<18 ; i ++) + { + QUIT; + errno = 0; + value = read_register(i); + write_register ( i, value); + if (errno == 0) + { + printf (" Succeeded with register %d; value 0x%x (%d).\n", + i, value, value); + } + else + printf (" Failed with register %d.\n", i); + } +} + +void +initialize () +{ + + inferior_pid = 0; + + +} + + +/* Return the contents of register REGNO, + regarding it as an integer. */ + +CORE_ADDR +read_register (regno) + int regno; +{ + /* This loses when REGISTER_RAW_SIZE (regno) != sizeof (int) */ + return *(int *) ®isters[REGISTER_BYTE (regno)]; +} + +/* Store VALUE in the register number REGNO, regarded as an integer. */ + +void +write_register (regno, val) + int regno, val; +{ + /* This loses when REGISTER_RAW_SIZE (regno) != sizeof (int) */ + *(int *) ®isters[REGISTER_BYTE (regno)] = val; + + if (have_inferior_p ()) + store_inferior_registers (regno); +} + + +int +have_inferior_p () +{ + return inferior_pid != 0; +} + +print_some_registers(regs) +int regs[]; +{ + register int i; + for (i = 0; i < 18; i++) { + printf("reg[%d] = %x\n", i, regs[i]); + } +} + +SHAR_EOF +cat << \SHAR_EOF > remote_server.c +/* Main code for remote server for GDB, the GNU Debugger. + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "param.h" +#include + +void read_inferior_memory(), fetch_inferior_registers(); +unsigned char resume(); +void kill_inferior(); +void initialize(), try_writing_regs_command(); +int create_inferior(), read_register(); + +extern char registers[]; +int inferior_pid; +extern char **environ; + +/* Descriptor for I/O to remote machine. */ +int remote_desc; +int kiodebug = 0; +int remote_debugging; + +void remote_send (); +void putpkt (); +void getpkt (); +void remote_open(); +void write_ok(); +void write_enn(); +void convert_ascii_to_int(); +void convert_int_to_ascii(); +void prepare_resume_reply(); +void decode_m_packet(); +void decode_M_packet(); + + +main(argc,argv) +int argc; char *argv[]; +{ + char ch,status, own_buf[2000], mem_buf[2000]; + int i=0; + unsigned char signal; + unsigned int mem_addr, len; + + initialize(); + printf("\nwill open serial link\n"); + remote_open("/dev/ttya",0); + + if(argc < 2) + { + printf("Enter name of program to be run with command line args\n"); + gets(own_buf); + inferior_pid = create_inferior(own_buf,environ); + printf("\nProcess %s created; pid = %d\n",own_buf,inferior_pid); + } + else + { + inferior_pid = create_inferior(argv[1],environ); + printf("\nProcess %s created; pid = %d\n",argv[1],inferior_pid); + } + + do { + getpkt(own_buf); + printf("\nPacket received is>:%s\n",own_buf); + i = 0; + ch = own_buf[i++]; + switch (ch) { + case 'h': /**********This is only for tweaking the gdb+ program *******/ + signal = resume(1,0,&status); + prepare_resume_reply(own_buf,status,signal); + break; + /*************end tweak*************************************/ + + case 'g': fetch_inferior_registers(); + convert_int_to_ascii(registers,own_buf,REGISTER_BYTES); + break; + case 'G': convert_ascii_to_int(&own_buf[1],registers,REGISTER_BYTES); + if(store_inferior_registers(-1)==0) + write_ok(own_buf); + else + write_enn(own_buf); + break; + case 'm': decode_m_packet(&own_buf[1],&mem_addr,&len); + read_inferior_memory(mem_addr,mem_buf,len); + convert_int_to_ascii(mem_buf,own_buf,len); + break; + case 'M': decode_M_packet(&own_buf[1],&mem_addr,&len,mem_buf); + if(write_inferior_memory(mem_addr,mem_buf,len)==0) + write_ok(own_buf); + else + write_enn(own_buf); + break; + case 'c': signal = resume(0,0,&status); + printf("\nSignal received is >: %0x \n",signal); + prepare_resume_reply(own_buf,status,signal); + break; + case 's': signal = resume(1,0,&status); + prepare_resume_reply(own_buf,status,signal); + break; + case 'k': kill_inferior(); + sprintf(own_buf,"q"); + putpkt(own_buf); + printf("\nObtained kill request...terminating\n"); + close(remote_desc); + exit(0); + case 't': try_writing_regs_command(); + own_buf[0] = '\0'; + break; + default : printf("\nUnknown option chosen by master\n"); + write_enn(own_buf); + break; + } + + putpkt(own_buf); + } while(1) ; + + close(remote_desc); + /** now get out of here**/ + printf("\nFinished reading data from serial link - Bye!\n"); + exit(0); + +} + +SHAR_EOF +cat << \SHAR_EOF > remote_utils.c +/* Remote utility routines for the remote server for GDB, the GNU debugger. + Copyright (C) 1986, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "param.h" +#include +#include +#include +#include +#include +#include +#include + +extern int remote_desc; +extern int remote_debugging; +extern int kiodebug; + +void remote_open(); +void remote_send(); +void putpkt(); +void getpkt(); + +void write_ok(); +void write_enn(); +void convert_ascii_to_int(); +void convert_int_to_ascii(); +void prepare_resume_reply(); + +/* Open a connection to a remote debugger. + NAME is the filename used for communication. */ + +void +remote_open (name, from_tty) + char *name; + int from_tty; +{ + struct sgttyb sg; + + remote_debugging = 0; + + remote_desc = open (name, O_RDWR); + if (remote_desc < 0) + printf("\ncould not open remote device\n"); + + ioctl (remote_desc, TIOCGETP, &sg); + sg.sg_flags = RAW; + ioctl (remote_desc, TIOCSETP, &sg); + + if (from_tty) + printf ("Remote debugging using %s\n", name); + remote_debugging = 1; +} + +/* Convert hex digit A to a number. */ + +static int +fromhex (a) + int a; +{ + if (a >= '0' && a <= '9') + return a - '0'; + else if (a >= 'a' && a <= 'f') + return a - 'a' + 10; + else + perror ("Reply contains invalid hex digit"); +} + +/* Convert number NIB to a hex digit. */ + +static int +tohex (nib) + int nib; +{ + if (nib < 10) + return '0'+nib; + else + return 'a'+nib-10; +} + +/* Send the command in BUF to the remote machine, + and read the reply into BUF. + Report an error if we get an error reply. */ + +void +remote_send (buf) + char *buf; +{ + putpkt (buf); + getpkt (buf); + + if (buf[0] == 'E') + perror ("Remote failure reply: %s", buf); +} + +/* Send a packet to the remote machine, with error checking. + The data of the packet is in BUF. */ + +void +putpkt (buf) + char *buf; +{ + int i; + unsigned char csum = 0; + char buf2[500]; + char buf3[1]; + int cnt = strlen (buf); + char *p; + + if (kiodebug) + fprintf (stderr, "Sending packet: %s\n", buf); + + /* Copy the packet into buffer BUF2, encapsulating it + and giving it a checksum. */ + + p = buf2; + *p++ = '$'; + + for (i = 0; i < cnt; i++) + { + csum += buf[i]; + *p++ = buf[i]; + } + *p++ = '#'; + *p++ = tohex ((csum >> 4) & 0xf); + *p++ = tohex (csum & 0xf); + + /* Send it over and over until we get a positive ack. */ + + do { + write (remote_desc, buf2, p - buf2); + read (remote_desc, buf3, 1); + } while (buf3[0] != '+'); +} + +static int +readchar () +{ + char buf[1]; + while (read (remote_desc, buf, 1) != 1) ; + return buf[0] & 0x7f; +} + +/* Read a packet from the remote machine, with error checking, + and store it in BUF. */ + +void +getpkt (buf) + char *buf; +{ + char *bp; + unsigned char csum, c, c1, c2; + extern kiodebug; + + while (1) + { + csum = 0; + while ((c = readchar()) != '$'); + + bp = buf; + while (1) + { + c = readchar (); + if (c == '#') + break; + *bp++ = c; + csum += c; + } + *bp = 0; + + c1 = fromhex (readchar ()); + c2 = fromhex (readchar ()); + if (csum == (c1 << 4) + c2) + break; + + printf ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n", + (c1 << 4) + c2, csum, buf); + write (remote_desc, "-", 1); + } + + write (remote_desc, "+", 1); + + if (kiodebug) + fprintf (stderr,"Packet received :%s\n", buf); +} + + +void +write_ok(buf) + char *buf; +{ + buf[0] = 'O'; + buf[1] = 'k'; + buf[2] = '\0'; +} + +void +write_enn(buf) + char *buf; +{ + buf[0] = 'E'; + buf[1] = 'N'; + buf[2] = 'N'; + buf[3] = '\0'; +} + +void +convert_int_to_ascii(from,to,n) +char *from, *to; int n; +{ + int nib ; + char ch; + while( n-- ) + { + ch = *from++; + nib = ((ch & 0xf0) >> 4)& 0x0f; + *to++ = tohex(nib); + nib = ch & 0x0f; + *to++ = tohex(nib); + } + *to++ = 0; +} + + +void +convert_ascii_to_int(from,to,n) +char *from, *to; int n; +{ + int nib1,nib2 ; + while( n-- ) + { + nib1 = fromhex(*from++); + nib2 = fromhex(*from++); + *to++ = (((nib1 & 0x0f)<< 4)& 0xf0) | (nib2 & 0x0f); + } +} + +void +prepare_resume_reply(buf,status,signal) +char *buf ,status; +unsigned char signal; +{ + int nib; + char ch; + + *buf++ = 'S'; + *buf++ = status; + nib = ((signal & 0xf0) >> 4) ; + *buf++ = tohex(nib); + nib = signal & 0x0f; + *buf++ = tohex(nib); + *buf++ = 0; +} + +void +decode_m_packet(from,mem_addr_ptr,len_ptr) +char *from; +unsigned int *mem_addr_ptr, *len_ptr; +{ + int i = 0, j = 0 ; + char ch; + *mem_addr_ptr = *len_ptr = 0; + /************debugging begin************/ + printf("\nIn decode_m_packet"); + /************debugging end************/ + + while((ch = from[i++]) != ',') + { + *mem_addr_ptr = *mem_addr_ptr << 4; + *mem_addr_ptr |= fromhex(ch) & 0x0f; + } + /************debugging begin************/ + printf("\nFinished mem_addr part"); + /************debugging end************/ + + for(j=0; j < 4; j++) + { + if((ch = from[i++]) == 0) + break; + *len_ptr = *len_ptr << 4; + *len_ptr |= fromhex(ch) & 0x0f; + } + /************debugging begin************/ + printf("\nFinished len_ptr part"); + /************debugging end************/ +} + +void +decode_M_packet(from,mem_addr_ptr,len_ptr,to) +char *from, *to; +unsigned int *mem_addr_ptr, *len_ptr; +{ + int i = 0, j = 0 ; + char ch; + *mem_addr_ptr = *len_ptr = 0; + /************debugging begin************/ + printf("\nIn decode_M_packet"); + /************debugging end************/ + + while((ch = from[i++]) != ',') + { + *mem_addr_ptr = *mem_addr_ptr << 4; + *mem_addr_ptr |= fromhex(ch) & 0x0f; + } + /************debugging begin************/ + printf("\nFinished mem_addr part: memaddr = %x",*mem_addr_ptr); + /************debugging end************/ + + while((ch = from[i++]) != ':') + { + *len_ptr = *len_ptr << 4; + *len_ptr |= fromhex(ch) & 0x0f; + } + /************debugging begin************/ + printf("\nFinished len_ptr part: len = %d",*len_ptr); + /************debugging end************/ + + convert_ascii_to_int(&from[i++],to,*len_ptr); + + /************debugging begin************/ + printf("\nmembuf : %x",*(int *)to); + /************debugging end************/ +} + +SHAR_EOF +# End of shell archive +exit 0 diff --git a/gdb/remote-sa.sparc.c b/gdb/remote-sa.sparc.c new file mode 100644 index 0000000000..686699e2da --- /dev/null +++ b/gdb/remote-sa.sparc.c @@ -0,0 +1,1146 @@ +/* THIS FILE HAS NOT HAD ITS COPYRIGHT CHECKED...FSF SHOULD NOT + DISTRIBUTE IT UNTIL THIS HAPPENS. */ + +/* Memory-access and commands for inferior process, for GDB. +*/ + +#include +#include +#include +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "value.h" +#include "inferior.h" +#include "symtab.h" + +#undef WSTOPSIG +#undef WTERMSIG +#include "wait.h" + +#ifdef USG +#include +#include +#endif + +#include +#include + +#include +#define TERMINAL struct termios + +#define LONGTIMEOUT 5 +#define SHORTTIMEOUT 1 + +#define KD_MINUTAE 1 +#define KD_LINEDISCIPLINE 2 +#define KD_RETRY 4 +#define KD_BLOCKTRANSFER 8 + +#ifndef STDIN +#define STDIN 0 +#endif + +#define GL_READING 0 /* get line is reading data */ +#define GL_OK 1 /* Getline saw the "ok" string */ +#define GL_SUCCESS 2 /* Get line got data */ +#define GL_TIMEOUT 3 /* Get line timed out */ +#define GL_OVERRUN 4 /* Get line filled up the buffer */ +#define GL_EXCEPTION 5 /* Get line saw "Exception" */ +#define GL_PROMLINE 6 /* Get line saw prom specific info */ +#define GL_BLANKLINE 7 /* Get line saw a blank line */ + +static int kiodebug /* = KD_RETRY | KD_BLOCKTRANSFER */; + +static CORE_ADDR remote_pc = 0; +static CORE_ADDR remote_next_pc = 0; +static CORE_ADDR remove_thisbp_next_pc = 0; +static CORE_ADDR remove_thisbp_target = 0; + +enum showDrainage {DONTSHOW , SHOW} ; + + +/* Descriptor for I/O to remote machine. Initialize it to -1 so that + remote_open knows that we don't have a file open when the program + starts. */ +int remote_desc = -1; + +int dontskipcrs = 0; + +#define PBUFSIZ 400 + +unsigned char ignorebuf[PBUFSIZ]; +#define IGNORE &ignorebuf[0] + +/* Maximum number of bytes to read/write at once. The value here + is chosen to fill up a packet (the headers account for the 32). */ +#define MAXBUFBYTES ((PBUFSIZ-32)/2) + +static void remote_send (); +static void putpkt (); +static int getpkt (); + + +/* Open a connection to a remote debugger. + NAME is the filename used for communication. */ +CORE_ADDR breakpoint_regs_addr; + + +void +remote_open (name, from_tty) + char *name; + int from_tty; +{ + extern int frame_file_full_name; + unsigned char buf[PBUFSIZ]; + TERMINAL sg; + + remote_debugging = 0; + + if (remote_desc >= 0) + close (remote_desc); + + breakpoint_regs_addr = parse_and_eval_address("&breakpoint_regs"); + + dontskipcrs = !frame_file_full_name; /* if we are running inside of + emacs, this will be true. + then skip carriage returns */ + + remote_desc = open (name, O_RDWR); + if (remote_desc < 0) + perror_with_name (name); + + setup_remote(); + + if (from_tty) + printf ("Remote debugging using %s\n", name); + remote_debugging = 1; + + +} +static char *boot_cmd = 0; + +static print_boot_cmd() +{ + fprintf(stderr, "boot command set to be \"%s\"\n", boot_cmd); +} + +remote_start() +{ + WAITTYPE ignoredWaitType; + + if (boot_cmd) + { + sendbreak(); + remote_wait (&ignoredWaitType); + putpkt ("reset"); + sleep(10); + sendbreak(); + remote_wait (&ignoredWaitType); + sleep(10); + print_boot_cmd(); + putpkt(boot_cmd); + fprintf(stderr, "rgdb and nucleus synchronized, booting....\n"); + } + else + { + error("The boot command is null. Cannot start the remote kernel/nucleus"); + } +} + +/* Close the open connection to the remote debugger. + Use this when you want to detach and do something else + with your gdb. */ +void +remote_close (from_tty) + int from_tty; +{ + if (!remote_debugging) + error ("Can't close remote connection: not debugging remotely."); + + close (remote_desc); /* This should never be called if + there isn't something valid in + remote_desc. */ + + /* Do not try to close remote_desc again, later in the program. */ + remote_desc = -1; + + if (from_tty) + printf ("Ending remote debugging\n"); + + remote_debugging = 0; +} + +/* Convert hex digit A to a number. */ + +static int +fromhex (a) + int a; +{ + if (a >= '0' && a <= '9') + return a - '0'; + else if (a >= 'a' && a <= 'f') + return a - 'a' + 10; + else + error ("Reply contains invalid hex digit"); +} + +/* Convert number NIB to a hex digit. */ + +static int +tohex (nib) + int nib; +{ + if (nib < 10) + return '0'+nib; + else + return 'a'+nib-10; +} + +/* Tell the remote machine to resume. */ + +extern int one_stepped; /* From machine dependent code */ +static int remote_set_one_stepped; + +int +remote_resume (step, signal) + int step, signal; +{ + if (step) + { + remote_single_step(); + } + remote_set_one_stepped = step; + putpkt("go"); +} + +/* Wait until the remote machine stops, then return, + storing status in STATUS just as `wait' would. */ + +int +remote_wait (status) + WAITTYPE *status; +{ + char last, this; + int pend, saveTheOh = 0; + + user_terminal_raw(); + + WSETEXIT ((*status), 0177); + last = this = 0; + + while (1) + { + char buf[PBUFSIZ]; + int readUser, readProm, state; + + doselect(&readUser, &readProm); + if (readProm) + { + switch (state = getline(buf, PBUFSIZ, SHORTTIMEOUT)) + { + case GL_BLANKLINE: + if (remote_set_one_stepped) + break; + + /* fall through */ + + default: + case GL_READING: + case GL_SUCCESS: + case GL_OVERRUN: + case GL_TIMEOUT: + if (kiodebug & KD_LINEDISCIPLINE) + fprintf(stderr, "%d<%s>\n", state, buf); + else + { + fprintf(stderr, "%s", buf); + fflush(stderr); + } + break; + case GL_OK: + remote_cleanup_after_stop(); + WSETSTOP ((*status), SIGTRAP); + return; + case GL_PROMLINE: + break; + } + } + if (readUser) + shuffleFromUserToProm(); + } +} +static TERMINAL userterminal; + +user_terminal_restore() +{ +#if 0 + int in_desc = fileno (stdin); + ioctl (in_desc, TCSETS, &userterminal); +#endif +} +static void set_term_raw(); + +user_terminal_raw() +{ +#if 0 + TERMINAL tempterminal; + int in_desc = fileno (stdin); + ioctl (in_desc, TCGETS, &userterminal); + tempterminal = userterminal; + + tempterminal.c_lflag &= ~(ICANON|ISIG|IEXTEN); + tempterminal.c_cc[VMIN] = 1; + tempterminal.c_cc[VTIME] = 0; + tempterminal.c_iflag &= ~(INPCK|IXON|IXOFF); + tempterminal.c_oflag = 0; + + ioctl (in_desc, TCSETS, &tempterminal); +#endif +} + +doselect(pReadUser, pReadProm) + int *pReadUser, *pReadProm; +{ + extern FILE *instream; + int in_desc = fileno (stdin); + int instreammask = 1 << in_desc; + int remotemask = 1 << remote_desc; + int rfds = instreammask | remotemask; + + select (32, &rfds, 0, 0, (struct timeval *) 0); /* 0 = Block indefinitely */ + *pReadUser = (rfds & instreammask) == instreammask; + *pReadProm = (rfds & remotemask) == remotemask; +} + + + +/* Read the remote registers into the block pRegisters. +implementation copied largely from fetch_inferior_registers () +in sparc-dep.c */ + +void +remote_fetch_registers(ignored) +int *ignored; +{ + struct regs inferior_registers; + extern char registers[]; + CORE_ADDR breakpoint_regs_target; + + if (breakpoint_regs_addr == 0) + { + error("no address for breakpoint_regs\n"); + return; + } + remote_read_inferior_memory(breakpoint_regs_addr, &breakpoint_regs_target, + sizeof(breakpoint_regs_target)); + + bzero(registers, REGISTER_BYTES); + registers[REGISTER_BYTE (0)] = 0; + + if (breakpoint_regs_target) + { + remote_read_inferior_memory(breakpoint_regs_target, &inferior_registers, + sizeof(inferior_registers)); + registers[REGISTER_BYTE (0)] = 0; + bcopy (&inferior_registers.r_g1, ®isters[REGISTER_BYTE (1)], 15 * 4); + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps; + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc; + *(int *)®isters[REGISTER_BYTE (NPC_REGNUM)] = inferior_registers.r_npc; + *(int *)®isters[REGISTER_BYTE (Y_REGNUM)] = inferior_registers.r_y; + remote_pc = inferior_registers.r_pc; + remote_next_pc = inferior_registers.r_npc; + remote_read_inferior_memory (inferior_registers.r_sp, + ®isters[REGISTER_BYTE (16)], + 16*4); + } + else + { + error("breakpoint_regs == 0\n"); + } +} + + + + +/* Write memory data directly to the remote machine. + This does not inform the data cache; the data cache uses this. + MEMADDR is the address in the remote memory space. + MYADDR is the address of the buffer in our space. + LEN is the number of bytes. */ + +int +remote_write_bytes (memaddr, myaddr, len) + CORE_ADDR memaddr; + unsigned char *myaddr; + int len; +{ + char buf[PBUFSIZ]; + int i; + + /* Command describes registers byte by byte, + each byte encoded as two hex characters. */ + + for (i = 0; i < len; i++) + { + sprintf(buf, "%x %x c!", myaddr[i], memaddr + i); + remote_send (buf, buf); + if (strstr(buf, "Exception")) + { + return EFAULT; + } + } + return 0; +} + +/* Copy LEN bytes of data from debugger memory at MYADDR + to inferior's memory at MEMADDR. Returns errno value. */ +int +remote_write_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + int xfersize; + int retval; + + while (len > 0) + { + if (len > MAXBUFBYTES) + xfersize = MAXBUFBYTES; + else + xfersize = len; + + retval = remote_write_bytes(memaddr, myaddr, xfersize); + if (retval) + return retval; /* error */ + + memaddr += xfersize; + myaddr += xfersize; + len -= xfersize; + } + return 0; /* no error */ +} + + +/* read a single character */ + +static int +readCharFromProm () +{ + char buf; + + buf = '\0'; + /* termio does the timeout for us. */ + read (remote_desc, &buf, 1); + return buf & 0x7f; +} + +/* Send the command in BUF to the remote machine, + and read the reply into BUF. + Report an error if we get an error reply. */ + +static void +remote_send (buf, buf2) + char *buf, *buf2; +{ + putpkt (buf); + getpkt (buf2); +} + +/* Send a single character out over the wire */ + +static void +putcharacter (ch) + char ch; +{ + + while (1) + { + int i; + + write(remote_desc, &ch, 1); + for (i = 0; i < 100; i++) + { + char nch = 0; + + if (read (remote_desc, &nch, 1) == 0) + i++; + if ((ch == nch) + || (ch == '\n' && nch == '\r') + || (ch == '\r' && nch == '\n')) + return; + if (kiodebug & KD_MINUTAE) + fprintf (stderr, "Sent %c(%d) Received %c(%d)\n", ch, ch, nch, nch); + } + } +} + +/* Send a packet to the remote machine, with error checking. + The data of the packet is in BUF. */ + +static void +putpkt (buf) + char *buf; +{ + int i; + int cnt = strlen (buf); + char ch; + + if (kiodebug & KD_LINEDISCIPLINE) + fprintf(stderr, "putpkt(%s)\n", buf); + + for (i = 0; i < cnt; i++) + putcharacter (buf[i]); + putcharacter ('\n'); +} + +jmp_buf getline_jmpbuf; + +/* Read a line from the remote machine, and store it in BUF. */ +getline_timer() +{ + alarm(0); + + if (kiodebug & KD_RETRY) + fprintf(stderr, "getline timed out\n"); + longjmp(getline_jmpbuf, 1); +} + +static int +getline (buf, size, timeout) + char *buf; + int size, timeout; +{ + int cnt = 0; + int state; + int isspace_state = 1; + + if ((void (*)) signal (SIGALRM, getline_timer) == (void (*)) -1) + perror ("remote_open: error in signal"); + + --size; /* back it up one so that we can read */ + + state = GL_READING; + + if (setjmp(getline_jmpbuf)) + state = GL_TIMEOUT; + else + { + alarm (timeout); + do + { + char ch = readCharFromProm(); + isspace_state = isspace_state && isspace(ch); + if (ch && (dontskipcrs || ch != '\r')) + { + buf[cnt++] = ch; + buf[cnt] = '\0'; + } + if (kiodebug & KD_MINUTAE) + fprintf (stderr,"letter received :%c\n", buf[cnt - 1]); + if (cnt >= 2 && buf[cnt - 2] == 'o' && buf[cnt - 1] == 'k') + state = GL_OK; + else if (buf[cnt - 1] == '\n' ) + state = isspace_state ? GL_BLANKLINE : GL_SUCCESS; + else if (cnt == size) + state = GL_OVERRUN; + else if (strstr(buf, "Type 'go' to resume")) + state = GL_PROMLINE; + else if (strstr(buf, "Type help for more information")) + state = GL_PROMLINE; + else if (strstr(buf, "Exception")) + state = GL_EXCEPTION; + } + while (state == GL_READING); + } + alarm (0); + + if (kiodebug & KD_LINEDISCIPLINE) + fprintf (stderr,"Line received :%s\n", buf); + return state; +} + + +/* Read a packet from the remote machine, and store it in BUF. */ + +static int +getpkt (buf) + char *buf; +{ + int cnt = 0; + + do + { + char ch = readCharFromProm(); + if (ch) + buf[cnt++] = ch; + if (kiodebug & KD_MINUTAE) + fprintf (stderr,"letter received :%c\n", buf[cnt - 1]); + } + while (cnt < 2 || + buf[cnt - 2] != 'o' && + buf[cnt - 1] != 'k'); + + buf[cnt] = '\0'; + if (kiodebug& KD_LINEDISCIPLINE) + fprintf (stderr,"Packet received :%s\n", buf); + return cnt; +} + +void remote_fetch_word (addr) + CORE_ADDR addr; +{ + error ("Internal error: remote_fetch_word is obsolete.\n"); +} +void remote_store_word (addr) + CORE_ADDR addr; +{ + error ("Internal error: remote_store_word is obsolete.\n"); +} +#include + +draininput(showit) +enum showDrainage showit; +{ + unsigned char buf[PBUFSIZ]; + int cnt; + + while ((cnt = read(remote_desc, buf, PBUFSIZ)) > 0) + { + buf[cnt] = 0; + if (kiodebug& KD_LINEDISCIPLINE) + fprintf (stderr,"Draining :%s\n", buf); + else + if (showit == SHOW) + fprintf (stderr,"%s", buf); + } + if (kiodebug& KD_LINEDISCIPLINE) + fprintf (stderr,"Drained\n"); +} +sendbreak() +{ + if (kiodebug & KD_RETRY) + fprintf (stderr,"rgdb sending break to target...\n"); + else + { + fprintf (stderr,"="); + fflush(stderr); + } + + ioctl (remote_desc, TCSBRK, 0); + sleep(5); +} + + +/* shuffle a character from the user to remote debugger */ + +int +shuffleFromUserToProm() +{ + char ch; + static int escape = 0; + + extern FILE *instream; + + ch = 0; + if (read(STDIN, &ch , 1) != 1 || ch == 0) + return; + + if (escape) { + if (ch == '#') + sendbreak(); + else if (ch == '.') + { + while (ch != '\n') + read(STDIN, &ch , 1); + return 1; + } + else { + static char tilde = '~'; + + putcharacter(tilde); + putcharacter(ch); + } + escape = 0; + } else /* not escape */ { + if (ch == '~') + escape = 1; + else + putcharacter(ch); + } + return 0; +} + + + +/* Tell the Prom put a breakpoint at memaddr */ +remote_insert_breakpoint(memaddr) + CORE_ADDR memaddr; +{ + char buf[PBUFSIZ]; + + /* Command describes registers byte by byte, + each byte encoded as two hex characters. */ + + sprintf(buf, "%x +bp", memaddr); + remote_send(buf, buf); + if (strstr(buf, "Exception")) + { + return EFAULT; + } + else + { + return 0; + } +} + +/* Tell the Prom remove the the breakpoint at memaddr */ +remote_remove_breakpoint(memaddr) + CORE_ADDR memaddr; +{ + char buf[PBUFSIZ]; + + /* Command describes registers byte by byte, + each byte encoded as two hex characters. */ + + sprintf(buf, "%x -bp", memaddr); + remote_send(buf, buf); + if (strstr(buf, "Exception")) + { + return EFAULT; + } + else + { + return 0; + } +} + + + + + +/* Read memory data directly from the remote machine. + This does not use the data cache; the data cache uses this. + MEMADDR is the address in the remote memory space. + MYADDR is the address of the buffer in our space. + LEN is the number of words. */ + +long +remote_read(memaddr, myaddr, len, increment, promcommand) + CORE_ADDR memaddr; + unsigned char *myaddr; + int len, increment; + char *promcommand; +{ + char buf[PBUFSIZ]; + char buf2[PBUFSIZ]; + int i; + unsigned long num; + + /* Command describes registers byte by byte, + each byte encoded as two hex characters. */ + + for (i = 0; i < len; i += increment) + { + sprintf(buf, promcommand, memaddr + i) ; + remote_send(buf, buf2); + remote_send(".", buf); + if (strstr(buf2, "Exception")) + { + bzero(&myaddr[i], len - i); + return -i; + } + else + { + char *pBuf; + for (pBuf = &buf[0]; *pBuf == '\r' || *pBuf == '\n'; pBuf++) + ; + sscanf(pBuf, "%x\n", &num); + switch (increment) + { + case 1: myaddr[i] = num; + if (num > 255) + fprintf(stderr, "number out of bounds %x truncating to %x\n", + num, myaddr[i]); + break; + case 4: {unsigned long *p; + p = (unsigned long *) &myaddr[i]; + *p = num; + } + break; + default: fprintf(stderr, "unknown increment\n"); break; + } + } + } + return i; +} + + + +/* Read LEN bytes from inferior memory at MEMADDR. Put the result + at debugger address MYADDR. Returns errno value. */ +int +remote_read_inferior_memory(memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + int xfersize; + while (len > 0) + { + int mod; + + if (len > MAXBUFBYTES) + xfersize = MAXBUFBYTES; + else + xfersize = len; + + mod = memaddr % 4; + if (mod == 0 && xfersize >= 4) + if (mod == 0 && xfersize >= 16) + { + xfersize = remote_read_many(memaddr, myaddr, (len & ~3)); + getpkt(IGNORE); + } + else + xfersize = remote_read(memaddr, myaddr, 4, 4, "%x @"); + else + xfersize = remote_read(memaddr, myaddr, max(mod, 1), 1, "%x c@"); + if (xfersize <= 0) + return EFAULT; /* error */ + memaddr += xfersize; + myaddr += xfersize; + len -= xfersize; + } + return 0; /* no error */ +} +static int baud_rate=B38400; + +static void set_term_raw(pTermio) + TERMINAL *pTermio; +{ + pTermio->c_cflag &= (CREAD|HUPCL|CLOCAL); + pTermio->c_cflag |= baud_rate | CS8; + pTermio->c_iflag = ISTRIP /* | IXON | IXOFF */; + pTermio->c_oflag = 0; + pTermio->c_lflag = 0; + pTermio->c_cc[VMIN] = 0; + pTermio->c_cc[VTIME] = 1; +} + +/* setup the remote termio stream */ +setup_remote() +{ + TERMINAL temptempio; + + ioctl(remote_desc, TCGETS, &temptempio); + set_term_raw(&temptempio); + ioctl(remote_desc, TCSETS, &temptempio); +} + +/* step one machine instruction */ +remote_single_step () +{ + CORE_ADDR next_pc, npc4, target, pc; + typedef enum + { + Error, not_branch, bicc, bicca, ba, baa, ticc, ta, + } branch_type; + branch_type br, isannulled(); + + npc4 = remote_next_pc + 4; /* branch not taken */ + + /* Always set breakpoint for NPC. */ + + remote_insert_breakpoint(remote_next_pc); + remove_thisbp_next_pc = remote_next_pc; + + /* printf ("set break at %x\n",remote_next_pc); */ + + br = isannulled (remote_pc, &target); + + if (br == bicca) + { + /* Conditional annulled branch will either end up at + npc (if taken) or at npc+4 (if not taken). + Trap npc+4. */ + remote_insert_breakpoint(npc4); + remove_thisbp_target = npc4; + } + else if (br == baa && target != remote_next_pc) + { + /* Unconditional annulled branch will always end up at + the target. */ + remote_insert_breakpoint(target); + remove_thisbp_target = target; + } +} + + + + +/* read many words of memory */ +long +remote_read_many(memaddr, myaddr, len) + CORE_ADDR memaddr; + unsigned char *myaddr; + int len; +{ +#define BLOCKSIZE 1024 + static int max_number_of_blocks = 24; + + char buf[PBUFSIZ]; + char buf2[PBUFSIZ]; + int i; + unsigned long *p; +/* Command describes registers byte by byte, + each byte encoded as two hex characters. */ + + len = min(len, max_number_of_blocks * BLOCKSIZE); + + sprintf(buf, "%x %x do i @ . cr 4 +loop", memaddr + len, memaddr); + putpkt(buf); + getline(buf2, PBUFSIZ, LONGTIMEOUT); /* I don't care */ + + p = (unsigned long *) myaddr; + for (i = 0; i < len; i += 4, p++) + { + extern int InspectIt; + + if (!InspectIt && ((i % BLOCKSIZE) == 0)) + fprintf(stderr, "+"); /* let 'em know that we are working */ + switch (getline(buf2, PBUFSIZ, LONGTIMEOUT)) + { + default: + case GL_PROMLINE: + case GL_READING: + case GL_OK: + case GL_OVERRUN: + case GL_TIMEOUT: + case GL_BLANKLINE: + /* resync and retry */ + max_number_of_blocks = max(1, i / BLOCKSIZE); + fprintf(stderr, "-"); /* let 'em know that we are working */ + + if (kiodebug & KD_BLOCKTRANSFER) + fprintf(stderr, "failed read_many %d %d/%d (%s)\n", + max_number_of_blocks, i, len, buf2); + sendbreak(); + return remote_read_many(memaddr, myaddr, len); + case GL_EXCEPTION: + return -i; + case GL_SUCCESS: + sscanf(buf2, "%x\n", p); + break; + } + } + if (kiodebug & KD_BLOCKTRANSFER) + fprintf(stderr, "success read_many %d %d/%d (%s)\n", max_number_of_blocks, + i, len, buf2); + return i; +} +/* + * allow the user to type directly to the prom ! + */ +prom_command() +{ + int readUser, readProm; + + user_terminal_raw(); + fprintf(stderr, "entering prom mode...\n"); + while (1) + { + doselect(&readUser, &readProm); + if (readUser) + if (shuffleFromUserToProm()) + { + fprintf(stderr, "exiting prom mode\n"); + user_terminal_restore(); + return; + } + if (readProm) + fprintf(stderr, "%c", readCharFromProm ()); + } +} +static char *boot_set_msg = "boot needs a string in quotes of the form \"boot vmunix\" "; +static char *baud_set_msg = "baud rate should be of the form \"set baud=9600\""; + +static void +set_boot (arg, from_tty) + char *arg; + int from_tty; +{ + int h, i; + + if (!arg) + { + print_boot_cmd(); + error_no_arg (boot_set_msg); + } + + arg = tilde_expand (arg); + make_cleanup (free, arg); + + i = strlen (arg) - 1; + + free (boot_cmd); + + h = 0; + while (*arg && h < i && (arg[h] == ' ' || arg[h] == '\t')) + { + h++; + arg++; + } + while (i > 0 && (arg[i] == ' ' || arg[i] == '\t')) + i--; + + if (h >= i || !*arg || arg[h] != '"' || arg[i] != '"') + error (boot_set_msg); + else + { + boot_cmd = savestring (++arg, i); + boot_cmd[i - 1] = '\0'; + } + if (from_tty) + print_boot_cmd(); +} + +static int bauds[] = { + 0, 50, 75, 110, 134, 150, 200, 300, 600, + 1200, 1800, 2400, 4800, 9600, 19200, 38400, -1 +}; + + +static int convert_to_baud_B(n) + int n; +{ + register int *p; + + for (p = bauds; *p != -1; p++) + if (*p != 0 && *p == n) + return (p - bauds); + return (NULL); +} + +static void print_acceptable_bauds() +{ + register int *p; + + for (p = bauds; *p != -1; p++) + if (*p != 0 ) + fprintf(stderr, "%d\n", *p); +} + +static void print_baud() +{ +fprintf(stderr, "the baud rate is now %d\n", bauds[baud_rate]); +} + +static void +set_baud (arg, from_tty) + char *arg; + int from_tty; +{ + int temp_baud_rate; + + if (!arg) + { + print_baud(); + print_acceptable_bauds(); + error_no_arg (baud_set_msg); + return; + } + + while (*arg && !isdigit(*arg)) + arg++; + + if (*arg && (temp_baud_rate = convert_to_baud_B(atoi(arg))) != NULL) + { + baud_rate = temp_baud_rate; + if (remote_debugging) + setup_remote(); + } + else + { + fprintf(stderr, "bad baud rate %s, acceptable values are\n", arg); + print_acceptable_bauds(); + } + + print_baud(); +} + + + + +void +_initialize_remote() +{ +/* Chain containing all defined set subcommands */ + +extern struct cmd_list_element *setlist; + + + add_com ("prom", class_obscure, prom_command, + "Conduct a dialogue directly with the prom. \ +only useful after an attach\n\ +Terminate by typing ~."); + + add_cmd ("boot_cmd", class_support, set_boot, boot_set_msg, &setlist); + + add_cmd ("baud", class_support, set_baud, baud_set_msg, &setlist); + + set_boot ("\"boot nucleus -d\"", 0); + } + + +/* Store the remote registers from the contents of the block REGS. */ + +void +remote_store_registers (registers) + char *registers; +{ + CORE_ADDR core; + struct regs inferior_registers; + + core = parse_and_eval_address("breakpoint_regs"); + + bcopy (®isters[REGISTER_BYTE (1)], + &inferior_registers.r_g1, 15 * 4); + + inferior_registers.r_ps = + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)]; + inferior_registers.r_pc = + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)]; + inferior_registers.r_npc = + *(int *)®isters[REGISTER_BYTE (NPC_REGNUM)]; + inferior_registers.r_y = + *(int *)®isters[REGISTER_BYTE (Y_REGNUM)]; + + remote_write_inferior_memory (*(int *)®isters[REGISTER_BYTE (SP_REGNUM)], + ®isters[REGISTER_BYTE (16)], + 16*4); + remote_write_inferior_memory (core, + &inferior_registers, + sizeof(inferior_registers)); +} + + + +/* we have stopped. do some cleanup */ +remote_cleanup_after_stop() +{ + if (remove_thisbp_next_pc) + { + remote_remove_breakpoint (remove_thisbp_next_pc); + remove_thisbp_next_pc = 0; + } + if (remove_thisbp_target) + { + remote_remove_breakpoint (remove_thisbp_target); + remove_thisbp_target = 0; + } + user_terminal_restore(); + + one_stepped = remote_set_one_stepped; +} diff --git a/gdb/remote-vx.68.c b/gdb/remote-vx.68.c new file mode 100644 index 0000000000..2c17b9e2ae --- /dev/null +++ b/gdb/remote-vx.68.c @@ -0,0 +1,1527 @@ +/* Memory-access and commands for remote VxWorks processes, for GDB. + Copyright (C) 1990 Free Software Foundation, Inc. + Contributed by Wind River Systems and Cygnus Support. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "defs.h" +#include "tm-vxworks68.h" +#include "param-no-tm.h" +#include "frame.h" +#include "inferior.h" +#include "wait.h" +#include "target.h" +#include "gdbcore.h" +#include "command.h" +#include "symtab.h" +#include "symfile.h" /* for struct complaint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#define free bogon_free /* Sun claims "int free()" not void */ +#include +#undef free +#include +#include +#include "xdr_ptrace.h" +#include "xdr_ld.h" +#include "xdr_rdb.h" +#include "dbgRpcLib.h" + +/* get rid of value.h if possible */ +#include +#include + +extern value call_function_by_hand (); +extern void symbol_file_command (); +extern int stop_soon_quietly; /* for wait_for_inferior */ + +static int net_ptrace_clnt_call (); /* Forward decl */ +static enum clnt_stat net_clnt_call (); /* Forward decl */ +extern struct target_ops vx_ops, vx_run_ops; /* Forward declaration */ + +/* Saved name of target host and called function for "info files". + Both malloc'd. */ + +static char *vx_host; +static char *vx_running; + +/* Nonzero means target that is being debugged remotely has a floating + point processor. */ + +static int target_has_fp; + +/* Default error message when the network is forking up. */ + +static const char rpcerr[] = "network target debugging: rpc error"; + +CLIENT *pClient; /* client used in net debugging */ +static int ptraceSock = RPC_ANYSOCK; +extern int errno; + +enum clnt_stat net_clnt_call(); +static void parse_args (); + +static struct timeval rpcTimeout = { 10, 0 }; + +static char *skip_white_space (); +static char *find_white_space (); + +/* Tell the VxWorks target system to download a file. + The load addresses of the text, data, and bss segments are + stored in pTextAddr, pDataAddr, and *pBssAddr (respectively). + Returns 0 for success, -1 for failure. */ + +static int +net_load (filename, pTextAddr, pDataAddr, pBssAddr) + char *filename; + CORE_ADDR *pTextAddr; + CORE_ADDR *pDataAddr; + CORE_ADDR *pBssAddr; + { + enum clnt_stat status; + struct ldfile ldstruct; + struct timeval load_timeout; + + bzero ((char *) &ldstruct, sizeof (ldstruct)); + + /* We invoke clnt_call () here directly, instead of through + net_clnt_call (), because we need to set a large timeout value. + The load on the target side can take quite a while, easily + more than 10 seconds. The user can kill this call by typing + CTRL-C if there really is a problem with the load. */ + + load_timeout.tv_sec = 0x7FFF7FFF; /* A large number, effectively inf. */ + load_timeout.tv_usec = 0; + + status = clnt_call (pClient, VX_LOAD, xdr_wrapstring, &filename, xdr_ldfile, + &ldstruct, load_timeout); + + if (status == RPC_SUCCESS) + { + if (*ldstruct.name == NULL) /* load failed on VxWorks side */ + return -1; + *pTextAddr = ldstruct.txt_addr; + *pDataAddr = ldstruct.data_addr; + *pBssAddr = ldstruct.bss_addr; + return 0; + } + else + return -1; + } + +/* returns 0 if successful, errno if RPC failed or VxWorks complains. */ + +static int +net_break (addr, procnum) + int addr; + u_long procnum; + { + enum clnt_stat status; + int break_status; + Rptrace ptrace_in; /* XXX This is stupid. It doesn't need to be a ptrace + structure. How about something smaller? */ + + bzero ((char *) &ptrace_in, sizeof (ptrace_in)); + break_status = 0; + + ptrace_in.addr = addr; + ptrace_in.pid = inferior_pid; + + status = net_clnt_call (procnum, xdr_rptrace, &ptrace_in, xdr_int, + &break_status); + + if (status != RPC_SUCCESS) + return errno; + + if (break_status == -1) + return ENOMEM; + return break_status; /* probably (FIXME) zero */ + } + +/* returns 0 if successful, errno otherwise */ + +int +vx_insert_breakpoint (addr) + int addr; + { + return net_break (addr, VX_BREAK_ADD); + } + +/* returns 0 if successful, errno otherwise */ + +int +vx_remove_breakpoint (addr) + int addr; + { + return net_break (addr, VX_BREAK_DELETE); + } + +/* Call a function on the VxWorks target system. + ARGS is a vector of values of arguments (NARGS of them). + FUNCTION is a value, the function to be called. + Returns a struct value * representing what the function returned. + May fail to return, if a breakpoint or signal is hit + during the execution of the function. */ + +#ifdef FIXME +/* FIXME, function calls are really fried. GO back to manual method. */ +value +vx_call_function (function, nargs, args) + value function; + int nargs; + value *args; +{ + register CORE_ADDR sp; + register int i; + CORE_ADDR start_sp; + static REGISTER_TYPE dummy[] = CALL_DUMMY; + REGISTER_TYPE dummy1[sizeof dummy / sizeof (REGISTER_TYPE)]; + CORE_ADDR old_sp; + struct type *value_type; + unsigned char struct_return; + CORE_ADDR struct_addr; + struct inferior_status inf_status; + struct cleanup *old_chain; + CORE_ADDR funaddr; + int using_gcc; + + save_inferior_status (&inf_status, 1); + old_chain = make_cleanup (restore_inferior_status, &inf_status); + + /* PUSH_DUMMY_FRAME is responsible for saving the inferior registers + (and POP_FRAME for restoring them). (At least on most machines) + they are saved on the stack in the inferior. */ + PUSH_DUMMY_FRAME; + + old_sp = sp = read_register (SP_REGNUM); + +#if 1 INNER_THAN 2 /* Stack grows down */ + sp -= sizeof dummy; + start_sp = sp; +#else /* Stack grows up */ + start_sp = sp; + sp += sizeof dummy; +#endif + + funaddr = find_function_addr (function, &value_type); + + { + struct block *b = block_for_pc (funaddr); + /* If compiled without -g, assume GCC. */ + using_gcc = b == NULL || BLOCK_GCC_COMPILED (b); + } + + /* Are we returning a value using a structure return or a normal + value return? */ + + struct_return = using_struct_return (function, funaddr, value_type, + using_gcc); + + /* Create a call sequence customized for this function + and the number of arguments for it. */ + bcopy (dummy, dummy1, sizeof dummy); + FIX_CALL_DUMMY (dummy1, start_sp, funaddr, nargs, args, + value_type, using_gcc); + +#if CALL_DUMMY_LOCATION == ON_STACK + write_memory (start_sp, dummy1, sizeof dummy); + +#else /* Not on stack. */ +#if CALL_DUMMY_LOCATION == BEFORE_TEXT_END + /* Convex Unix prohibits executing in the stack segment. */ + /* Hope there is empty room at the top of the text segment. */ + { + static checked = 0; + if (!checked) + for (start_sp = text_end - sizeof dummy; start_sp < text_end; ++start_sp) + if (read_memory_integer (start_sp, 1) != 0) + error ("text segment full -- no place to put call"); + checked = 1; + sp = old_sp; + start_sp = text_end - sizeof dummy; + write_memory (start_sp, dummy1, sizeof dummy); + } +#else /* After text_end. */ + { + int errcode; + sp = old_sp; + start_sp = text_end; + errcode = target_write_memory (start_sp, dummy1, sizeof dummy); + if (errcode != 0) + error ("Cannot write text segment -- call_function failed"); + } +#endif /* After text_end. */ +#endif /* Not on stack. */ + +#ifdef STACK_ALIGN + /* If stack grows down, we must leave a hole at the top. */ + { + int len = 0; + + /* Reserve space for the return structure to be written on the + stack, if necessary */ + + if (struct_return) + len += TYPE_LENGTH (value_type); + + for (i = nargs - 1; i >= 0; i--) + len += TYPE_LENGTH (VALUE_TYPE (value_arg_coerce (args[i]))); +#ifdef CALL_DUMMY_STACK_ADJUST + len += CALL_DUMMY_STACK_ADJUST; +#endif +#if 1 INNER_THAN 2 + sp -= STACK_ALIGN (len) - len; +#else + sp += STACK_ALIGN (len) - len; +#endif + } +#endif /* STACK_ALIGN */ + + /* Reserve space for the return structure to be written on the + stack, if necessary */ + + if (struct_return) + { +#if 1 INNER_THAN 2 + sp -= TYPE_LENGTH (value_type); + struct_addr = sp; +#else + struct_addr = sp; + sp += TYPE_LENGTH (value_type); +#endif + } + +#if defined (REG_STRUCT_HAS_ADDR) + { + /* This is a machine like the sparc, where we need to pass a pointer + to the structure, not the structure itself. */ + if (REG_STRUCT_HAS_ADDR (using_gcc)) + for (i = nargs - 1; i >= 0; i--) + if (TYPE_CODE (VALUE_TYPE (args[i])) == TYPE_CODE_STRUCT) + { + CORE_ADDR addr; +#if !(1 INNER_THAN 2) + /* The stack grows up, so the address of the thing we push + is the stack pointer before we push it. */ + addr = sp; +#endif + /* Push the structure. */ + sp = value_push (sp, args[i]); +#if 1 INNER_THAN 2 + /* The stack grows down, so the address of the thing we push + is the stack pointer after we push it. */ + addr = sp; +#endif + /* The value we're going to pass is the address of the thing + we just pushed. */ + args[i] = value_from_long (builtin_type_long, (LONGEST) addr); + } + } +#endif /* REG_STRUCT_HAS_ADDR. */ + +#ifdef PUSH_ARGUMENTS + PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr); +#else /* !PUSH_ARGUMENTS */ + for (i = nargs - 1; i >= 0; i--) + sp = value_arg_push (sp, args[i]); +#endif /* !PUSH_ARGUMENTS */ + +#ifdef CALL_DUMMY_STACK_ADJUST +#if 1 INNER_THAN 2 + sp -= CALL_DUMMY_STACK_ADJUST; +#else + sp += CALL_DUMMY_STACK_ADJUST; +#endif +#endif /* CALL_DUMMY_STACK_ADJUST */ + + /* Store the address at which the structure is supposed to be + written. Note that this (and the code which reserved the space + above) assumes that gcc was used to compile this function. Since + it doesn't cost us anything but space and if the function is pcc + it will ignore this value, we will make that assumption. + + Also note that on some machines (like the sparc) pcc uses a + convention like gcc's. */ + + if (struct_return) + STORE_STRUCT_RETURN (struct_addr, sp); + + /* Write the stack pointer. This is here because the statements above + might fool with it. On SPARC, this write also stores the register + window into the right place in the new stack frame, which otherwise + wouldn't happen. (See write_inferior_registers in sparc-xdep.c.) */ + write_register (SP_REGNUM, sp); + + /* Figure out the value returned by the function. */ + { + char retbuf[REGISTER_BYTES]; + + /* Execute the stack dummy routine, calling FUNCTION. + When it is done, discard the empty frame + after storing the contents of all regs into retbuf. */ + run_stack_dummy (start_sp + CALL_DUMMY_START_OFFSET, retbuf); + + do_cleanups (old_chain); + + return value_being_returned (value_type, retbuf, struct_return); + } +} +/* should return a value of some sort */ + +value +vx_call_function (funcAddr, nargs, args, valueType) + char *funcAddr; + int nargs; + value *args; + struct type * valueType; +{ + int i; + func_call funcInfo; + arg_value *argValue; + enum clnt_stat status; + register int len; + arg_value funcReturn; + value gdbValue; + + argValue = (arg_value *) xmalloc (nargs * sizeof (arg_value)); + + bzero (argValue, nargs * sizeof (arg_value)); + bzero (&funcReturn, sizeof (funcReturn)); + + for (i = nargs - 1; i >= 0; i--) + { + len = TYPE_LENGTH (VALUE_TYPE (args [i])); + + switch (TYPE_CODE (VALUE_TYPE (args[i]))) + { + /* XXX put other types here. Where's CHAR, etc??? */ + + case TYPE_CODE_FLT: + argValue[i].type = T_FLOAT; + break; + case TYPE_CODE_INT: + case TYPE_CODE_PTR: + case TYPE_CODE_ENUM: + case TYPE_CODE_FUNC: + argValue[i].type = T_INT; + break; + + case TYPE_CODE_UNDEF: + case TYPE_CODE_ARRAY: + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + case TYPE_CODE_VOID: + case TYPE_CODE_SET: + case TYPE_CODE_RANGE: + case TYPE_CODE_PASCAL_ARRAY: + case TYPE_CODE_MEMBER: /* C++ */ + case TYPE_CODE_METHOD: /* C++ */ + case TYPE_CODE_REF: /* C++ */ + default: + error ("No corresponding VxWorks type for %d. CHECK IT OUT!!!\n", + TYPE_CODE(VALUE_TYPE(args[i]))); + } /* switch */ + if (TYPE_CODE(VALUE_TYPE(args[i])) == TYPE_CODE_FUNC) + argValue[i].arg_value_u.v_int = VALUE_ADDRESS(args[i]); + else + bcopy (VALUE_CONTENTS (args[i]), (char *) &argValue[i].arg_value_u, + len); + } + + /* XXX what should the type of this function addr be? + * XXX Both in gdb and vxWorks + */ + funcInfo.func_addr = (int) funcAddr; + funcInfo.args.args_len = nargs; + funcInfo.args.args_val = argValue; + + status = net_clnt_call (VX_CALL_FUNC, xdr_func_call, (char *) &funcInfo, + xdr_arg_value, &funcReturn); + + free ((char *) argValue); + + if (status == RPC_SUCCESS) + { + /* XXX this assumes that vxWorks ALWAYS returns an int, and that + * XXX gdb isn't expecting anything more + */ + + /******************* + if (funcReturn.type == T_UNKNOWN) + return YYYXXX...; + *******************/ + gdbValue = allocate_value (valueType); + bcopy (&funcReturn.arg_value_u.v_int, VALUE_CONTENTS (gdbValue), + sizeof (int)); + return gdbValue; + } + else + error (rpcerr); + } +#endif /* FIXME */ + +/* Start an inferior process and sets inferior_pid to its pid. + EXEC_FILE is the file to run. + ALLARGS is a string containing the arguments to the program. + ENV is the environment vector to pass. + Returns process id. Errors reported with error(). + On VxWorks, we ignore exec_file. */ + +void +vx_create_inferior (exec_file, args, env) + char *exec_file; + char *args; + char **env; +{ + enum clnt_stat status; + arg_array passArgs; + TASK_START taskStart; + + bzero ((char *) &passArgs, sizeof (passArgs)); + bzero ((char *) &taskStart, sizeof (taskStart)); + + /* parse arguments, put them in passArgs */ + + parse_args (args, &passArgs); + + if (passArgs.arg_array_len == 0) + error ("You must specify a function name to run, and arguments if any"); + + status = net_clnt_call (PROCESS_START, xdr_arg_array, &passArgs, + xdr_TASK_START, &taskStart); + + if ((status != RPC_SUCCESS) || (taskStart.status == -1)) + error ("Can't create process on remote target machine"); + + /* Save the name of the running function */ + if (vx_running) + free (vx_running); + vx_running = savestring (passArgs.arg_array_val[0], + strlen (passArgs.arg_array_val[0])); + +#ifdef CREATE_INFERIOR_HOOK + CREATE_INFERIOR_HOOK (pid); +#endif + + push_target (&vx_run_ops); + inferior_pid = taskStart.pid; + +#if defined (START_INFERIOR_HOOK) + START_INFERIOR_HOOK (); +#endif + + /* We will get a trace trap after one instruction. + Insert breakpoints and continue. */ + + init_wait_for_inferior (); + + /* Set up the "saved terminal modes" of the inferior + based on what modes we are starting it with. */ + target_terminal_init (); + + /* Install inferior's terminal modes. */ + target_terminal_inferior (); + + /* remote_start(args); */ + /* trap_expected = 0; */ + stop_soon_quietly = 1; + wait_for_inferior (); /* Get the task spawn event */ + stop_soon_quietly = 0; + + /* insert_step_breakpoint (); FIXME, do we need this? */ + proceed(-1, -1, 0); +} + +/* Fill ARGSTRUCT in argc/argv form with the arguments from the + argument string ARGSTRING. */ + +static void +parse_args (arg_string, arg_struct) + register char *arg_string; + arg_array *arg_struct; +{ + register int arg_count = 0; /* number of arguments */ + register int arg_index = 0; + register char *p0; + + bzero ((char *) arg_struct, sizeof (arg_array)); + + /* first count how many arguments there are */ + + p0 = arg_string; + while (*p0 != '\0') + { + if (*(p0 = skip_white_space (p0)) == '\0') + break; + p0 = find_white_space (p0); + arg_count++; + } + + arg_struct->arg_array_len = arg_count; + arg_struct->arg_array_val = (char **) xmalloc ((arg_count + 1) + * sizeof (char *)); + + /* now copy argument strings into arg_struct. */ + + while (*(arg_string = skip_white_space (arg_string))) + { + p0 = find_white_space (arg_string); + arg_struct->arg_array_val[arg_index++] = savestring (arg_string, + p0 - arg_string); + arg_string = p0; + } + + arg_struct->arg_array_val[arg_count] = NULL; +} + +/* Advance a string pointer across whitespace and return a pointer + to the first non-white character. */ + +static char * +skip_white_space (p) + register char *p; +{ + while (*p == ' ' || *p == '\t') + p++; + return p; +} + +/* Search for the first unquoted whitespace character in a string. + Returns a pointer to the character, or to the null terminator + if no whitespace is found. */ + +static char * +find_white_space (p) + register char *p; +{ + register int c; + + while ((c = *p) != ' ' && c != '\t' && c) + { + if (c == '\'' || c == '"') + { + while (*++p != c && *p) + { + if (*p == '\\') + p++; + } + if (!*p) + break; + } + p++; + } + return p; +} + +/* Poll the VxWorks target system for an event related + to the debugged task. + Returns -1 if remote wait failed, task status otherwise. */ + +int +net_wait (pEvent) + RDB_EVENT *pEvent; +{ + int pid; + enum clnt_stat status; + + bzero ((char *) pEvent, sizeof (RDB_EVENT)); + + pid = inferior_pid; + status = net_clnt_call (PROCESS_WAIT, xdr_int, &pid, xdr_RDB_EVENT, pEvent); + + return (status == RPC_SUCCESS)? pEvent->status: -1; +} + +/* Suspend the remote task. + Returns -1 if suspend fails on target system, 0 otherwise. */ + +int +net_quit () +{ + int pid; + int quit_status; + enum clnt_stat status; + + quit_status = 0; + + /* don't let rdbTask suspend itself by passing a pid of 0 */ + + if ((pid = inferior_pid) == 0) + return -1; + + status = net_clnt_call (VX_TASK_SUSPEND, xdr_int, &pid, xdr_int, + &quit_status); + + return (status == RPC_SUCCESS)? quit_status: -1; +} + +/* Read a register or registers from the remote system. */ + +int +vx_read_register (regno) + int regno; +{ + int status; + Rptrace ptrace_in; + Ptrace_return ptrace_out; + struct regs inferior_registers; + struct fp_status inferior_fp_registers; + extern char registers[]; + + bzero ((char *) &ptrace_in, sizeof (ptrace_in)); + bzero ((char *) &ptrace_out, sizeof (ptrace_out)); + + /* FIXME, eventually only get the ones we need. */ + registers_fetched (); + + ptrace_in.pid = inferior_pid; + ptrace_out.info.more_data = (caddr_t) &inferior_registers; + status = net_ptrace_clnt_call (PTRACE_GETREGS, &ptrace_in, &ptrace_out); + if (status) + error (rpcerr); + if (ptrace_out.status == -1) + { + errno = ptrace_out.errno; + return -1; + } + +#ifdef I80960 +#else /* I80960 */ + bcopy (&inferior_registers, registers, 16 * 4); + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps; + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc; + + if (target_has_fp) + { + ptrace_in.pid = inferior_pid; + ptrace_out.info.more_data = (caddr_t) &inferior_fp_registers; + status = net_ptrace_clnt_call (PTRACE_GETFPREGS, &ptrace_in, &ptrace_out); + if (status) + error (rpcerr); + if (ptrace_out.status == -1) + { + errno = ptrace_out.errno; + return -1; + } + + bcopy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof inferior_fp_registers.fps_regs); + bcopy (&inferior_fp_registers.fps_control, + ®isters[REGISTER_BYTE (FPC_REGNUM)], + sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs); + } + else + { + bzero (®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof inferior_fp_registers.fps_regs); + bzero (®isters[REGISTER_BYTE (FPC_REGNUM)], + sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs); + } +#endif + return 0; +} + +/* Prepare to store registers. Since we will store all of them, + read out their current values now. */ + +void +vx_prepare_to_store () +{ + vx_read_register (-1); +} + + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + /* FIXME, look at REGNO to save time here */ + +vx_write_register (regno) + int regno; +{ + struct regs inferior_registers; + struct fp_status inferior_fp_registers; + extern char registers[]; + int status; + Rptrace ptrace_in; + Ptrace_return ptrace_out; + + bzero ((char *) &ptrace_in, sizeof (ptrace_in)); + bzero ((char *) &ptrace_out, sizeof (ptrace_out)); + + bcopy (registers, &inferior_registers, 16 * 4); + inferior_registers.r_ps = *(int *)®isters[REGISTER_BYTE (PS_REGNUM)]; + inferior_registers.r_pc = *(int *)®isters[REGISTER_BYTE (PC_REGNUM)]; + ptrace_in.pid = inferior_pid; + ptrace_in.info.ttype = REGS; + ptrace_in.info.more_data = (caddr_t) &inferior_registers; + + /* XXX change second param to be a proc number */ + status = net_ptrace_clnt_call (PTRACE_SETREGS, &ptrace_in, &ptrace_out); + if (status) + error (rpcerr); + if (ptrace_out.status == -1) + { + errno = ptrace_out.errno; + return -1; + } + + if (target_has_fp) + { + bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers, + sizeof inferior_fp_registers.fps_regs); + bcopy (®isters[REGISTER_BYTE (FPC_REGNUM)], + &inferior_fp_registers.fps_control, + sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs); + + ptrace_in.pid = inferior_pid; + ptrace_in.info.ttype = FPREGS; + ptrace_in.info.more_data = (caddr_t) &inferior_fp_registers; + + status = net_ptrace_clnt_call (PTRACE_SETFPREGS, &ptrace_in, &ptrace_out); + if (status) + error (rpcerr); + if (ptrace_out.status == -1) + { + errno = ptrace_out.errno; + return -1; + } + } + return 0; +} + +/* Copy LEN bytes to or from remote inferior's memory starting at MEMADDR + to debugger memory starting at MYADDR. WRITE is true if writing to the + inferior. + Result is the number of bytes written or read (zero if error). The + protocol allows us to return a negative count, indicating that we can't + handle the current address but can handle one N bytes further, but + vxworks doesn't give us that information. */ + +int +vx_xfer_memory (memaddr, myaddr, len, write) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + int status; + Rptrace ptrace_in; + Ptrace_return ptrace_out; + C_bytes data; + + bzero ((char *) &ptrace_in, sizeof (ptrace_in)); + bzero ((char *) &ptrace_out, sizeof (ptrace_out)); + + ptrace_in.pid = inferior_pid; /* XXX pid unnecessary for READDATA */ + ptrace_in.addr = (int) memaddr; /* Where from */ + ptrace_in.data = len; /* How many bytes */ + + if (write) + { + ptrace_in.info.ttype = DATA; + ptrace_in.info.more_data = (caddr_t) &data; + + data.bytes = (caddr_t) myaddr; /* Where from */ + data.len = len; /* How many bytes (again, for XDR) */ + + /* XXX change second param to be a proc number */ + status = net_ptrace_clnt_call (PTRACE_WRITEDATA, &ptrace_in, &ptrace_out); + } + else + { + ptrace_out.info.more_data = (caddr_t) &data; + data.bytes = myaddr; /* Where to */ + data.len = len; /* How many (again, for XDR) */ + + /* XXX change second param to be a proc number */ + status = net_ptrace_clnt_call (PTRACE_READDATA, &ptrace_in, &ptrace_out); + } + + if (status) + error (rpcerr); + if (ptrace_out.status == -1) + { + return 0; /* No bytes moved */ + } + return len; /* Moved *all* the bytes */ +} + +void +vx_files_info () +{ + printf ("\tAttached to host `%s'", vx_host); + printf (", which has %sfloating point", target_has_fp? "": "no "); + printf (".\n"); +} + +void +vx_run_files_info () +{ + printf ("\tRunning VxWorks process 0x%x, function `%s'.\n", + inferior_pid, vx_running); +} + +void +vx_resume (step, siggnal) + int step; + int siggnal; +{ + int status; + Rptrace ptrace_in; + Ptrace_return ptrace_out; + + if (siggnal != 0) + error ("Cannot send signals to VxWorks processes"); + + bzero ((char *) &ptrace_in, sizeof (ptrace_in)); + bzero ((char *) &ptrace_out, sizeof (ptrace_out)); + + ptrace_in.pid = inferior_pid; + ptrace_in.addr = 1; /* Target side insists on this, or it panics. */ + + /* XXX change second param to be a proc number */ + status = net_ptrace_clnt_call (step? PTRACE_SINGLESTEP: PTRACE_CONT, + &ptrace_in, &ptrace_out); + if (status) + error (rpcerr); + if (ptrace_out.status == -1) + { + errno = ptrace_out.errno; + perror_with_name ("Resuming remote process"); + } +} + +void +vx_mourn_inferior () +{ + pop_target (); /* Pop back to no-child state */ + generic_mourn_inferior (); +} + + +/* This function allows the addition of incrementally linked object files. */ + +void +vx_add_file_command (arg_string, from_tty) + char* arg_string; + int from_tty; +{ + CORE_ADDR text_addr; + CORE_ADDR data_addr; + CORE_ADDR bss_addr; + + if (arg_string == 0) + error ("add-file takes a file name in VxWorks"); + + arg_string = tilde_expand (arg_string); + make_cleanup (free, arg_string); + + dont_repeat (); + + if (net_load (arg_string, &text_addr, &data_addr, &bss_addr) == -1) + error ("Load failed on target machine"); + + /* FIXME, for now we ignore data_addr and bss_addr. */ + symbol_file_add (arg_string, from_tty, text_addr, 0); +} + +#ifdef FIXME /* Not ready for prime time */ +/* Single step the target program at the source or machine level. + Takes an error exit if rpc fails. + Returns -1 if remote single-step operation fails, else 0. */ + +static int +net_step () +{ + enum clnt_stat status; + int step_status; + SOURCE_STEP source_step; + + source_step.taskId = inferior_pid; + + if (step_range_end) + { + source_step.startAddr = step_range_start; + source_step.endAddr = step_range_end; + } + else + { + source_step.startAddr = 0; + source_step.endAddr = 0; + } + + status = net_clnt_call (VX_SOURCE_STEP, xdr_SOURCE_STEP, &source_step, + xdr_int, &step_status); + + if (status == RPC_SUCCESS) + return step_status; + else + error (rpcerr); +} +#endif + +/* Emulate ptrace using RPC calls to the VxWorks target system. + Returns nonzero (-1) if RPC status to VxWorks is bad, 0 otherwise. */ + +static int +net_ptrace_clnt_call (request, pPtraceIn, pPtraceOut) + enum ptracereq request; + Rptrace *pPtraceIn; + Ptrace_return *pPtraceOut; +{ + enum clnt_stat status; + + status = net_clnt_call (request, xdr_rptrace, pPtraceIn, xdr_ptrace_return, + pPtraceOut); + + if (status != RPC_SUCCESS) + return -1; + + return 0; +} + +/* Query the target for the name of the file from which VxWorks was + booted. pBootFile is the address of a pointer to the buffer to + receive the file name; if the pointer pointed to by pBootFile is + NULL, memory for the buffer will be allocated by XDR. + Returns -1 if rpc failed, 0 otherwise. */ + +int +net_get_boot_file (pBootFile) + char **pBootFile; +{ + enum clnt_stat status; + + status = net_clnt_call (VX_BOOT_FILE_INQ, xdr_void, (char *) 0, + xdr_wrapstring, pBootFile); + return (status == RPC_SUCCESS) ? 0 : -1; +} + +/* Fetch a list of loaded object modules from the VxWorks target. + Returns -1 if rpc failed, 0 otherwise + There's no way to check if the returned loadTable is correct. + VxWorks doesn't check it. */ + +int +net_get_symbols (pLoadTable) + ldtabl *pLoadTable; /* return pointer to ldtabl here */ +{ + enum clnt_stat status; + + bzero ((char *) pLoadTable, sizeof (struct ldtabl)); + + status = net_clnt_call (VX_STATE_INQ, xdr_void, 0, xdr_ldtabl, pLoadTable); + return (status == RPC_SUCCESS) ? 0 : -1; +} + +/* Look up a symbol in the VxWorks target's symbol table. + Returns status of symbol read on target side (0=success, -1=fail) + Returns -1 and complain()s if rpc fails. */ + +struct complaint cant_contact_target = + {"Lost contact with VxWorks target", 0, 0}; + +int +vx_lookup_symbol (name, pAddr) + char *name; /* symbol name */ + CORE_ADDR *pAddr; +{ + enum clnt_stat status; + SYMBOL_ADDR symbolAddr; + + *pAddr = 0; + bzero ((char *) &symbolAddr, sizeof (symbolAddr)); + + status = net_clnt_call (VX_SYMBOL_INQ, xdr_wrapstring, &name, + xdr_SYMBOL_ADDR, &symbolAddr); + if (status != RPC_SUCCESS) { + complain (&cant_contact_target, 0); + return -1; + } + + *pAddr = symbolAddr.addr; + return symbolAddr.status; +} + +/* Check to see if the VxWorks target has a floating point coprocessor. + Returns 1 if target has floating point processor, 0 otherwise. + Calls error() if rpc fails. */ + +int +net_check_for_fp () +{ + enum clnt_stat status; + bool_t fp = 0; /* true if fp processor is present on target board */ + + status = net_clnt_call (VX_FP_INQUIRE, xdr_void, 0, xdr_bool, &fp); + if (status != RPC_SUCCESS) + error (rpcerr); + + return (int) fp; +} + +/* Establish an RPC connection with the VxWorks target system. + Calls error () if unable to establish connection. */ + +void +net_connect (host) + char *host; +{ + struct sockaddr_in destAddr; + struct hostent *destHost; + + /* get the internet address for the given host */ + + if ((destHost = (struct hostent *) gethostbyname (host)) == NULL) + error ("Invalid hostname. Couldn't attach remote target."); + + bzero (&destAddr, sizeof (destAddr)); + + destAddr.sin_addr.s_addr = * (u_long *) destHost->h_addr; + destAddr.sin_family = AF_INET; + destAddr.sin_port = 0; /* set to actual port that remote + ptrace is listening on. */ + + /* Create a tcp client transport on which to issue + calls to the remote ptrace server. */ + + ptraceSock = RPC_ANYSOCK; + pClient = clnttcp_create (&destAddr, RDBPROG, RDBVERS, &ptraceSock, 0, 0); + /* FIXME, here is where we deal with different version numbers of the proto */ + + if (pClient == NULL) + { + clnt_pcreateerror ("\tnet_connect"); + error ("Couldn't connect to remote target."); + } +} + +/* Sleep for the specified number of milliseconds + * (assumed to be less than 1000). + * If select () is interrupted, returns immediately; + * takes an error exit if select () fails for some other reason. + */ + +static void +sleep_ms (ms) + long ms; +{ + struct timeval select_timeout; + int status; + + select_timeout.tv_sec = 0; + select_timeout.tv_usec = ms * 1000; + + status = select (0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &select_timeout); + + if (status < 0 && errno != EINTR) + perror_with_name ("select"); +} + +/* Wait for control to return from inferior to debugger. + If inferior gets a signal, we may decide to start it up again + instead of returning. That is why there is a loop in this function. + When this function actually returns it means the inferior + should be left stopped and GDB should read more commands. */ + +/* For network debugging with VxWorks. + * VxWorks knows when tasks hit breakpoints, receive signals, exit, etc, + * so vx_wait() receives this information directly from + * VxWorks instead of trying to figure out what happenned via a wait() call. + */ + +static int +vx_wait (status) + int *status; +{ + register int pid; + WAITTYPE w; + RDB_EVENT rdbEvent; + int quit_failed; + + do + { + /* If CTRL-C is hit during this loop, + suspend the inferior process. */ + + quit_failed = 0; + if (quit_flag) + { + quit_failed = (net_quit () == -1); + quit_flag = 0; + } + + /* If a net_quit () or net_wait () call has failed, + allow the user to break the connection with the target. + We can't simply error () out of this loop, since the + data structures representing the state of the inferior + are in an inconsistent state. */ + + if (quit_failed || net_wait (&rdbEvent) == -1) + { + terminal_ours (); + if (query ("Can't %s. Disconnect from target system? ", + (quit_failed) ? "suspend remote task" + : "get status of remote task")) + { + target_mourn_inferior(); + error ("Use the \"target\" command to reconnect."); + } + else + { + terminal_inferior (); + continue; + } + } + + + if (quit_failed || net_wait (&rdbEvent) == -1) + { + error ("Wait on remote target failed"); + } + + pid = rdbEvent.taskId; + if (pid == 0) + { + sleep_ms (200); /* FIXME Don't kill the network too badly */ + } + else if (pid != inferior_pid) + fatal ("Bad pid for debugged task: 0x%x\n", pid); + } while (pid == 0); + + /* FIXME, eventually do more then SIGTRAP on everything... */ + switch (rdbEvent.eventType) + { + case EVENT_EXIT: + WSETEXIT (w, 0); + /* FIXME is it possible to distinguish between a + XXX normal vs abnormal exit in VxWorks? */ + break; + + case EVENT_START: + WSETSTOP (w, SIGTRAP); + break; + + case EVENT_STOP: + WSETSTOP (w, SIGTRAP); + /* XXX was it stopped by a signal? act accordingly */ + break; + + case EVENT_BREAK: + /* Expecting a trace trap. Stop the inferior and + * return silently when it happens. */ + WSETSTOP (w, SIGTRAP); + break; + + case EVENT_SUSPEND: + target_terminal_ours_for_output (); + printf ("\nRemote task suspended\n"); /* FIXME */ + fflush (stdout); + WSETSTOP (w, SIGTRAP); + break; + + case EVENT_SIGNAL: + /* The target is not running Unix, and its + faults/traces do not map nicely into Unix signals. + Make sure they do not get confused with Unix signals + by numbering them with values higher than the highest + legal Unix signal. code in the arch-dependent PRINT_RANDOM_SIGNAL + routine will interpret the value for wait_for_inferior. */ + WSETSTOP (w, rdbEvent.sigType + NSIG); + break; + } /* switch */ + *status = *(int *)&w; /* Grumble union wait crap Grumble */ + return pid; +} + +static int +symbol_stub (arg) + int arg; +{ + char *bootFile = (char *)arg; + symbol_file_command (bootFile, 0); + return 1; +} + +static int +add_symbol_stub (arg) + int arg; +{ + struct ldfile *pLoadFile = (struct ldfile *)arg; + + symbol_file_add (pLoadFile->name, 0, pLoadFile->txt_addr, 0); + return 1; +} +/* Target command for VxWorks target systems. + + Used in vxgdb. Takes the name of a remote target machine + running vxWorks and connects to it to initialize remote network + debugging. */ + +static void +vx_open (args, from_tty) + char *args; + int from_tty; +{ + extern int close (); + char *bootFile; + extern char *source_path; + struct ldtabl loadTable; + struct ldfile *pLoadFile; + int i; + extern CLIENT *pClient; + + if (!args) + error_no_arg ("target machine name"); + + printf ("Attaching remote machine across net...\n"); + fflush (stdout); + + /* Allow the user to kill the connect attempt by typing ^C. + Wait until the call to target_has_fp () completes before + disallowing an immediate quit, since even if net_connect () + is successful, the remote debug server might be hung. */ + + immediate_quit++; + + net_connect (args); + target_has_fp = net_check_for_fp (); + printf_filtered ("Connected to %s\n", args); + + immediate_quit--; + + push_target (&vx_ops); + + /* Save a copy of the target host's name. */ + if (vx_host) + free (vx_host); + vx_host = savestring (args, strlen (args)); + + /* Find out the name of the file from which the target was booted + and load its symbol table. */ + + bootFile = NULL; + if (!net_get_boot_file (&bootFile)) + { + if (*bootFile) { + printf_filtered ("%s: ", bootFile); + if (catch_errors (symbol_stub, (int)bootFile, + "Error reading symbols from boot file")) + puts_filtered ("ok\n"); + } else if (from_tty) + printf ("VxWorks kernel symbols not loaded.\n"); + } + else + error ("Can't retrieve boot file name from target machine."); + + clnt_freeres (pClient, xdr_wrapstring, &bootFile); + + if (net_get_symbols (&loadTable) != 0) + error ("Can't read loaded modules from target machine"); + + i = 0-1; + while (++i < loadTable.tbl_size) + { + QUIT; /* FIXME, avoids clnt_freeres below: mem leak */ + pLoadFile = &loadTable.tbl_ent [i]; +#ifdef WRS_ORIG + { + register int desc; + struct cleanup *old_chain; + char *fullname = NULL; + + desc = openp (source_path, 0, pLoadFile->name, O_RDONLY, 0, &fullname); + if (desc < 0) + perror_with_name (pLoadFile->name); + old_chain = make_cleanup (close, desc); + add_file_at_addr (fullname, desc, pLoadFile->txt_addr, pLoadFile->data_addr, + pLoadFile->bss_addr); + do_cleanups (old_chain); + } +#else + /* Botches, FIXME: + (1) Searches the PATH, not the source path. + (2) data and bss are assumed to be at the usual offsets from text. */ + catch_errors (add_symbol_stub, (int)pLoadFile, + "Error in reading symbols from loaded module."); +#endif + } + + clnt_freeres (pClient, xdr_ldtabl, &loadTable); + + if (from_tty) + { + puts_filtered ("Success!\n"); + } +} + +/* Cross-net conversion of floats to and from extended form. + (This is needed because different target machines have different + extended floating point formats.) */ + +/* Convert from an extended float to a double. + + The extended float is stored as raw data pointed to by FROM. + Return the converted value as raw data in the double pointed to by TO. +*/ + +static void +vx_convert_to_virtual (regno, from, to) + int regno; + char *from; + char *to; +{ + enum clnt_stat status; + ext_fp from_ext_fp; + double to_double; + + if (REGISTER_CONVERTIBLE (regno)) + { + if (!target_has_fp) { + *(double *)to = 0.0; /* Skip the trouble if no float anyway */ + return; + } + bcopy (from, (char *) &from_ext_fp, sizeof (from_ext_fp)); + bzero ((char *) &to_double, sizeof (to_double)); + + status = net_clnt_call (VX_CONV_FROM_68881, xdr_ext_fp, &from_ext_fp, + xdr_double, &to_double); + if (status == RPC_SUCCESS) + bcopy ((char *) &to_double, to, sizeof (to_double)); + else + error (rpcerr); + } + else + bcopy (from, to, REGISTER_VIRTUAL_SIZE (regno)); +} + + +/* The converse: convert from a double to an extended float. + + The double is stored as raw data pointed to by FROM. + Return the converted value as raw data in the extended + float pointed to by TO. +*/ + +static void +vx_convert_from_virtual (regno, from, to) + int regno; + char *from; + char *to; +{ + enum clnt_stat status; + ext_fp to_ext_fp; + double from_double; + + if (REGISTER_CONVERTIBLE (regno)) + { + if (!target_has_fp) { + bzero (to, REGISTER_RAW_SIZE (FP0_REGNUM)); /* Shrug */ + return; + } + bcopy (from, (char *) &from_double, sizeof (from_double)); + bzero ((char *) &to_ext_fp, sizeof (to_ext_fp)); + + status = net_clnt_call (VX_CONV_TO_68881, xdr_double, &from_double, + xdr_ext_fp, &to_ext_fp); + if (status == RPC_SUCCESS) + bcopy ((char *) &to_ext_fp, to, sizeof (to_ext_fp)); + else + error (rpcerr); + } + else + bcopy (from, to, REGISTER_VIRTUAL_SIZE (regno)); +} + +/* Make an RPC call to the VxWorks target. + Returns RPC status. */ + +static enum clnt_stat +net_clnt_call (procNum, inProc, in, outProc, out) + enum ptracereq procNum; + xdrproc_t inProc; + char *in; + xdrproc_t outProc; + char *out; +{ + enum clnt_stat status; + + status = clnt_call (pClient, procNum, inProc, in, outProc, out, rpcTimeout); + + if (status != RPC_SUCCESS) + clnt_perrno (status); + + return status; +} + + +/* Target ops structure for accessing memory and such over the net */ + +struct target_ops vx_ops = { + "vxworks", "VxWorks target memory via RPC over TCP/IP", + vx_open, 0, /* vx_detach, */ + 0, 0, /* resume, wait */ + 0, 0, /* read_reg, write_reg */ + 0, vx_convert_to_virtual, vx_convert_from_virtual, /* prep_to_store, */ + vx_xfer_memory, vx_files_info, + 0, 0, /* insert_breakpoint, remove_breakpoint */ + 0, 0, 0, 0, 0, /* terminal stuff */ + 0, /* vx_kill, */ + vx_add_file_command, + call_function_by_hand, /* FIXME, calling fns is maybe botched? */ + vx_lookup_symbol, + vx_create_inferior, 0, /* mourn_inferior */ + core_stratum, 0, /* next */ + 1, 1, 0, 0, 0, /* all mem, mem, stack, regs, exec */ + OPS_MAGIC, /* Always the last thing */ +}; + +/* Target ops structure for accessing VxWorks child processes over the net */ + +struct target_ops vx_run_ops = { + "vxprocess", "VxWorks process", + vx_open, 0, /* vx_detach, */ + vx_resume, vx_wait, + vx_read_register, vx_write_register, + vx_prepare_to_store, vx_convert_to_virtual, vx_convert_from_virtual, + vx_xfer_memory, vx_run_files_info, + vx_insert_breakpoint, vx_remove_breakpoint, + 0, 0, 0, 0, 0, /* terminal stuff */ + 0, /* vx_kill, */ + vx_add_file_command, + call_function_by_hand, /* FIXME, calling fns is maybe botched? */ + vx_lookup_symbol, + vx_create_inferior, vx_mourn_inferior, + process_stratum, 0, /* next */ + 1, 1, 1, 1, 1, /* all mem, mem, stack, regs, exec */ + OPS_MAGIC, /* Always the last thing */ +}; +/* ==> Remember when reading at end of file, there are two "ops" structs here. */ + +void +_initialize_vx () +{ + add_target (&vx_ops); + add_target (&vx_run_ops); +} diff --git a/gdb/symm-tdep.c b/gdb/symm-tdep.c new file mode 100644 index 0000000000..aba21c3c43 --- /dev/null +++ b/gdb/symm-tdep.c @@ -0,0 +1,494 @@ +/* Sequent Symmetry target interface, for GDB when running under Unix. + Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* many 387-specific items of use taken from i386-dep.c */ + +#include +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" +#include "symtab.h" + +#include +#include +#include +#include +#include +#include +#include "gdbcore.h" +#include + +static long i386_get_frame_setup (); +static i386_follow_jump (); + +#include +#define TERMINAL struct sgttyb + +exec_file_command (filename, from_tty) + char *filename; + int from_tty; +{ + int val; + + /* Eliminate all traces of old exec file. + Mark text segment as empty. */ + + if (execfile) + free (execfile); + execfile = 0; + data_start = 0; + data_end -= exec_data_start; + text_start = 0; + text_end = 0; + exec_data_start = 0; + exec_data_end = 0; + if (execchan >= 0) + close (execchan); + execchan = -1; + + /* Now open and digest the file the user requested, if any. */ + + if (filename) + { + filename = tilde_expand (filename); + make_cleanup (free, filename); + + execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0, + &execfile); + if (execchan < 0) + perror_with_name (filename); + +#ifdef COFF_FORMAT + { + int aout_hdrsize; + int num_sections; + + if (read_file_hdr (execchan, &file_hdr) < 0) + error ("\"%s\": not in executable format.", execfile); + + aout_hdrsize = file_hdr.f_opthdr; + num_sections = file_hdr.f_nscns; + + if (read_aout_hdr (execchan, &exec_aouthdr, aout_hdrsize) < 0) + error ("\"%s\": can't read optional aouthdr", execfile); + + if (read_section_hdr (execchan, _TEXT, &text_hdr, num_sections, + aout_hdrsize) < 0) + error ("\"%s\": can't read text section header", execfile); + + if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections, + aout_hdrsize) < 0) + error ("\"%s\": can't read data section header", execfile); + + text_start = exec_aouthdr.text_start; + text_end = text_start + exec_aouthdr.tsize; + text_offset = text_hdr.s_scnptr; + exec_data_start = exec_aouthdr.data_start; + exec_data_end = exec_data_start + exec_aouthdr.dsize; + exec_data_offset = data_hdr.s_scnptr; + data_start = exec_data_start; + data_end += exec_data_start; + exec_mtime = file_hdr.f_timdat; + } +#else /* not COFF_FORMAT */ + { + struct stat st_exec; + + val = myread (execchan, &exec_aouthdr, sizeof (AOUTHDR)); + + if (val < 0) + perror_with_name (filename); + + text_start = N_ADDRADJ(exec_aouthdr); + exec_data_start = round(exec_aouthdr.a_text, NBPG*CLSIZE); + text_offset = N_TXTOFF (exec_aouthdr); + exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text; + text_end = exec_aouthdr.a_text; + exec_data_end = exec_data_start + exec_aouthdr.a_data; + data_start = exec_data_start; + data_end = data_start + exec_aouthdr.a_data; + exec_data_offset = N_TXTOFF(exec_aouthdr); + fstat (execchan, &st_exec); + exec_mtime = st_exec.st_mtime; + } +#endif /* not COFF_FORMAT */ + + validate_files (); + } + else if (from_tty) + printf ("No exec file now.\n"); + + /* Tell display code (if any) about the changed file name. */ + if (exec_file_display_hook) + (*exec_file_display_hook) (filename); +} + +/* rounds 'one' up to divide evenly by 'two' */ + +int +round(one,two) +register int one, two; + +{ + register int temp; + temp = (one/two)*two; + if (one != temp) { + temp += two; + } + return temp; +} + + +static CORE_ADDR codestream_next_addr; +static CORE_ADDR codestream_addr; +static unsigned char codestream_buf[sizeof (int)]; +static int codestream_off; +static int codestream_cnt; + +#define codestream_tell() (codestream_addr + codestream_off) +#define codestream_peek() (codestream_cnt == 0 ? \ + codestream_fill(1): codestream_buf[codestream_off]) +#define codestream_get() (codestream_cnt-- == 0 ? \ + codestream_fill(0) : codestream_buf[codestream_off++]) + + +static unsigned char +codestream_fill (peek_flag) +{ + codestream_addr = codestream_next_addr; + codestream_next_addr += sizeof (int); + codestream_off = 0; + codestream_cnt = sizeof (int); + read_memory (codestream_addr, + (unsigned char *)codestream_buf, + sizeof (int)); + + if (peek_flag) + return (codestream_peek()); + else + return (codestream_get()); +} + +static void +codestream_seek (place) +{ + codestream_next_addr = place & -sizeof (int); + codestream_cnt = 0; + codestream_fill (1); + while (codestream_tell() != place) + codestream_get (); +} + +static void +codestream_read (buf, count) + unsigned char *buf; +{ + unsigned char *p; + int i; + p = buf; + for (i = 0; i < count; i++) + *p++ = codestream_get (); +} + +/* + * Following macro translates i386 opcode register numbers to Symmetry + * register numbers. This is used by FRAME_FIND_SAVED_REGS. + * + * %eax %ecx %edx %ebx %esp %ebp %esi %edi + * i386 0 1 2 3 4 5 6 7 + * Symmetry 0 2 1 5 14 15 6 7 + * + */ +#define I386_REGNO_TO_SYMMETRY(n) \ +((n)==0?0 :(n)==1?2 :(n)==2?1 :(n)==3?5 :(n)==4?14 :(n)==5?15 :(n)) + +/* from i386-dep.c */ +i386_frame_find_saved_regs (fip, fsrp) + struct frame_info *fip; + struct frame_saved_regs *fsrp; +{ + unsigned long locals; + unsigned char *p; + unsigned char op; + CORE_ADDR dummy_bottom; + CORE_ADDR adr; + int i; + + bzero (fsrp, sizeof *fsrp); + + /* if frame is the end of a dummy, compute where the + * beginning would be + */ + dummy_bottom = fip->frame - 4 - NUM_REGS*4 - CALL_DUMMY_LENGTH; + + /* check if the PC is in the stack, in a dummy frame */ + if (dummy_bottom <= fip->pc && fip->pc <= fip->frame) + { + /* all regs were saved by push_call_dummy () */ + adr = fip->frame - 4; + for (i = 0; i < NUM_REGS; i++) + { + fsrp->regs[i] = adr; + adr -= 4; + } + return; + } + + locals = i386_get_frame_setup (get_pc_function_start (fip->pc)); + + if (locals >= 0) + { + adr = fip->frame - 4 - locals; + for (i = 0; i < 8; i++) + { + op = codestream_get (); + if (op < 0x50 || op > 0x57) + break; + fsrp->regs[I386_REGNO_TO_SYMMETRY(op - 0x50)] = adr; + adr -= 4; + } + } + + fsrp->regs[PC_REGNUM] = fip->frame + 4; + fsrp->regs[FP_REGNUM] = fip->frame; +} + +static long +i386_get_frame_setup (pc) +{ + unsigned char op; + + codestream_seek (pc); + + i386_follow_jump (); + + op = codestream_get (); + + if (op == 0x58) /* popl %eax */ + { + /* + * this function must start with + * + * popl %eax 0x58 + * xchgl %eax, (%esp) 0x87 0x04 0x24 + * or xchgl %eax, 0(%esp) 0x87 0x44 0x24 0x00 + * + * (the system 5 compiler puts out the second xchg + * inst, and the assembler doesn't try to optimize it, + * so the 'sib' form gets generated) + * + * this sequence is used to get the address of the return + * buffer for a function that returns a structure + */ + int pos; + unsigned char buf[4]; + static unsigned char proto1[3] = { 0x87,0x04,0x24 }; + static unsigned char proto2[4] = { 0x87,0x44,0x24,0x00 }; + pos = codestream_tell (); + codestream_read (buf, 4); + if (bcmp (buf, proto1, 3) == 0) + pos += 3; + else if (bcmp (buf, proto2, 4) == 0) + pos += 4; + + codestream_seek (pos); + op = codestream_get (); /* update next opcode */ + } + + if (op == 0x55) /* pushl %esp */ + { + if (codestream_get () != 0x8b) /* movl %esp, %ebp (2bytes) */ + return (-1); + if (codestream_get () != 0xec) + return (-1); + /* + * check for stack adjustment + * + * subl $XXX, %esp + * + * note: you can't subtract a 16 bit immediate + * from a 32 bit reg, so we don't have to worry + * about a data16 prefix + */ + op = codestream_peek (); + if (op == 0x83) /* subl with 8 bit immed */ + { + codestream_get (); + if (codestream_get () != 0xec) + return (-1); + /* subl with signed byte immediate + * (though it wouldn't make sense to be negative) + */ + return (codestream_get()); + } + else if (op == 0x81) /* subl with 32 bit immed */ + { + int locals; + if (codestream_get () != 0xec) + return (-1); + /* subl with 32 bit immediate */ + codestream_read ((unsigned char *)&locals, 4); + return (locals); + } + else + { + return (0); + } + } + else if (op == 0xc8) + { + /* enter instruction: arg is 16 unsigned immed */ + unsigned short slocals; + codestream_read ((unsigned char *)&slocals, 2); + codestream_get (); /* flush final byte of enter instruction */ + return (slocals); + } + return (-1); +} + +/* next instruction is a jump, move to target */ +static +i386_follow_jump () +{ + int long_delta; + short short_delta; + char byte_delta; + int data16; + int pos; + + pos = codestream_tell (); + + data16 = 0; + if (codestream_peek () == 0x66) + { + codestream_get (); + data16 = 1; + } + + switch (codestream_get ()) + { + case 0xe9: + /* relative jump: if data16 == 0, disp32, else disp16 */ + if (data16) + { + codestream_read ((unsigned char *)&short_delta, 2); + pos += short_delta + 3; /* include size of jmp inst */ + } + else + { + codestream_read ((unsigned char *)&long_delta, 4); + pos += long_delta + 5; + } + break; + case 0xeb: + /* relative jump, disp8 (ignore data16) */ + codestream_read ((unsigned char *)&byte_delta, 1); + pos += byte_delta + 2; + break; + } + codestream_seek (pos + data16); +} + +/* return pc of first real instruction */ +/* from i386-dep.c */ + +i386_skip_prologue (pc) +{ + unsigned char op; + int i; + + if (i386_get_frame_setup (pc) < 0) + return (pc); + + /* found valid frame setup - codestream now points to + * start of push instructions for saving registers + */ + + /* skip over register saves */ + for (i = 0; i < 8; i++) + { + op = codestream_peek (); + /* break if not pushl inst */ + if (op < 0x50 || op > 0x57) + break; + codestream_get (); + } + + i386_follow_jump (); + + return (codestream_tell ()); +} + +symmetry_extract_return_value(type, regbuf, valbuf) + struct type *type; + char *regbuf; + char *valbuf; +{ + union { + double d; + int l[2]; + } xd; + int i; + float f; + + if (TYPE_CODE_FLT == TYPE_CODE(type)) { + for (i = 0; i < misc_function_count; i++) { + if (!strcmp(misc_function_vector[i].name, "1167_flt")) + break; + } + if (i < misc_function_count) { + /* found "1167_flt" means 1167, %fp2-%fp3 */ + /* float & double; 19= %fp2, 20= %fp3 */ + /* no single precision on 1167 */ + xd.l[1] = *((int *)®buf[REGISTER_BYTE(19)]); + xd.l[0] = *((int *)®buf[REGISTER_BYTE(20)]); + switch (TYPE_LENGTH(type)) { + case 4: + f = (float) xd.d; + bcopy(&f, valbuf, TYPE_LENGTH(type)); + break; + case 8: + bcopy(&xd.d, valbuf, TYPE_LENGTH(type)); + break; + default: + error("Unknown floating point size"); + break; + } + } else { + /* 387 %st(0), gcc uses this */ + i387_to_double(((int *)®buf[REGISTER_BYTE(3)]), + &xd.d); + switch (TYPE_LENGTH(type)) { + case 4: /* float */ + f = (float) xd.d; + bcopy(&f, valbuf, 4); + break; + case 8: /* double */ + bcopy(&xd.d, valbuf, 8); + break; + default: + error("Unknown floating point size"); + break; + } + } + } else { + bcopy (regbuf, valbuf, TYPE_LENGTH (type)); + } +} diff --git a/gdb/symm-xdep.c b/gdb/symm-xdep.c new file mode 100644 index 0000000000..34496789ac --- /dev/null +++ b/gdb/symm-xdep.c @@ -0,0 +1,557 @@ +/* Sequent Symmetry host interface, for GDB when running under Unix. + Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* many 387-specific items of use taken from i386-dep.c */ + +#include +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" +#include "symtab.h" + +#include +#include +#include +#include +#include +#include +#include "gdbcore.h" +#include + +static long i386_get_frame_setup (); +static i386_follow_jump (); + +#include +#define TERMINAL struct sgttyb + +store_inferior_registers(regno) +int regno; +{ + struct pt_regset regs; + int reg_tmp, i; + extern char registers[]; + +#if 0 + /* PREPARE_TO_STORE deals with this. */ + if (-1 == regno) + { +#endif + regs.pr_eax = *(int *)®isters[REGISTER_BYTE(0)]; + regs.pr_ebx = *(int *)®isters[REGISTER_BYTE(5)]; + regs.pr_ecx = *(int *)®isters[REGISTER_BYTE(2)]; + regs.pr_edx = *(int *)®isters[REGISTER_BYTE(1)]; + regs.pr_esi = *(int *)®isters[REGISTER_BYTE(6)]; + regs.pr_edi = *(int *)®isters[REGISTER_BYTE(7)]; + regs.pr_esp = *(int *)®isters[REGISTER_BYTE(14)]; + regs.pr_ebp = *(int *)®isters[REGISTER_BYTE(15)]; + regs.pr_eip = *(int *)®isters[REGISTER_BYTE(16)]; + regs.pr_flags = *(int *)®isters[REGISTER_BYTE(17)]; + for (i = 0; i < 31; i++) { + regs.pr_fpa.fpa_regs[i] = + *(int *)®isters[REGISTER_BYTE(FP1_REGNUM+i)]; + } +#if 0 + } + else + { + reg_tmp = *(int *)®isters[REGISTER_BYTE(regno)]; + ptrace(XPT_RREGS, inferior_pid, ®s, 0); + switch (regno) + { + case 0: + regs.pr_eax = *(int *)®isters[REGISTER_BYTE(0)]; + break; + case 5: + regs.pr_ebx = *(int *)®isters[REGISTER_BYTE(5)]; + break; + case 2: + regs.pr_ecx = *(int *)®isters[REGISTER_BYTE(2)]; + break; + case 1: + regs.pr_edx = *(int *)®isters[REGISTER_BYTE(1)]; + break; + case 6: + regs.pr_esi = *(int *)®isters[REGISTER_BYTE(6)]; + break; + case 7: + regs.pr_edi = *(int *)®isters[REGISTER_BYTE(7)]; + break; + case 15: + regs.pr_ebp = *(int *)®isters[REGISTER_BYTE(15)]; + break; + case 14: + regs.pr_esp = *(int *)®isters[REGISTER_BYTE(14)]; + break; + case 16: + regs.pr_eip = *(int *)®isters[REGISTER_BYTE(16)]; + break; + case 17: + regs.pr_flags = *(int *)®isters[REGISTER_BYTE(17)]; + break; + } + } +#endif /* 0 */ + ptrace(XPT_WREGS, inferior_pid, ®s, 0); +} + +void +fetch_inferior_registers() +{ + int i; + struct pt_regset regs; + extern char registers[]; + + registers_fetched (); + + ptrace(XPT_RREGS, inferior_pid, ®s, 0); + *(int *)®isters[REGISTER_BYTE(0)] = regs.pr_eax; + *(int *)®isters[REGISTER_BYTE(5)] = regs.pr_ebx; + *(int *)®isters[REGISTER_BYTE(2)] = regs.pr_ecx; + *(int *)®isters[REGISTER_BYTE(1)] = regs.pr_edx; + *(int *)®isters[REGISTER_BYTE(6)] = regs.pr_esi; + *(int *)®isters[REGISTER_BYTE(7)] = regs.pr_edi; + *(int *)®isters[REGISTER_BYTE(15)] = regs.pr_ebp; + *(int *)®isters[REGISTER_BYTE(14)] = regs.pr_esp; + *(int *)®isters[REGISTER_BYTE(16)] = regs.pr_eip; + *(int *)®isters[REGISTER_BYTE(17)] = regs.pr_flags; + for (i = 0; i < FPA_NREGS; i++) { + *(int *)®isters[REGISTER_BYTE(FP1_REGNUM+i)] = regs.pr_fpa.fpa_regs[i]; + } + bcopy(regs.pr_fpu.fpu_stack[0], ®isters[REGISTER_BYTE(3)], 10); + bcopy(regs.pr_fpu.fpu_stack[1], ®isters[REGISTER_BYTE(4)], 10); + bcopy(regs.pr_fpu.fpu_stack[2], ®isters[REGISTER_BYTE(8)], 10); + bcopy(regs.pr_fpu.fpu_stack[3], ®isters[REGISTER_BYTE(9)], 10); + bcopy(regs.pr_fpu.fpu_stack[4], ®isters[REGISTER_BYTE(10)], 10); + bcopy(regs.pr_fpu.fpu_stack[5], ®isters[REGISTER_BYTE(11)], 10); + bcopy(regs.pr_fpu.fpu_stack[6], ®isters[REGISTER_BYTE(12)], 10); + bcopy(regs.pr_fpu.fpu_stack[7], ®isters[REGISTER_BYTE(13)], 10); +} + + +/* Work with core dump and executable files, for GDB. + This code would be in core.c if it weren't machine-dependent. */ + +#include "gdbcore.h" + +void +core_file_command (filename, from_tty) + char *filename; + int from_tty; +{ + int val; + extern char registers[]; + + /* Discard all vestiges of any previous core file + and mark data and stack spaces as empty. */ + + if (corefile) + free (corefile); + corefile = 0; + + if (corechan >= 0) + close (corechan); + corechan = -1; + + data_start = 0; + data_end = 0; + stack_start = STACK_END_ADDR; + stack_end = STACK_END_ADDR; + + /* Now, if a new core file was specified, open it and digest it. */ + + if (filename) + { + filename = tilde_expand (filename); + make_cleanup (free, filename); + + if (have_inferior_p ()) + error ("To look at a core file, you must kill the inferior with \"kill\"."); + corechan = open (filename, O_RDONLY, 0); + if (corechan < 0) + perror_with_name (filename); + /* 4.2-style (and perhaps also sysV-style) core dump file. */ + { + struct user u; + int reg_offset; + + val = myread (corechan, &u, sizeof u); + if (val < 0) + perror_with_name (filename); + data_start = exec_data_start; + + data_end = data_start + NBPG * (u.u_dsize - u.u_tsize); + stack_start = stack_end - NBPG * u.u_ssize; + data_offset = NBPG * UPAGES; + stack_offset = ctob(UPAGES + u.u_dsize - u.u_tsize); + reg_offset = (int) u.u_ar0 - KERNEL_U_ADDR; +printf("u.u_tsize= %#x, u.u_dsize= %#x, u.u_ssize= %#x, stack_off= %#x\n", + u.u_tsize, u.u_dsize, u.u_ssize, stack_offset); + + core_aouthdr.a_magic = 0; + + /* Read the register values out of the core file and store + them where `read_register' will find them. */ + + { + register int regno; + + for (regno = 0; regno < NUM_REGS; regno++) + { + char buf[MAX_REGISTER_RAW_SIZE]; + + val = lseek (corechan, register_addr (regno, reg_offset), 0); + if (val < 0) + perror_with_name (filename); + + val = myread (corechan, buf, sizeof buf); + if (val < 0) + perror_with_name (filename); + supply_register (regno, buf); + } + } + } + if (filename[0] == '/') + corefile = savestring (filename, strlen (filename)); + else + { + corefile = concat (current_directory, "/", filename); + } + + set_current_frame(create_new_frame(read_register(FP_REGNUM), + read_pc())); +/* set_current_frame (read_register (FP_REGNUM));*/ + select_frame (get_current_frame (), 0); + validate_files (); + } + else if (from_tty) + printf ("No core file now.\n"); +} + +/* from i386-dep.c */ +static +print_387_control_word (control) +unsigned short control; +{ + printf ("control 0x%04x: ", control); + printf ("compute to "); + switch ((control >> 8) & 3) + { + case 0: printf ("24 bits; "); break; + case 1: printf ("(bad); "); break; + case 2: printf ("53 bits; "); break; + case 3: printf ("64 bits; "); break; + } + printf ("round "); + switch ((control >> 10) & 3) + { + case 0: printf ("NEAREST; "); break; + case 1: printf ("DOWN; "); break; + case 2: printf ("UP; "); break; + case 3: printf ("CHOP; "); break; + } + if (control & 0x3f) + { + printf ("mask:"); + if (control & 0x0001) printf (" INVALID"); + if (control & 0x0002) printf (" DENORM"); + if (control & 0x0004) printf (" DIVZ"); + if (control & 0x0008) printf (" OVERF"); + if (control & 0x0010) printf (" UNDERF"); + if (control & 0x0020) printf (" LOS"); + printf (";"); + } + printf ("\n"); + if (control & 0xe080) printf ("warning: reserved bits on 0x%x\n", + control & 0xe080); +} + +static +print_387_status_word (status) + unsigned short status; +{ + printf ("status %#04x: ", status); + if (status & 0xff) { + printf ("exceptions:"); /* exception names match */ + if (status & 0x0001) printf (" FLTINV"); + if (status & 0x0002) printf (" FLTDEN"); + if (status & 0x0004) printf (" FLTDIV"); + if (status & 0x0008) printf (" FLTOVF"); + if (status & 0x0010) printf (" FLTUND"); + if (status & 0x0020) printf (" FLTPRE"); + if (status & 0x0040) printf (" FLTSTK"); + printf ("; "); + } + printf ("flags: %d%d%d%d; ", + (status & 0x4000) != 0, + (status & 0x0400) != 0, + (status & 0x0200) != 0, + (status & 0x0100) != 0); + + printf ("top %d\n", (status >> 11) & 7); +} + +static +print_fpu_status(ep) +struct pt_regset ep; + +{ + int i; + int bothstatus; + int top; + int fpreg; + unsigned char *p; + + printf("80387:"); + if (ep.pr_fpu.fpu_ip == 0) { + printf(" not in use.\n"); + return; + } else { + printf("\n"); + } + if (ep.pr_fpu.fpu_status != 0) { + print_387_status_word (ep.pr_fpu.fpu_status); + } + print_387_control_word (ep.pr_fpu.fpu_control); + printf ("last exception: "); + printf ("opcode 0x%x; ", ep.pr_fpu.fpu_rsvd4); + printf ("pc 0x%x:0x%x; ", ep.pr_fpu.fpu_cs, ep.pr_fpu.fpu_ip); + printf ("operand 0x%x:0x%x\n", ep.pr_fpu.fpu_data_offset, ep.pr_fpu.fpu_op_sel); + + top = (ep.pr_fpu.fpu_status >> 11) & 7; + + printf ("regno tag msb lsb value\n"); + for (fpreg = 7; fpreg >= 0; fpreg--) + { + double val; + + printf ("%s %d: ", fpreg == top ? "=>" : " ", fpreg); + + switch ((ep.pr_fpu.fpu_tag >> (fpreg * 2)) & 3) + { + case 0: printf ("valid "); break; + case 1: printf ("zero "); break; + case 2: printf ("trap "); break; + case 3: printf ("empty "); break; + } + for (i = 9; i >= 0; i--) + printf ("%02x", ep.pr_fpu.fpu_stack[fpreg][i]); + + i387_to_double (ep.pr_fpu.fpu_stack[fpreg], (char *)&val); + printf (" %g\n", val); + } + if (ep.pr_fpu.fpu_rsvd1) + printf ("warning: rsvd1 is 0x%x\n", ep.pr_fpu.fpu_rsvd1); + if (ep.pr_fpu.fpu_rsvd2) + printf ("warning: rsvd2 is 0x%x\n", ep.pr_fpu.fpu_rsvd2); + if (ep.pr_fpu.fpu_rsvd3) + printf ("warning: rsvd3 is 0x%x\n", ep.pr_fpu.fpu_rsvd3); + if (ep.pr_fpu.fpu_rsvd5) + printf ("warning: rsvd5 is 0x%x\n", ep.pr_fpu.fpu_rsvd5); +} + + +print_1167_control_word(pcr) +unsigned int pcr; + +{ + int pcr_tmp; + + pcr_tmp = pcr & FPA_PCR_MODE; + printf("\tMODE= %#x; RND= %#x ", pcr_tmp, pcr_tmp & 12); + switch (pcr_tmp & 12) { + case 0: + printf("RN (Nearest Value)"); + break; + case 1: + printf("RZ (Zero)"); + break; + case 2: + printf("RP (Positive Infinity)"); + break; + case 3: + printf("RM (Negative Infinity)"); + break; + } + printf("; IRND= %d ", pcr_tmp & 2); + if (0 == pcr_tmp & 2) { + printf("(same as RND)\n"); + } else { + printf("(toward zero)\n"); + } + pcr_tmp = pcr & FPA_PCR_EM; + printf("\tEM= %#x", pcr_tmp); + if (pcr_tmp & FPA_PCR_EM_DM) printf(" DM"); + if (pcr_tmp & FPA_PCR_EM_UOM) printf(" UOM"); + if (pcr_tmp & FPA_PCR_EM_PM) printf(" PM"); + if (pcr_tmp & FPA_PCR_EM_UM) printf(" UM"); + if (pcr_tmp & FPA_PCR_EM_OM) printf(" OM"); + if (pcr_tmp & FPA_PCR_EM_ZM) printf(" ZM"); + if (pcr_tmp & FPA_PCR_EM_IM) printf(" IM"); + printf("\n"); + pcr_tmp = FPA_PCR_CC; + printf("\tCC= %#x", pcr_tmp); + if (pcr_tmp & FPA_PCR_20MHZ) printf(" 20MHZ"); + if (pcr_tmp & FPA_PCR_CC_Z) printf(" Z"); + if (pcr_tmp & FPA_PCR_CC_C2) printf(" C2"); + if (pcr_tmp & FPA_PCR_CC_C1) printf(" C1"); + switch (pcr_tmp) { + case FPA_PCR_CC_Z: + printf(" (Equal)"); + break; + case FPA_PCR_CC_C1: + printf(" (Less than)"); + break; + case 0: + printf(" (Greater than)"); + break; + case FPA_PCR_CC_Z | FPA_PCR_CC_C1 | FPA_PCR_CC_C2: + printf(" (Unordered)"); + break; + default: + printf(" (Undefined)"); + break; + } + printf("\n"); + pcr_tmp = pcr & FPA_PCR_AE; + printf("\tAE= %#x", pcr_tmp); + if (pcr_tmp & FPA_PCR_AE_DE) printf(" DE"); + if (pcr_tmp & FPA_PCR_AE_UOE) printf(" UOE"); + if (pcr_tmp & FPA_PCR_AE_PE) printf(" PE"); + if (pcr_tmp & FPA_PCR_AE_UE) printf(" UE"); + if (pcr_tmp & FPA_PCR_AE_OE) printf(" OE"); + if (pcr_tmp & FPA_PCR_AE_ZE) printf(" ZE"); + if (pcr_tmp & FPA_PCR_AE_EE) printf(" EE"); + if (pcr_tmp & FPA_PCR_AE_IE) printf(" IE"); + printf("\n"); +} + +print_1167_regs(regs) +long regs[FPA_NREGS]; + +{ + int i; + + union { + double d; + long l[2]; + } xd; + union { + float f; + long l; + } xf; + + + for (i = 0; i < FPA_NREGS; i++) { + xf.l = regs[i]; + printf("%%fp%d: raw= %#x, single= %f", i+1, regs[i], xf.f); + if (!(i & 1)) { + printf("\n"); + } else { + xd.l[1] = regs[i]; + xd.l[0] = regs[i+1]; + printf(", double= %f\n", xd.d); + } + } +} + +print_fpa_status(ep) +struct pt_regset ep; + +{ + + printf("WTL 1167:"); + if (ep.pr_fpa.fpa_pcr !=0) { + printf("\n"); + print_1167_control_word(ep.pr_fpa.fpa_pcr); + print_1167_regs(ep.pr_fpa.fpa_regs); + } else { + printf(" not in use.\n"); + } +} + +i386_float_info () + +{ + char ubuf[UPAGES*NBPG]; + struct pt_regset regset; + extern int corechan; + + if (have_inferior_p()) { + call_ptrace(XPT_RREGS, inferior_pid, ®set, 0); + } else { + if (lseek (corechan, 0, 0) < 0) { + perror ("seek on core file"); + } + if (myread (corechan, ubuf, UPAGES*NBPG) < 0) { + perror ("read on core file"); + } + /* only interested in the floating point registers */ + regset.pr_fpu = ((struct user *) ubuf)->u_fpusave; + regset.pr_fpa = ((struct user *) ubuf)->u_fpasave; + } + print_fpu_status(regset); + print_fpa_status(regset); +} + +i387_to_double (from, to) + char *from; + char *to; +{ + long *lp; + /* push extended mode on 387 stack, then pop in double mode + * + * first, set exception masks so no error is generated - + * number will be rounded to inf or 0, if necessary + */ + asm ("pushl %eax"); /* grab a stack slot */ + asm ("fstcw (%esp)"); /* get 387 control word */ + asm ("movl (%esp),%eax"); /* save old value */ + asm ("orl $0x3f,%eax"); /* mask all exceptions */ + asm ("pushl %eax"); + asm ("fldcw (%esp)"); /* load new value into 387 */ + + asm ("movl 8(%ebp),%eax"); + asm ("fldt (%eax)"); /* push extended number on 387 stack */ + asm ("fwait"); + asm ("movl 12(%ebp),%eax"); + asm ("fstpl (%eax)"); /* pop double */ + asm ("fwait"); + + asm ("popl %eax"); /* flush modified control word */ + asm ("fnclex"); /* clear exceptions */ + asm ("fldcw (%esp)"); /* restore original control word */ + asm ("popl %eax"); /* flush saved copy */ +} + +double_to_i387 (from, to) + char *from; + char *to; +{ + /* push double mode on 387 stack, then pop in extended mode + * no errors are possible because every 64-bit pattern + * can be converted to an extended + */ + asm ("movl 8(%ebp),%eax"); + asm ("fldl (%eax)"); + asm ("fwait"); + asm ("movl 12(%ebp),%eax"); + asm ("fstpt (%eax)"); + asm ("fwait"); +} diff --git a/gdb/tm-vx68.h b/gdb/tm-vx68.h new file mode 100644 index 0000000000..a3cd7c22f6 --- /dev/null +++ b/gdb/tm-vx68.h @@ -0,0 +1,48 @@ +/* Parameters for execution on VxWorks 68k's, for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define GDBINIT_FILENAME ".vxgdbinit" + +#define DEFAULT_PROMPT "(vxgdb) " + +/* Kludge... */ +#include "tm-sun3.h" + +/* We have more complex, useful breakpoints on the target. */ +#undef DECR_PC_AFTER_BREAK +#define DECR_PC_AFTER_BREAK 0 + +/* We are guaranteed to have a zero frame pointer at bottom of stack, too. */ +#undef FRAME_CHAIN +#undef FRAME_CHAIN_VALID + +/* Takes the current frame-struct pointer and returns the chain-pointer + to get to the calling frame. + + If our current frame pointer is zero, we're at the top; else read out + the saved FP from memory pointed to by the current FP. */ + +#define FRAME_CHAIN(thisframe) ((thisframe)->frame? read_memory_integer ((thisframe)->frame, 4): 0) + +/* If the chain pointer is zero (either because the saved value fetched + by FRAME_CHAIN was zero, or because the current FP was zero so FRAME_CHAIN + never fetched anything), we are at the top of the stack. */ + +#define FRAME_CHAIN_VALID(chain, thisframe) (chain != 0) diff --git a/gdb/tm-vx960.h b/gdb/tm-vx960.h new file mode 100644 index 0000000000..fc5c21454f --- /dev/null +++ b/gdb/tm-vx960.h @@ -0,0 +1,48 @@ +/* Parameters for VxWorks Intel 960's, for GDB, the GNU debugger. + Copyright (C) 1986-1991 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "tm-i960.h" + +#define GDBINIT_FILENAME ".vxgdbinit" + +#define DEFAULT_PROMPT "(vxgdb) " + +/* We have more complex, useful breakpoints on the target. + Amount ip must be decremented by after a breakpoint. */ + +#define DECR_PC_AFTER_BREAK 0 + +/* We are guaranteed to have a zero frame pointer at bottom of stack, too. */ + +#define FRAME_CHAIN_VALID(chain, thisframe) (chain != 0) + +/* Breakpoint patching is handled at the target end in VxWorks. */ +/* #define BREAKPOINT {0x00, 0x3e, 0x00, 0x66} */ + +/* Not needed, because we don't support core files: + #define KERNEL_U_ADDR + #define REGISTER_U_ADDR(addr, blockend, regno) + */ + +/* Address of end of stack space. + This doesn't matter for VxWorks, because it's only used + in manipulation of core files, which we don't support. */ + +/* #define STACK_END_ADDR (0xfe000000) */ diff --git a/gdb/xm-i386sco.h b/gdb/xm-i386sco.h new file mode 100644 index 0000000000..e8ecc9938c --- /dev/null +++ b/gdb/xm-i386sco.h @@ -0,0 +1,37 @@ +/* Macro defintions for i386, running SCO Unix System V/386 3.2. + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "xm-i386v.h" + +/* Apparently there is inconsistency among various System V's about what + the name of this field is. */ +#define U_FPSTATE(u) u.u_fps.u_fpstate + +/* TIOCGETC is defined in System V 3.2 termio.h, but struct tchars + is not. This makes problems for inflow.c. */ +#define TIOCGETC_BROKEN + +/* All the job control definitions exist in SCO Unix, but the standard + shells don't use them. So we must disable job control. */ +#define NO_JOB_CONTROL + +/* SCO's assembler doesn't grok dollar signs in identifiers. + So we use dots instead. This item must be coordinated with G++. */ +#undef CPLUS_MARKER +#define CPLUS_MARKER '.'