Mercurial > illumos > s390-betelgeuse
changeset 10887:697142fd7740
First pass at enabling Dtrace on System z
line wrap: on
line diff
--- a/usr/src/common/dis/s390/dis_tables.c Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/common/dis/s390/dis_tables.c Thu Oct 08 12:44:34 2009 -0400 @@ -44,40 +44,6 @@ /* D e f i n e s */ /*------------------------------------------------------------------*/ -#define IFMT_E 0 -#define IFMT_I 1 -#define IFMT_RI1 2 -#define IFMT_RI2 3 -#define IFMT_RIE 4 -#define IFMT_RIL1 5 -#define IFMT_RIL2 6 -#define IFMT_RR 7 -#define IFMT_RRE 8 -#define IFMT_RRF1 9 -#define IFMT_RRF2 10 -#define IFMT_RRF3 11 -#define IFMT_RRR 12 -#define IFMT_RS1 13 -#define IFMT_RS2 14 -#define IFMT_RSI 15 -#define IFMT_RSL 16 -#define IFMT_RSY1 17 -#define IFMT_RSY2 18 -#define IFMT_RX 19 -#define IFMT_RXE 20 -#define IFMT_RXF 21 -#define IFMT_RXY 22 -#define IFMT_S 23 -#define IFMT_SI 24 -#define IFMT_SIY 25 -#define IFMT_SS1 26 -#define IFMT_SS2 27 -#define IFMT_SS3 28 -#define IFMT_SS4 29 -#define IFMT_SS5 30 -#define IFMT_SSE 31 -#define IFMT_SSF 32 - #define TBL_INV -1 #define TBL_01 -2 #define TBL_A5 -3 @@ -100,8 +66,6 @@ /* I n c l u d e s */ /*------------------------------------------------------------------*/ -#pragma ident "%Z%%M% %I% %E% NAF" - #include <sys/types.h> #include <sys/asm_linkage.h> #include "dis_tables.h" @@ -119,278 +83,6 @@ int8_t type; /* Entry type: IFMT_xxx, TBL_xxx */ } opCode_t; -typedef struct _E_t { - uint16_t opcode; -} __attribute__ ((packed)) E_t; - -typedef struct _I_t { - uint8_t opcode; - uint8_t i1; -} __attribute__ ((packed)) I_t; - -typedef struct _RI1_t { - uint8_t op1; - uint8_t r1 : 4; - uint8_t op2 : 4; - int16_t i2; -} __attribute__ ((packed)) RI1_t ; - -typedef struct _RI2_t { - uint8_t op1; - uint8_t m1 : 4; - uint8_t op2 : 4; - int16_t i2; -} __attribute__ ((packed)) RI2_t; - -typedef struct _RIE_t { - uint8_t op1; - uint8_t r1 : 4; - uint8_t r3 : 4; - int16_t i2; - uint8_t xxx; - uint8_t op2; -} __attribute__ ((packed)) RIE_t; - -typedef struct _RIL1_t { - uint8_t op1; - uint8_t r1 : 4; - uint8_t op2 : 4; - int32_t i2; -} __attribute__ ((packed)) RIL1_t; - -typedef struct _RIL2_t { - uint8_t op1; - uint8_t m1 : 4; - uint8_t op2 : 4; - int32_t i2; -} __attribute__ ((packed)) RIL2_t; - -typedef struct _RR_t { - uint8_t opcode; - uint8_t r1 : 4; - uint8_t r2 : 4; -} __attribute__ ((packed)) RR_t; - -typedef struct _RRE_t { - uint16_t opcode; - uint8_t xxx; - uint8_t r1 : 4; - uint8_t r2 : 4; -} __attribute__ ((packed)) RRE_t; - -typedef struct _RRF1_t { - uint16_t opcode; - uint8_t r1 : 4; - uint8_t xx : 4; - uint8_t r3 : 4; - uint8_t r2 : 4; -} __attribute__ ((packed)) RRF1_t; - -typedef struct _RRF2_t { - uint16_t opcode; - uint8_t m3 : 4; - uint8_t xx : 4; - uint8_t r1 : 4; - uint8_t r2 : 4; -} __attribute__ ((packed)) RRF2_t; - -typedef struct _RRF3_t { - uint16_t opcode; - uint8_t r3 : 4; - uint8_t m4 : 4; - uint8_t r1 : 4; - uint8_t r2 : 4; -} __attribute__ ((packed)) RRF3_t; - -typedef struct _RRR_t { - uint16_t opcode; - uint8_t r3 : 4; - uint8_t xx : 4; - uint8_t r1 : 4; - uint8_t r2 : 4; -} __attribute__ ((packed)) RRR_t; - -typedef struct _RS1_t { - uint8_t opcode; - uint8_t r1 : 4; - uint8_t r3 : 4; - uint16_t b2 : 4; - uint16_t d2 : 12; -} __attribute__ ((packed)) RS1_t; - -typedef struct _RS2_t { - uint8_t opcode; - uint8_t r1 : 4; - uint8_t m3 : 4; - uint16_t b2 : 4; - uint16_t d2 : 12; -} __attribute__ ((packed)) RS2_t; - -typedef struct _RSI_t { - uint8_t opcode; - uint8_t r1 : 4; - uint8_t r3 : 4; - int16_t i2; -} __attribute__ ((packed)) RSI_t; - -typedef struct _RSL_t { - uint8_t op1; - uint8_t l1 : 4; - uint8_t xx : 4; - uint16_t b1 : 4; - uint16_t d1 : 12; - uint8_t zz; - uint8_t op2; -} __attribute__ ((packed)) RSL_t; - -typedef struct _RSY1_t { - uint8_t op1; - uint8_t r1 : 4; - uint8_t r3 : 4; - uint16_t b2 : 4; - uint16_t dl : 12; - uint8_t dh; - uint8_t op2; -} __attribute__ ((packed)) RSY1_t; - -typedef struct _RSY2_t { - uint8_t op1; - uint8_t r1 : 4; - uint8_t m3 : 4; - uint16_t b2 : 4; - uint16_t dl : 12; - uint8_t dh; - uint8_t op2; -} __attribute__ ((packed)) RSY2_t; - -typedef struct _RX_t { - uint8_t opcode; - uint8_t r1 : 4; - uint8_t x2 : 4; - uint16_t b2 : 4; - uint16_t d2 : 12; -} __attribute__ ((packed)) RX_t; - -typedef struct _RXE_t { - uint8_t op1; - uint8_t r1 : 4; - uint8_t x2 : 4; - uint16_t b2 : 4; - uint16_t d2 : 12; - uint8_t xx; - uint8_t op2; -} __attribute__ ((packed)) RXE_t; - -typedef struct _RXF_t { - uint8_t op1; - uint8_t r3 : 4; - uint8_t x2 : 4; - uint16_t b2 : 4; - uint16_t d2 : 12; - uint8_t r1 : 4; - uint8_t xx : 4; - uint8_t op2; -} __attribute__ ((packed)) RXF_t; - -typedef struct _RXY_t { - uint8_t op1; - uint8_t r1 : 4; - uint8_t x2 : 4; - uint16_t b2 : 4; - uint16_t dl : 12; - uint8_t dh; - uint8_t op2; -} __attribute__ ((packed)) RXY_t; - -typedef struct _S_t { - uint16_t opcode; - uint16_t b2 : 4; - uint16_t d2 : 12; -} __attribute__ ((packed)) S_t; - -typedef struct _SI_t { - uint8_t opcode; - uint8_t i2; - uint16_t b1 : 4; - uint16_t d1 : 12; -} __attribute__ ((packed)) SI_t; - -typedef struct _SIY_t { - uint8_t opcode; - uint8_t i2; - uint16_t b1 : 4; - uint16_t dl : 12; - uint8_t dh; - uint8_t op2; -} __attribute__ ((packed)) SIY_t; - -typedef struct _SS1_t { - uint8_t opcode; - uint8_t l; - uint16_t b1 : 4; - uint16_t d1 : 12; - uint16_t b2 : 4; - uint16_t d2 : 12; -} __attribute__ ((packed)) SS1_t; - -typedef struct _SS2_t { - uint8_t opcode; - uint8_t l1 : 4; - uint8_t l2 : 4; - uint16_t b1 : 4; - uint16_t d1 : 12; - uint16_t b2 : 4; - uint16_t d2 : 12; -} __attribute__ ((packed)) SS2_t; - -typedef struct _SS3_t { - uint8_t opcode; - uint8_t l1 : 4; - uint8_t i3 : 4; - uint16_t b1 : 4; - uint16_t d1 : 12; - uint16_t b2 : 4; - uint16_t d2 : 12; -} __attribute__ ((packed)) SS3_t; - -typedef struct _SS4_t { - uint8_t opcode; - uint8_t r1 : 4; - uint8_t r3 : 4; - uint16_t b1 : 4; - uint16_t d1 : 12; - uint16_t b2 : 4; - uint16_t d2 : 12; -} __attribute__ ((packed)) SS4_t; - -typedef struct _SS5_t { - uint8_t opcode; - uint8_t r1 : 4; - uint8_t r3 : 4; - uint16_t b2 : 4; - uint16_t d2 : 12; - uint16_t b4 : 4; - uint16_t d4 : 12; -} __attribute__ ((packed)) SS5_t; - -typedef struct _SSE_t { - uint16_t opcode; - uint16_t b1 : 4; - uint16_t d1 : 12; - uint16_t b2 : 4; - uint16_t d2 : 12; -} __attribute__ ((packed)) SSE_t; - -typedef struct _SSF_t { - uint8_t op1; - uint8_t r3 : 4; - uint8_t op2 : 4; - uint16_t b1 : 4; - uint16_t d1 : 12; - uint16_t b2 : 4; - uint16_t d2 : 12; -} __attribute__ ((packed)) SSF_t; - /*========================= End of Typedefs ========================*/ /*------------------------------------------------------------------*/ @@ -543,8 +235,8 @@ {0x80, "SET SYSTEM MASK", "SSM", IFMT_S}, {0x82, "LOAD PSW", "LPSW", IFMT_S}, {0x83, "DIAGNOSE", "DIAG", IFMT_RSI}, - {0x84, "BRANCH RELATIVE ON INDEX HIGH (32)", "BRXH", IFMT_RSI}, - {0x85, "BRANCH RELATIVE ON INDEX LOW OR EQ. (32)", "BRXLE", IFMT_RSI}, + {0x84, "BRANCH RELATIVE ON INDEX HIGH (32)", "BRXH", IFMT_RSI|IFMT_PCREL}, + {0x85, "BRANCH RELATIVE ON INDEX LOW OR EQ. (32)", "BRXLE", IFMT_RSI|IFMT_RSI}, {0x86, "BRANCH ON INDEX HIGH (32)", "BXH", IFMT_RS1}, {0x87, "BRANCH ON INDEX LOW OR EQUAL (32)", "BXLE", IFMT_RS1}, {0x88, "SHIFT RIGHT SINGLE LOGICAL (32)", "SRL", IFMT_RS1}, @@ -683,7 +375,7 @@ {0x00, "", "", TBL_INV} }; -opCode_t opc_a5[] = { +static opCode_t opc_a5[] = { {0x00, "INSERT IMMEDIATE (high high)", "IIHH", IFMT_RI1}, {0x01, "INSERT IMMEDIATE (high low)", "IIHL", IFMT_RI1}, {0x02, "INSERT IMMEDIATE (low high)", "IILH", IFMT_RI1}, @@ -708,10 +400,10 @@ {0x01, "TEST UNDER MASK (low low)", "TMLL", IFMT_RI1}, {0x02, "TEST UNDER MASK (high high)", "TMHH", IFMT_RI1}, {0x03, "TEST UNDER MASK (high low)", "TMHL", IFMT_RI1}, - {0x04, "BRANCH RELATIVE ON CONDITION", "BRC", IFMT_RI2}, - {0x05, "BRANCH RELATIVE AND SAVE", "BRAS", IFMT_RI1}, - {0x06, "BRANCH RELATIVE ON COUNT (32)", "BRCT", IFMT_RI1}, - {0x07, "BRANCH RELATIVE ON COUNT (64)", "BRCTG", IFMT_RI1}, + {0x04, "BRANCH RELATIVE ON CONDITION", "BRC", IFMT_RI2|IFMT_PCREL}, + {0x05, "BRANCH RELATIVE AND SAVE", "BRAS", IFMT_RI1|IFMT_PCREL}, + {0x06, "BRANCH RELATIVE ON COUNT (32)", "BRCT", IFMT_RI1|IFMT_PCREL}, + {0x07, "BRANCH RELATIVE ON COUNT (64)", "BRCTG", IFMT_RI1|IFMT_PCREL}, {0x08, "LOAD HALFWORD IMMEDIATE (32)", "LHI", IFMT_RI1}, {0x09, "LOAD HALFWORD IMMEDIATE (64)", "LGHI", IFMT_RI1}, {0x0A, "ADD HALFWORD IMMEDIATE (32)", "AHI", IFMT_RI1}, @@ -1320,10 +1012,10 @@ }; static opCode_t opc_c0[] = { - {0x00, "LOAD ADDRESS RELATIVE LONG", "LARL", IFMT_RIL1}, - {0x01, "LOAD IMMEDIATE (64 32)", "LGFI", IFMT_RIL1}, - {0x04, "BRANCH RELATIVE ON CONDITION LONG", "BRCL", IFMT_RIL2}, - {0x05, "BRANCH RELATIVE AND SAVE LONG", "BRASL", IFMT_RIL1}, + {0x00, "LOAD ADDRESS RELATIVE LONG", "LARL", IFMT_RIL1|IFMT_PCREL}, + {0x01, "LOAD IMMEDIATE (64 32)", "LGFI", IFMT_RIL1|IFMT_PCREL}, + {0x04, "BRANCH RELATIVE ON CONDITION LONG", "BRCL", IFMT_RIL2|IFMT_PCREL}, + {0x05, "BRANCH RELATIVE AND SAVE LONG", "BRASL", IFMT_RIL1|IFMT_PCREL}, {0x06, "EXCLUSIVE OR IMMEDIATE (high)", "XIHF", IFMT_RIL1}, {0x07, "EXCLUSIVE OR IMMEDIATE (low)", "XILF", IFMT_RIL1}, {0x08, "INSERT IMMEDIATE (high)", "IIHF", IFMT_RIL1}, @@ -1489,8 +1181,10 @@ }; static opCode_t opc_ec[] = { - {0x44, "BRANCH RELATIVE ON INDEX HIGH (64)", "BRXHG", IFMT_RIE}, - {0x45, "BRANCH RELATIVE ON INDEX LOW OR EQ. (64)", "BRXLG", IFMT_RIE}, + {0x44, "BRANCH RELATIVE ON INDEX HIGH (64)", "BRXHG", IFMT_RIE1|IFMT_PCREL}, + {0x45, "BRANCH RELATIVE ON INDEX LOW OR EQ. (64)", "BRXLG", IFMT_RIE1|IFMT_PCREL}, + {0x64, "COMPARE AND BRANCH RELATIVE (32)", "CRJ", IFMT_RIE2|IFMT_PCREL}, + {0x76, "COMPARE AND BRANCH RELATIVE (64)", "CRGJ", IFMT_RIE2|IFMT_PCREL}, {0x00, "", "", TBL_INV} }; @@ -1554,6 +1248,13 @@ {0x00, "", "", TBL_INV} }; +/* + * The 1st two bits of the opcode describe the length of the + * instruction (in halfwords). 00 - one; 01/10 - two; 11 - three + * This table allows for a quick lookup and returns value in bytes + */ +static int lenTab[4] = {2, 4, 4, 6}; + /*====================== End of Global Variables ===================*/ /*------------------------------------------------------------------*/ @@ -1582,7 +1283,92 @@ /*------------------------------------------------------------------*/ /* */ -/* Name - dtrace_dis390x. */ +/* Name - dtrace_getfmtlen. */ +/* */ +/* Function - Get the format of the instruction and its length. */ +/* */ +/*------------------------------------------------------------------*/ + +int +dtrace_getfmtlen(char *instr, uint8_t *fmt) +{ + opCode_t *op; + + switch(opCodes[instr[0]].type) { + case TBL_INV: + return(-1); + break; + case TBL_01 : + op = findOpCode(opc_01, instr[1], 0xff); + if (op->type == TBL_INV) + return(-1); + break; + case TBL_A5 : + op = findOpCode(opc_a5, instr[1], 0x0f); + if (op->type == TBL_INV) + return(-1); + break; + case TBL_A7 : + op = findOpCode(opc_a7, instr[1], 0x0f); + if (op->type == TBL_INV) + return(-1); + case TBL_B2 : + op = &opc_b2[instr[1]]; + if (op->type == TBL_INV) + return(-1); + break; + case TBL_B3 : + op = &opc_b3[instr[1]]; + if (op->type == TBL_INV) + return(-1); + break; + case TBL_C0 : + op = findOpCode(opc_c0, instr[1], 0x0f); + if (op->type == TBL_INV) + return(-1); + break; + case TBL_C2 : + op = findOpCode(opc_c2, instr[1], 0x0f); + if (op->type == TBL_INV) + return(-1); + break; + case TBL_E3 : + op = findOpCode(opc_e3, instr[5], 0xff); + if (op->type == TBL_INV) + return(-1); + break; + case TBL_E5 : + op = findOpCode(opc_e5, instr[1], 0xff); + if (op->type == TBL_INV) + return(-1); + break; + case TBL_EB : + op = findOpCode(opc_eb, instr[5], 0xff); + if (op->type == TBL_INV) + return(-1); + break; + case TBL_EC : + op = findOpCode(opc_ec, instr[5], 0xff); + if (op->type == TBL_INV) + return(-1); + break; + case TBL_ED : + op = findOpCode(opc_ed, instr[5], 0xff); + if (op->type == TBL_INV) + return(-1); + break; + default : + op = &opCodes[instr[0]]; + } + *fmt = op->type; + return(lenTab[((instr[0] & 0xc0) >> 6)]); +} + +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - dtrace_dis390. */ /* */ /* Function - Disassemble a single s390x instruction. Returns */ /* non-zero for a bad opcode. */ @@ -1590,18 +1376,22 @@ /*------------------------------------------------------------------*/ int -dtrace_dis390x(dis390x_t *x, uint64_t pc, char *buf, size_t buflen) +dtrace_dis390(dis390_t *x, uint64_t pc, char *buf, size_t buflen) { uchar_t instr[8]; int size, iOp, + opLen, fmt; opCode_t *op; - size = x->d390x_get_bytes(x->d390x_data, &instr[0], 2); + size = x->d390_get_bytes(x->d390_data, &instr[0], 2); if (size == -1) return (-1); + opLen = (instr[0] & 0xc0) >> 6; + x->d390_len = lenTab[opLen]; + switch(opCodes[instr[0]].type) { case TBL_INV: return(-1); @@ -1641,7 +1431,7 @@ return(-1); break; case TBL_E3 : - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 4) == -1) + if (x->d390_get_bytes(x->d390_data, &instr[2], 4) == -1) return (-1); op = findOpCode(opc_e3, instr[5], 0xff); if (op->type == TBL_INV) @@ -1653,22 +1443,22 @@ return(-1); break; case TBL_EB : - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 4) == -1) + if (x->d390_get_bytes(x->d390_data, &instr[2], 4) == -1) return (-1); op = findOpCode(opc_eb, instr[5], 0xff); if (op->type == TBL_INV) return(-1); break; case TBL_EC : - x->d390x_data = &instr[2]; - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 4) == -1) + x->d390_data = &instr[2]; + if (x->d390_get_bytes(x->d390_data, &instr[2], 4) == -1) return (-1); op = findOpCode(opc_ec, instr[5], 0xff); if (op->type == TBL_INV) return(-1); break; case TBL_ED : - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 4) == -1) + if (x->d390_get_bytes(x->d390_data, &instr[2], 4) == -1) return (-1); op = findOpCode(opc_ed, instr[5], 0xff); if (op->type == TBL_INV) @@ -1684,78 +1474,99 @@ /* SIY formats we've read in 6 bytes because the 2nd part of*/ /* the op code is in bits 44-47. */ /*----------------------------------------------------------*/ - switch(op->type) { + x->d390_fmt = op->type; + switch((op->type & ~IFMT_PCREL)) { case IFMT_E : if (buf != NULL) { - x->d390x_sprintf_func(buf, buflen, "%p\t%s\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\n", pc, op->mnemonic); } break; case IFMT_I : - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 2) == -1) + if (x->d390_get_bytes(x->d390_data, &instr[2], 2) == -1) return (-1); if (buf != NULL) { I_t *tInstr = (I_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\t%d\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\t%d\n", pc, op->mnemonic, tInstr->i1); } break; case IFMT_RI1 : - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 2) == -1) + if (x->d390_get_bytes(x->d390_data, &instr[2], 2) == -1) return (-1); if (buf != NULL) { RI1_t *ri1Instr = (RI1_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\tR%d,%d\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\tR%d,%d\n", pc, op->mnemonic, ri1Instr->r1, ri1Instr->i2); } break; case IFMT_RI2 : - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 2) == -1) + if (x->d390_get_bytes(x->d390_data, &instr[2], 2) == -1) return (-1); if (buf != NULL) { RI2_t *ri2Instr = (RI2_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\t0x%x,%d\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\t0x%x,%d\n", pc, op->mnemonic, ri2Instr->m1, ri2Instr->i2); } break; - case IFMT_RIE : + case IFMT_RIE1 : if (buf != NULL) { - RIE_t *rieInstr = (RIE_t *) &instr[0]; + RIE1_t *rieInstr = (RIE1_t *) &instr[0]; void *br = (void *) (pc + rieInstr->i2 * 2); - x->d390x_sprintf_func(buf, buflen, "%p\t%s\tR%d,R%d,%p\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\tR%d,R%d,%p\n", pc, op->mnemonic, rieInstr->r1, rieInstr->r3, br); } break; + case IFMT_RIE2 : + if (buf != NULL) { + RIE2_t *rieInstr = (RIE2_t *) &instr[0]; + void *br = (void *) (pc + rieInstr->i4 * 2); + + x->d390_sprintf_func(buf, buflen, "%p\t%s\tR%d,R%d,%d,%p\n", + pc, op->mnemonic, rieInstr->r1, + rieInstr->r2, rieInstr->m3, br); + } + break; + case IFMT_RIE3 : + if (buf != NULL) { + RIE3_t *rieInstr = (RIE3_t *) &instr[0]; + + x->d390_sprintf_func(buf, buflen, "%p\t%s\tR%d,R%d,%d,%d\n", + pc, op->mnemonic, rieInstr->r1, + rieInstr->r2, rieInstr->i3, rieInstr->i4, + rieInstr->i5); + } + break; case IFMT_RIL1 : - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 4) == -1) + if (x->d390_get_bytes(x->d390_data, &instr[2], 4) == -1) return (-1); if (buf != NULL) { RIL1_t *ril1Instr = (RIL1_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\t%x,%d\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\t%x,%d\n", pc, op->mnemonic, ril1Instr->r1, ril1Instr->i2); } break; case IFMT_RIL2 : - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 4) == -1) + if (x->d390_get_bytes(x->d390_data, &instr[2], 4) == -1) return (-1); if (buf != NULL) { RIL2_t *ril2Instr = (RIL2_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\t%x,%d\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\t%x,%d\n", pc, op->mnemonic, ril2Instr->m1, ril2Instr->i2); } @@ -1764,106 +1575,106 @@ if (buf != NULL) { RR_t *rrInstr = (RR_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\tR%d,R%d\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\tR%d,R%d\n", pc, op->mnemonic, rrInstr->r1, rrInstr->r2); } break; case IFMT_RRE : - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 2) == -1) + if (x->d390_get_bytes(x->d390_data, &instr[2], 2) == -1) return (-1); if (buf != NULL) { RRE_t *rreInstr = (RRE_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\tR%d,%%d\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\tR%d,%%d\n", pc, op->mnemonic, rreInstr->r1, rreInstr->r2); } break; case IFMT_RRF1 : - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 2) == -1) + if (x->d390_get_bytes(x->d390_data, &instr[2], 2) == -1) return (-1); if (buf != NULL) { RRF1_t *rrf1Instr = (RRF1_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\tR%d,R%d,R%d\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\tR%d,R%d,R%d\n", pc, op->mnemonic, rrf1Instr->r1, rrf1Instr->r3, rrf1Instr->r2); } break; case IFMT_RRF2 : - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 2) == -1) + if (x->d390_get_bytes(x->d390_data, &instr[2], 2) == -1) return (-1); if (buf != NULL) { RRF2_t *rrf2Instr = (RRF2_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\tR%d,R%d,0x%x\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\tR%d,R%d,0x%x\n", pc, op->mnemonic, rrf2Instr->r1, rrf2Instr->r2, rrf2Instr->m3); } break; case IFMT_RRF3 : - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 2) == -1) + if (x->d390_get_bytes(x->d390_data, &instr[2], 2) == -1) return (-1); if (buf != NULL) { RRF3_t *rrf3Instr = (RRF3_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\tR%d,R%d,R%d,0x%x\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\tR%d,R%d,R%d,0x%x\n", pc, op->mnemonic, rrf3Instr->r1, rrf3Instr->r3, rrf3Instr->r2, rrf3Instr->m4); } break; case IFMT_RRR : - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 2) == -1) + if (x->d390_get_bytes(x->d390_data, &instr[2], 2) == -1) return (-1); if (buf != NULL) { RRR_t *rrrInstr = (RRR_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\tR%d,R%d,R%d,%d\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\tR%d,R%d,R%d,%d\n", pc, op->mnemonic, rrrInstr->r1, rrrInstr->r2, rrrInstr->r3); } break; case IFMT_RS1 : - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 2) == -1) + if (x->d390_get_bytes(x->d390_data, &instr[2], 2) == -1) return (-1); if (buf != NULL) { RS1_t *rs1Instr = (RS1_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\tR%d,R%d,%u(R%d)\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\tR%d,R%d,%u(R%d)\n", pc, op->mnemonic, rs1Instr->r1, rs1Instr->r3, rs1Instr->d2, rs1Instr->b2); } break; case IFMT_RS2 : - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 2) == -1) + if (x->d390_get_bytes(x->d390_data, &instr[2], 2) == -1) return (-1); if (buf != NULL) { RS2_t *rs2Instr = (RS2_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\tR%d,0x%x,%u(R%d)\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\tR%d,0x%x,%u(R%d)\n", pc, op->mnemonic, rs2Instr->r1, rs2Instr->m3, rs2Instr->d2, rs2Instr->b2); } break; case IFMT_RSI : - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 2) == -1) + if (x->d390_get_bytes(x->d390_data, &instr[2], 2) == -1) return (-1); if (buf != NULL) { RSI_t *rsiInstr = (RSI_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\tR%d,R%d,%d\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\tR%d,R%d,%d\n", pc, op->mnemonic, rsiInstr->r1, rsiInstr->r3, rsiInstr->i2); } @@ -1872,7 +1683,7 @@ if (buf != NULL) { RSL_t *rslInstr = (RSL_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\t%u(%d,R%d)\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\t%u(%d,R%d)\n", pc, op->mnemonic, rslInstr->d1, rslInstr->l1+1, rslInstr->b1); } @@ -1882,7 +1693,7 @@ RSY1_t *rsy1Instr = (RSY1_t *) &instr[0]; int disp = (rsy1Instr->dh << 12) + rsy1Instr->dl; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\tR%d,R%d,%d(R%d)\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\tR%d,R%d,%d(R%d)\n", pc, op->mnemonic, rsy1Instr->r1, rsy1Instr->r3, disp, rsy1Instr->b2); } @@ -1892,19 +1703,19 @@ RSY2_t *rsy2Instr = (RSY2_t *) &instr[0]; int disp = (rsy2Instr->dh << 12) + rsy2Instr->dl; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\tR%d,0x%x,%d(R%d)\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\tR%d,0x%x,%d(R%d)\n", pc, op->mnemonic, rsy2Instr->r1, rsy2Instr->m3, disp, rsy2Instr->b2); } break; case IFMT_RX : - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 2) == -1) + if (x->d390_get_bytes(x->d390_data, &instr[2], 2) == -1) return (-1); if (buf != NULL) { RX_t *rxInstr = (RX_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\tR%d,%u(R%d,R%d)\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\tR%d,%u(R%d,R%d)\n", pc, op->mnemonic, rxInstr->r1, rxInstr->d2, rxInstr->x2, rxInstr->b2); @@ -1914,7 +1725,7 @@ if (buf != NULL) { RXE_t *rxeInstr = (RXE_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\tR%d,%u(R%d,R%d)\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\tR%d,%u(R%d,R%d)\n", pc, op->mnemonic, rxeInstr->r1, rxeInstr->d2, rxeInstr->x2, rxeInstr->b2); } @@ -1923,7 +1734,7 @@ if (buf != NULL) { RXF_t *rxfInstr = (RXF_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\tR%d,R%d,%u(R%d,R%d)\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\tR%d,R%d,%u(R%d,R%d)\n", pc, op->mnemonic, rxfInstr->r1, rxfInstr->r3, rxfInstr->d2, rxfInstr->x2, rxfInstr->b2); @@ -1934,31 +1745,31 @@ RXY_t *rxfInstr = (RXY_t *) &instr[0]; int disp = (rxfInstr->dh << 12) + rxfInstr->dl; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\tR%d,%d(R%d,R%d)\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\tR%d,%d(R%d,R%d)\n", pc, op->mnemonic, rxfInstr->r1, disp, rxfInstr->x2, rxfInstr->b2); } break; case IFMT_S : - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 2) == -1) + if (x->d390_get_bytes(x->d390_data, &instr[2], 2) == -1) return (-1); if (buf != NULL) { S_t *sInstr = (S_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\t%u(R%d)\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\t%u(R%d)\n", pc, op->mnemonic, sInstr->d2, sInstr->b2); } break; case IFMT_SI : - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 2) == -1) + if (x->d390_get_bytes(x->d390_data, &instr[2], 2) == -1) return (-1); if (buf != NULL) { SI_t *siInstr = (SI_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\t%u(R%d),0x%x\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\t%u(R%d),0x%x\n", pc, op->mnemonic, siInstr->d1, siInstr->b1, siInstr->i2); } @@ -1968,32 +1779,32 @@ SIY_t *siyInstr = (SIY_t *) &instr[0]; int disp = (siyInstr->dh << 12) + siyInstr->dl; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\t%d(R%d),0x%x\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\t%d(R%d),0x%x\n", pc, op->mnemonic, disp, siyInstr->b1, siyInstr->i2); } break; case IFMT_SS1 : - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 4) == -1) + if (x->d390_get_bytes(x->d390_data, &instr[2], 4) == -1) return (-1); if (buf != NULL) { SS1_t *ss1Instr = (SS1_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\t%u(%d,R%d),%u(R%d)\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\t%u(%d,R%d),%u(R%d)\n", pc, op->mnemonic, ss1Instr->d1, ss1Instr->l+1, ss1Instr->b1, ss1Instr->d2, ss1Instr->b2); } break; case IFMT_SS2 : - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 4) == -1) + if (x->d390_get_bytes(x->d390_data, &instr[2], 4) == -1) return (-1); if (buf != NULL) { SS2_t *ss2Instr = (SS2_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\t%u(%d,R%d),%u(%d,R%d)\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\t%u(%d,R%d),%u(%d,R%d)\n", pc, op->mnemonic, ss2Instr->d1, ss2Instr->l1+1, ss2Instr->b1, ss2Instr->d2, ss2Instr->l2+1, @@ -2001,65 +1812,65 @@ } break; case IFMT_SS3 : - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 4) == -1) + if (x->d390_get_bytes(x->d390_data, &instr[2], 4) == -1) return (-1); if (buf != NULL) { SS3_t *ss3Instr = (SS3_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\t%u(%d,R%d),%u(R%d),0x%x\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\t%u(%d,R%d),%u(R%d),0x%x\n", pc, op->mnemonic, ss3Instr->d1, ss3Instr->l1+1, ss3Instr->b1, ss3Instr->d2, ss3Instr->b2, ss3Instr->i3); } break; case IFMT_SS4 : - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 4) == -1) + if (x->d390_get_bytes(x->d390_data, &instr[2], 4) == -1) return (-1); if (buf != NULL) { SS4_t *ss4Instr = (SS4_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\tR%d,R%d,%u(R%d),%u(R%d)\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\tR%d,R%d,%u(R%d),%u(R%d)\n", pc, op->mnemonic, ss4Instr->r1, ss4Instr->r3, ss4Instr->d1, ss4Instr->b1, ss4Instr->d2, ss4Instr->b2); } break; case IFMT_SS5 : - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 4) == -1) + if (x->d390_get_bytes(x->d390_data, &instr[2], 4) == -1) return (-1); if (buf != NULL) { SS5_t *ss5Instr = (SS5_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\tR%d,R%d,%u(R%d),%u(R%d)\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\tR%d,R%d,%u(R%d),%u(R%d)\n", pc, op->mnemonic, ss5Instr->r1, ss5Instr->r3, ss5Instr->d2, ss5Instr->b2, ss5Instr->d4, ss5Instr->b4); } break; case IFMT_SSE : - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 4) == -1) + if (x->d390_get_bytes(x->d390_data, &instr[2], 4) == -1) return (-1); if (buf != NULL) { SSE_t *sseInstr = (SSE_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\t%u(R%d),%u(R%d)\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\t%u(R%d),%u(R%d)\n", pc, op->mnemonic, sseInstr->d1, sseInstr->b1, sseInstr->d2, sseInstr->b2); } break; case IFMT_SSF : - if (x->d390x_get_bytes(x->d390x_data, &instr[2], 4) == -1) + if (x->d390_get_bytes(x->d390_data, &instr[2], 4) == -1) return (-1); if (buf != NULL) { SSF_t *ssfInstr = (SSF_t *) &instr[0]; - x->d390x_sprintf_func(buf, buflen, "%p\t%s\tR%d,%u(R%d),%u(R%d)\n", + x->d390_sprintf_func(buf, buflen, "%p\t%s\tR%d,%u(R%d),%u(R%d)\n", pc, op->mnemonic, ssfInstr->r3, ssfInstr->d1, ssfInstr->b1, ssfInstr->d2, ssfInstr->b2);
--- a/usr/src/common/dis/s390/dis_tables.h Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/common/dis/s390/dis_tables.h Thu Oct 08 12:44:34 2009 -0400 @@ -46,23 +46,355 @@ #include <sys/inttypes.h> #include <sys/param.h> +#define IFMT_E 0 +#define IFMT_I 1 +#define IFMT_RI1 2 +#define IFMT_RI2 3 +#define IFMT_RIE1 4 +#define IFMT_RIE2 5 +#define IFMT_RIE3 6 +#define IFMT_RIL1 7 +#define IFMT_RIL2 8 +#define IFMT_RR 9 +#define IFMT_RRE 10 +#define IFMT_RRF1 11 +#define IFMT_RRF2 12 +#define IFMT_RRF3 13 +#define IFMT_RRR 14 +#define IFMT_RS1 15 +#define IFMT_RS2 16 +#define IFMT_RSI 17 +#define IFMT_RSL 18 +#define IFMT_RSY1 19 +#define IFMT_RSY2 20 +#define IFMT_RX 21 +#define IFMT_RXE 22 +#define IFMT_RXF 23 +#define IFMT_RXY 24 +#define IFMT_S 25 +#define IFMT_SI 26 +#define IFMT_SIY 27 +#define IFMT_SS1 28 +#define IFMT_SS2 29 +#define IFMT_SS3 30 +#define IFMT_SS4 31 +#define IFMT_SS5 32 +#define IFMT_SSE 33 +#define IFMT_SSF 34 + +#define IFMT_PCREL 0x80 /* Instruction has PC relative operand */ + +typedef struct _E_t { + uint16_t opcode; +} __attribute__ ((packed)) E_t; + +typedef struct _I_t { + uint8_t opcode; + uint8_t i1; +} __attribute__ ((packed)) I_t; + +typedef struct _RI1_t { + uint8_t op1; + uint8_t r1 : 4; + uint8_t op2 : 4; + int16_t i2; +} __attribute__ ((packed)) RI1_t ; + +typedef struct _RI2_t { + uint8_t op1; + uint8_t m1 : 4; + uint8_t op2 : 4; + int16_t i2; +} __attribute__ ((packed)) RI2_t; + +typedef struct _RIE1_t { + uint8_t op1; + uint8_t r1 : 4; + uint8_t r3 : 4; + int16_t i2; + uint8_t xxx; + uint8_t op2; +} __attribute__ ((packed)) RIE1_t; + +typedef struct _RIE2_t { + uint8_t op1; + uint8_t r1 : 4; + uint8_t r2 : 4; + int16_t i4; + uint8_t m3 : 4; + uint8_t xx : 4; + uint8_t op2; +} __attribute__ ((packed)) RIE2_t; + +typedef struct _RIE3_t { + uint8_t op1; + uint8_t r1 : 4; + uint8_t r2 : 4; + int16_t i3; + int16_t i4; + int16_t i5; + uint8_t op2; +} __attribute__ ((packed)) RIE3_t; + +typedef struct _RIL1_t { + uint8_t op1; + uint8_t r1 : 4; + uint8_t op2 : 4; + int32_t i2; +} __attribute__ ((packed)) RIL1_t; + +typedef struct _RIL2_t { + uint8_t op1; + uint8_t m1 : 4; + uint8_t op2 : 4; + int32_t i2; +} __attribute__ ((packed)) RIL2_t; + +typedef struct _RR_t { + uint8_t opcode; + uint8_t r1 : 4; + uint8_t r2 : 4; +} __attribute__ ((packed)) RR_t; + +typedef struct _RRE_t { + uint16_t opcode; + uint8_t xxx; + uint8_t r1 : 4; + uint8_t r2 : 4; +} __attribute__ ((packed)) RRE_t; + +typedef struct _RRF1_t { + uint16_t opcode; + uint8_t r1 : 4; + uint8_t xx : 4; + uint8_t r3 : 4; + uint8_t r2 : 4; +} __attribute__ ((packed)) RRF1_t; + +typedef struct _RRF2_t { + uint16_t opcode; + uint8_t m3 : 4; + uint8_t xx : 4; + uint8_t r1 : 4; + uint8_t r2 : 4; +} __attribute__ ((packed)) RRF2_t; + +typedef struct _RRF3_t { + uint16_t opcode; + uint8_t r3 : 4; + uint8_t m4 : 4; + uint8_t r1 : 4; + uint8_t r2 : 4; +} __attribute__ ((packed)) RRF3_t; + +typedef struct _RRR_t { + uint16_t opcode; + uint8_t r3 : 4; + uint8_t xx : 4; + uint8_t r1 : 4; + uint8_t r2 : 4; +} __attribute__ ((packed)) RRR_t; + +typedef struct _RS1_t { + uint8_t opcode; + uint8_t r1 : 4; + uint8_t r3 : 4; + uint16_t b2 : 4; + uint16_t d2 : 12; +} __attribute__ ((packed)) RS1_t; + +typedef struct _RS2_t { + uint8_t opcode; + uint8_t r1 : 4; + uint8_t m3 : 4; + uint16_t b2 : 4; + uint16_t d2 : 12; +} __attribute__ ((packed)) RS2_t; + +typedef struct _RSI_t { + uint8_t opcode; + uint8_t r1 : 4; + uint8_t r3 : 4; + int16_t i2; +} __attribute__ ((packed)) RSI_t; + +typedef struct _RSL_t { + uint8_t op1; + uint8_t l1 : 4; + uint8_t xx : 4; + uint16_t b1 : 4; + uint16_t d1 : 12; + uint8_t zz; + uint8_t op2; +} __attribute__ ((packed)) RSL_t; + +typedef struct _RSY1_t { + uint8_t op1; + uint8_t r1 : 4; + uint8_t r3 : 4; + uint16_t b2 : 4; + uint16_t dl : 12; + uint8_t dh; + uint8_t op2; +} __attribute__ ((packed)) RSY1_t; + +typedef struct _RSY2_t { + uint8_t op1; + uint8_t r1 : 4; + uint8_t m3 : 4; + uint16_t b2 : 4; + uint16_t dl : 12; + uint8_t dh; + uint8_t op2; +} __attribute__ ((packed)) RSY2_t; + +typedef struct _RX_t { + uint8_t opcode; + uint8_t r1 : 4; + uint8_t x2 : 4; + uint16_t b2 : 4; + uint16_t d2 : 12; +} __attribute__ ((packed)) RX_t; + +typedef struct _RXE_t { + uint8_t op1; + uint8_t r1 : 4; + uint8_t x2 : 4; + uint16_t b2 : 4; + uint16_t d2 : 12; + uint8_t xx; + uint8_t op2; +} __attribute__ ((packed)) RXE_t; + +typedef struct _RXF_t { + uint8_t op1; + uint8_t r3 : 4; + uint8_t x2 : 4; + uint16_t b2 : 4; + uint16_t d2 : 12; + uint8_t r1 : 4; + uint8_t xx : 4; + uint8_t op2; +} __attribute__ ((packed)) RXF_t; + +typedef struct _RXY_t { + uint8_t op1; + uint8_t r1 : 4; + uint8_t x2 : 4; + uint16_t b2 : 4; + uint16_t dl : 12; + uint8_t dh; + uint8_t op2; +} __attribute__ ((packed)) RXY_t; + +typedef struct _S_t { + uint16_t opcode; + uint16_t b2 : 4; + uint16_t d2 : 12; +} __attribute__ ((packed)) S_t; + +typedef struct _SI_t { + uint8_t opcode; + uint8_t i2; + uint16_t b1 : 4; + uint16_t d1 : 12; +} __attribute__ ((packed)) SI_t; + +typedef struct _SIY_t { + uint8_t opcode; + uint8_t i2; + uint16_t b1 : 4; + uint16_t dl : 12; + uint8_t dh; + uint8_t op2; +} __attribute__ ((packed)) SIY_t; + +typedef struct _SS1_t { + uint8_t opcode; + uint8_t l; + uint16_t b1 : 4; + uint16_t d1 : 12; + uint16_t b2 : 4; + uint16_t d2 : 12; +} __attribute__ ((packed)) SS1_t; + +typedef struct _SS2_t { + uint8_t opcode; + uint8_t l1 : 4; + uint8_t l2 : 4; + uint16_t b1 : 4; + uint16_t d1 : 12; + uint16_t b2 : 4; + uint16_t d2 : 12; +} __attribute__ ((packed)) SS2_t; + +typedef struct _SS3_t { + uint8_t opcode; + uint8_t l1 : 4; + uint8_t i3 : 4; + uint16_t b1 : 4; + uint16_t d1 : 12; + uint16_t b2 : 4; + uint16_t d2 : 12; +} __attribute__ ((packed)) SS3_t; + +typedef struct _SS4_t { + uint8_t opcode; + uint8_t r1 : 4; + uint8_t r3 : 4; + uint16_t b1 : 4; + uint16_t d1 : 12; + uint16_t b2 : 4; + uint16_t d2 : 12; +} __attribute__ ((packed)) SS4_t; + +typedef struct _SS5_t { + uint8_t opcode; + uint8_t r1 : 4; + uint8_t r3 : 4; + uint16_t b2 : 4; + uint16_t d2 : 12; + uint16_t b4 : 4; + uint16_t d4 : 12; +} __attribute__ ((packed)) SS5_t; + +typedef struct _SSE_t { + uint16_t opcode; + uint16_t b1 : 4; + uint16_t d1 : 12; + uint16_t b2 : 4; + uint16_t d2 : 12; +} __attribute__ ((packed)) SSE_t; + +typedef struct _SSF_t { + uint8_t op1; + uint8_t r3 : 4; + uint8_t op2 : 4; + uint16_t b1 : 4; + uint16_t d1 : 12; + uint16_t b2 : 4; + uint16_t d2 : 12; +} __attribute__ ((packed)) SSF_t; + #define OPLEN 256 -#define PFIXLEN 8 -#define NCPS 12 /* number of chars per symbol */ /* * data structures that must be provided to dtrace_dis390x() */ -typedef struct dis390x { - int d390x_flags; - int (*d390x_check_func)(void *); - int (*d390x_get_bytes)(void *, uchar_t *, int); - int (*d390x_sym_lookup)(void *, uint64_t, char *, size_t); - int (*d390x_sprintf_func)(char *, size_t, const char *, ...); - void *d390x_data; -} dis390x_t; +typedef struct dis390 { + int (*d390_check_func)(void *); + int (*d390_get_bytes)(void *, uchar_t *, int); + int (*d390_sym_lookup)(void *, uint64_t, char *, size_t); + int (*d390_sprintf_func)(char *, size_t, const char *, ...); + void *d390_data; + int d390_flags; + uint_t d390_len; /* instruction length */ + int d390_fmt; /* instruction format */ + char d390_mnem[OPLEN]; +} dis390_t; -extern int dtrace_dis390x(dis390x_t *, uint64_t, char *, size_t); +extern int dtrace_dis390(dis390_t *, uint64_t, char *, size_t); +extern int dtrace_getfmtlen(char *, uint8_t *); #define DIS_F_OCTAL 0x1 /* Print all numbers in octal */ #define DIS_F_NOIMMSYM 0x2 /* Don't print symbols for immediates (.o) */
--- a/usr/src/common/dis/s390x/dis_tables.c Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/common/dis/s390x/dis_tables.c Thu Oct 08 12:44:34 2009 -0400 @@ -1600,7 +1600,7 @@ fmt; opCode_t *op; - size = x->d390x_get_bytes(x->d390x_data, &instr[0], 2); + x->d390x_len = size = x->d390x_get_bytes(x->d390x_data, &instr[0], 2); if (size == -1) return (-1);
--- a/usr/src/common/dis/s390x/dis_tables.h Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/common/dis/s390x/dis_tables.h Thu Oct 08 12:44:34 2009 -0400 @@ -48,19 +48,19 @@ #include <sys/param.h> #define OPLEN 256 -#define PFIXLEN 8 -#define NCPS 12 /* number of chars per symbol */ /* * data structures that must be provided to dtrace_dis390x() */ typedef struct dis390x { int d390x_flags; + uint_t d390x_len; /* instruction length */ int (*d390x_check_func)(void *); int (*d390x_get_bytes)(void *, uchar_t *, int); int (*d390x_sym_lookup)(void *, uint64_t, char *, size_t); int (*d390x_sprintf_func)(char *, size_t, const char *, ...); void *d390x_data; + char d390x_mnem[OPLEN]; } dis390x_t; extern int dtrace_dis390x(dis390x_t *, uint64_t, char *, size_t);
--- a/usr/src/lib/libc/inc/thr_uberdata.h Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/lib/libc/inc/thr_uberdata.h Thu Oct 08 12:44:34 2009 -0400 @@ -538,6 +538,8 @@ uint32_t ul_drestore; /* dtrace: restore %g0, %g0, %g0 */ uint32_t ul_dftret; /* dtrace: return probe fasttrap */ uint32_t ul_dreturn; /* dtrace: return %o0 */ +#elif defined(__s390) + uint8_t ul_dinstr[24]; /* scratch space for dtrace */ #endif struct ulwp *ul_self; /* pointer to self */ #if defined(__i386)
--- a/usr/src/lib/libdisasm/Makefile.com Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/lib/libdisasm/Makefile.com Thu Oct 08 12:44:34 2009 -0400 @@ -124,7 +124,7 @@ # CPPFLAGS_dis_i386 = -I$(SRC)/common/dis/i386 -DDIS_TEXT CPPFLAGS_dis_sparc = -CPPFLAGS_dis_s390 = -I$(SRC)/common/dis/s390x +CPPFLAGS_dis_s390 = -I$(SRC)/common/dis/s390 CPPFLAGS += $(CPPFLAGS_dis_$(MACH)) CFLAGS_standalone = $(STAND_FLAGS_32)
--- a/usr/src/lib/libdisasm/Makefile.targ Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/lib/libdisasm/Makefile.targ Thu Oct 08 12:44:34 2009 -0400 @@ -92,6 +92,6 @@ $(INS.file) # install rule for x86 common source -objs/%.o pics/%.o: $(SRC)/common/dis/i386/%.c +objs/%.o pics/%.o: $(SRC)/common/dis/$(MACH)/%.c $(COMPILE.c) -o $@ $< $(POST_PROCESS_O)
--- a/usr/src/lib/libdisasm/s390/Makefile Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/lib/libdisasm/s390/Makefile Thu Oct 08 12:44:34 2009 -0400 @@ -37,8 +37,3 @@ include ../Makefile.targ C99MODE = $(C99_ENABLE) - -# install rule for s390 common source -objs/dis_tables.o pics/dis_tables.o: $(SRC)/common/dis/s390/dis_tables.c - $(COMPILE.c) -o $@ $(SRC)/common/dis/s390/dis_tables.c - $(POST_PROCESS_O)
--- a/usr/src/lib/libdisasm/s390/dis_s390.c Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/lib/libdisasm/s390/dis_s390.c Thu Oct 08 12:44:34 2009 -0400 @@ -83,7 +83,7 @@ int dh_flags; dis_lookup_f dh_lookup; dis_read_f dh_read; - dis390x_t dh_dis; + dis390_t dh_dis; uint64_t dh_addr; uint64_t dh_end; }; @@ -217,10 +217,10 @@ dhp->dh_flags = flags; dhp->dh_data = data; - dhp->dh_dis.d390x_sprintf_func = snprintf; - dhp->dh_dis.d390x_get_bytes = get_bytes; - dhp->dh_dis.d390x_sym_lookup = do_lookup; - dhp->dh_dis.d390x_check_func = check_func; + dhp->dh_dis.d390_sprintf_func = snprintf; + dhp->dh_dis.d390_get_bytes = get_bytes; + dhp->dh_dis.d390_sym_lookup = do_lookup; + dhp->dh_dis.d390_check_func = check_func; return (dhp); } @@ -375,7 +375,7 @@ int dis_disassemble(dis_handle_t *dhp, uint64_t addr, char *buf, size_t buflen) { - return(dtrace_dis390x(&dhp->dh_dis, addr, buf, buflen)); + return(dtrace_dis390(&dhp->dh_dis, addr, buf, buflen)); } /*========================= End of Function ========================*/
--- a/usr/src/lib/libdisasm/s390x/Makefile Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/lib/libdisasm/s390x/Makefile Thu Oct 08 12:44:34 2009 -0400 @@ -18,13 +18,11 @@ # # CDDL HEADER END # -# Copyright 2008 Sine Nomine Associates. All rights reserved. +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# + ISASRCDIR=../$(MACH)/ include ../Makefile.com @@ -38,8 +36,3 @@ include ../Makefile.targ C99MODE = $(C99_ENABLE) - -# install rule for s390x common source -objs/dis_tables.o pics/dis_tables.o: $(SRC)/common/dis/s390x/dis_tables.c - $(COMPILE.c) -o $@ $(SRC)/common/dis/s390x/dis_tables.c - $(POST_PROCESS_O)
--- a/usr/src/lib/libdtrace/Makefile Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/lib/libdtrace/Makefile Thu Oct 08 12:44:34 2009 -0400 @@ -59,5 +59,5 @@ # Cross-reference customization: build the cross-reference only over the # source directories, and ignore Makefiles and machine-generated source. # -XRDIRS = common i386 sparc sparcv9 +XRDIRS = common i386 sparc sparcv9 s390 s390x XRDEL = dt_lex.c dt_grammar.c Makefile*
--- a/usr/src/lib/libdtrace/s390/Makefile Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/lib/libdtrace/s390/Makefile Thu Oct 08 12:44:34 2009 -0400 @@ -28,12 +28,23 @@ # ASFLAGS += -D_ASM -MAPDIR = ../spec/s390x +MACHOBJS = dis_tables.o + include ../Makefile.com + +SRCS += $(SRC)/common/dis/s390/dis_tables.c +CPPFLAGS += -I$(SRC)/common/dis/s390 + LDLIBS += -lgcc_s SRCS += dt_asmsubr.s OBJECTS += dt_asmsubr.o +LINTFLAGS += -erroff=E_BAD_PTR_CAST_ALIGN + +pics/%.o: $(SRC)/common/dis/s390/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + install yydebug: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) \ $(ROOTDLIBS) $(ROOTDOBJS)
--- a/usr/src/lib/libdtrace/s390/dt_asmsubr.s Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/lib/libdtrace/s390/dt_asmsubr.s Thu Oct 08 12:44:34 2009 -0400 @@ -42,7 +42,6 @@ #else ENTRY(dtrace_probe) - lhi %r2,0 svc ST_DTRACE_PROBE br %r14 SET_SIZE(dtrace_probe)
--- a/usr/src/lib/libdtrace/s390/dt_isadep.c Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/lib/libdtrace/s390/dt_isadep.c Thu Oct 08 12:44:34 2009 -0400 @@ -1,62 +1,127 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ +/*------------------------------------------------------------------*/ +/* */ +/* Name - dt_isadep. */ +/* */ +/* Function - ISA dependent code for System z (64-bit) */ +/* */ +/* Name - Neale Ferguson */ +/* */ +/* Date - October, 2009 */ +/* */ +/*------------------------------------------------------------------*/ + +/*------------------------------------------------------------------*/ +/* L I C E N S E */ +/*------------------------------------------------------------------*/ -#pragma ident "@(#)dt_isadep.c 1.6 05/06/08 SMI" +/*==================================================================*/ +/* */ +/* CDDL HEADER START */ +/* */ +/* The contents of this file are subject to the terms of the */ +/* Common Development and Distribution License (the "License"). */ +/* You may not use this file except in compliance the the License. */ +/* */ +/* You can obtain a copy of the license at: */ +/* - usr/src/OPENSOLARIS.LICENSE, or, */ +/* - http://www.opensolaris.org/os/licensing. */ +/* See the License for the specific language governing permissions */ +/* and limitations under the License. */ +/* */ +/* When distributing Covered Code, include this CDDL HEADER in each */ +/* file and include the License file at usr/src/OPENSOLARIS.LICENSE.*/ +/* If applicable, add the following below this CDDL HEADER, with */ +/* the fields enclosed by brackets "[]" replaced with your own */ +/* identifying information: */ +/* Portions Copyright [yyyy] [name of copyright owner] */ +/* */ +/* CDDL HEADER END */ +/* */ +/* Copyright 2008 Sine Nomine Associates. */ +/* All rights reserved. */ +/* Use is subject to license terms. */ +/* */ +/* Copyright 2005 Sun Microsystems, Inc. All rights reserved. */ +/* Use is subject to license terms. */ +/* */ +/*==================================================================*/ + +/*------------------------------------------------------------------*/ +/* D e f i n e s */ +/*------------------------------------------------------------------*/ + +#define BUCR 0x07f0 /* Branch unconditional register */ + +/*========================= End of Defines =========================*/ + +/*------------------------------------------------------------------*/ +/* I n c l u d e s */ +/*------------------------------------------------------------------*/ #include <stdlib.h> #include <assert.h> #include <errno.h> #include <string.h> #include <libgen.h> - +#include <dis_tables.h> #include <dt_impl.h> #include <dt_pid.h> -#define OP(x) ((x) >> 30) -#define OP2(x) (((x) >> 22) & 0x07) -#define COND(x) (((x) >> 25) & 0x0f) -#define A(x) (((x) >> 29) & 0x01) +/*========================= End of Includes ========================*/ + +/*------------------------------------------------------------------*/ +/* T y p e d e f s */ +/*------------------------------------------------------------------*/ + + +/*========================= End of Typedefs ========================*/ + +/*------------------------------------------------------------------*/ +/* E x t e r n a l R e f e r e n c e s */ +/*------------------------------------------------------------------*/ + +typedef struct dtrace_dis { + uchar_t *instr; + dtrace_hdl_t *dtp; + pid_t pid; + uintptr_t addr; +} dtrace_dis_t; + +/*=================== End of External References ===================*/ -#define OP_BRANCH 0 +/*------------------------------------------------------------------*/ +/* P r o t o t y p e s */ +/*------------------------------------------------------------------*/ + +static int dt_getbyte(void *, uchar_t *, int); +static int dt_instr_size(uchar_t *, dtrace_hdl_t *, pid_t, + uintptr_t, char); + +/*========================= End of Prototypes ======================*/ -#define OP2_BPcc 0x1 -#define OP2_Bicc 0x2 -#define OP2_BPr 0x3 -#define OP2_FBPfcc 0x5 -#define OP2_FBfcc 0x6 +/*------------------------------------------------------------------*/ +/* G l o b a l V a r i a b l e s */ +/*------------------------------------------------------------------*/ + +/*====================== End of Global Variables ===================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - dt_pid_create_entry_probe. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ /*ARGSUSED*/ int dt_pid_create_entry_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, fasttrap_probe_spec_t *ftp, const GElf_Sym *symp) { - ftp->ftps_type = DTFTP_ENTRY; - ftp->ftps_pc = (uintptr_t)symp->st_value; - ftp->ftps_size = (size_t)symp->st_size; - ftp->ftps_noffs = 1; + ftp->ftps_type = DTFTP_ENTRY; + ftp->ftps_pc = (uintptr_t)symp->st_value; + ftp->ftps_size = (size_t)symp->st_size; + ftp->ftps_noffs = 1; ftp->ftps_offs[0] = 0; if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { @@ -68,14 +133,25 @@ return (1); } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - dt_pid_create_return_probe. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + int dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret) { - - uint32_t *text; - int i; + uint8_t *text; + int i, size; int srdepth = 0; + pid_t pid = Pstatus(P)->pr_pid; + char dmodel = Pstatus(P)->pr_dmodel; if ((text = malloc(symp->st_size + 4)) == NULL) { dt_dprintf("mr sparkle: malloc() failed\n"); @@ -92,172 +168,25 @@ * Leave a dummy instruction in the last slot to simplify edge * conditions. */ - text[symp->st_size / 4] = 0; + text[symp->st_size] = 0; - ftp->ftps_type = DTFTP_RETURN; - ftp->ftps_pc = symp->st_value; - ftp->ftps_size = symp->st_size; + ftp->ftps_type = DTFTP_RETURN; + ftp->ftps_pc = symp->st_value; + ftp->ftps_size = symp->st_size; ftp->ftps_noffs = 0; - for (i = 0; i < symp->st_size / 4; i++) { - /* - * If we encounter an existing tracepoint, query the - * kernel to find out the instruction that was - * replaced at this spot. - */ - while (text[i] == FASTTRAP_INSTR) { - fasttrap_instr_query_t instr; - - instr.ftiq_pid = Pstatus(P)->pr_pid; - instr.ftiq_pc = symp->st_value + i * 4; - - if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_GETINSTR, - &instr) != 0) { - - if (errno == ESRCH || errno == ENOENT) { - if (Pread(P, &text[i], 4, - instr.ftiq_pc) != 4) { - dt_dprintf("mr sparkle: " - "Pread() failed\n"); - free(text); - return (DT_PROC_ERR); - } - continue; - } - - free(text); - dt_dprintf("mr sparkle: getinstr query " - "failed: %s\n", strerror(errno)); - return (DT_PROC_ERR); - } - - text[i] = instr.ftiq_instr; - break; - } - - /* save */ - if ((text[i] & 0xc1f80000) == 0x81e00000) { - srdepth++; - continue; - } - - /* restore */ - if ((text[i] & 0xc1f80000) == 0x81e80000) { - srdepth--; - continue; - } - - if (srdepth > 0) { - /* ret */ - if (text[i] == 0x81c7e008) - goto is_ret; - - /* return */ - if (text[i] == 0x81cfe008) - goto is_ret; - - /* call or jmpl w/ restore in the slot */ - if (((text[i] & 0xc0000000) == 0x40000000 || - (text[i] & 0xc1f80000) == 0x81c00000) && - (text[i + 1] & 0xc1f80000) == 0x81e80000) - goto is_ret; - - /* call to one of the stret routines */ - if ((text[i] & 0xc0000000) == 0x40000000) { - int32_t disp = text[i] << 2; - uint64_t dest = ftp->ftps_pc + i * 4 + disp; - - dt_dprintf("dest = %llx\n", (u_longlong_t)dest); - - if (dest == stret[0] || dest == stret[1] || - dest == stret[2] || dest == stret[3]) - goto is_ret; - } - } else { - /* external call */ - if ((text[i] & 0xc0000000) == 0x40000000) { - int32_t dst = text[i] << 2; + for (i = 0; i < symp->st_size; i += size) { + uint16_t *br = (uint16_t *) text; - dst += i * 4; - - if ((uintptr_t)dst >= (uintptr_t)symp->st_size) - goto is_ret; - } - - /* jmpl into %g0 -- this includes the retl pseudo op */ - if ((text[i] & 0xfff80000) == 0x81c00000) - goto is_ret; - - /* external branch -- possible return site */ - if (OP(text[i]) == OP_BRANCH) { - int32_t dst; - int baa; - - switch (OP2(text[i])) { - case OP2_BPcc: - dst = text[i] & 0x7ffff; - dst <<= 13; - dst >>= 11; - - baa = COND(text[i]) == 8 && A(text[i]); - break; - case OP2_Bicc: - dst = text[i] & 0x3fffff; - dst <<= 10; - dst >>= 8; - - baa = COND(text[i]) == 8 && A(text[i]); - break; - case OP2_BPr: - dst = (((text[i]) >> 6) & 0xc000) | - ((text[i]) & 0x3fff); - dst <<= 16; - dst >>= 14; + size = dt_instr_size(&text[i], dtp, pid, symp->st_value + i, dmodel); + if (size < 0) + break; - baa = 0; - break; - case OP2_FBPfcc: - dst = text[i] & 0x7ffff; - dst <<= 13; - dst >>= 11; - - baa = COND(text[i]) == 8 && A(text[i]); - break; - case OP2_FBfcc: - dst = text[i] & 0x3fffff; - dst <<= 10; - dst >>= 8; - - baa = COND(text[i]) == 8 && A(text[i]); - break; - default: - continue; - } - - dst += i * 4; + if ((*br & 0xfff0) != BUCR) + continue; - /* - * Interpret branches outside of the function's - * bounds as potential return sites. If the - * branch is a ba,a don't skip the instruction - * in the delay slot. - */ - if ((uintptr_t)dst >= - (uintptr_t)symp->st_size) { - if (baa) - goto is_ret_baa; - else - goto is_ret; - } - } - } - - continue; -is_ret: - i++; -is_ret_baa: - dt_dprintf("return at offset %x\n", i * 4); - ftp->ftps_offs[ftp->ftps_noffs++] = i * 4; + dt_dprintf("return at offset %x\n", i); + ftp->ftps_offs[ftp->ftps_noffs++] = i; } free(text); @@ -273,6 +202,16 @@ return (ftp->ftps_noffs); } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - dt_pid_create_offset_probe. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + /*ARGSUSED*/ int dt_pid_create_offset_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, @@ -281,10 +220,10 @@ if (off & 0x3) return (DT_PROC_ALIGN); - ftp->ftps_type = DTFTP_OFFSETS; - ftp->ftps_pc = (uintptr_t)symp->st_value; - ftp->ftps_size = (size_t)symp->st_size; - ftp->ftps_noffs = 1; + ftp->ftps_type = DTFTP_OFFSETS; + ftp->ftps_pc = (uintptr_t)symp->st_value; + ftp->ftps_size = (size_t)symp->st_size; + ftp->ftps_noffs = 1; ftp->ftps_offs[0] = off; if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { @@ -296,6 +235,16 @@ return (1); } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - dt_pid_create_glob_offset_probes. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + /*ARGSUSED*/ int dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp, @@ -303,9 +252,9 @@ { ulong_t i; - ftp->ftps_type = DTFTP_OFFSETS; - ftp->ftps_pc = (uintptr_t)symp->st_value; - ftp->ftps_size = (size_t)symp->st_size; + ftp->ftps_type = DTFTP_OFFSETS; + ftp->ftps_pc = (uintptr_t)symp->st_value; + ftp->ftps_size = (size_t)symp->st_size; ftp->ftps_noffs = 0; /* @@ -336,3 +285,88 @@ return (ftp->ftps_noffs); } + +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - dt_getbyte. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + +static int +dt_getbyte(void *data, uchar_t *inst, int len) +{ + dtrace_dis_t *dis = data; + uint16_t ret = *(uint16_t *) dis->instr; + + if (ret == FASTTRAP_INSTR) { + fasttrap_instr_query_t instr; + + instr.ftiq_pid = dis->pid; + instr.ftiq_pc = dis->addr; + + /* + * If we hit a byte that looks like the fasttrap provider's + * trap instruction (which doubles as the breakpoint + * instruction for debuggers) we need to query the kernel + * for the real value. This may just be part of an immediate + * value so there's no need to return an error if the + * kernel doesn't know about this address. + */ + if (ioctl(dis->dtp->dt_ftfd, FASTTRAPIOC_GETINSTR, &instr) == 0) + ret = instr.ftiq_instr; + } + + dis->addr += len; + dis->instr += len; + + return ((int)ret); +} + +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - dt_instr_size. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + +static int +dt_instr_size(uchar_t *instr, dtrace_hdl_t *dtp, pid_t pid, uintptr_t addr, + char dmodel) +{ + dtrace_dis_t data; + dis390_t s390dis; + uint_t cpu_mode; + uint16_t *opcode = (uint16_t *) instr; + + data.instr = instr; + data.dtp = dtp; + data.pid = pid; + data.addr = addr; + + s390dis.d390_data = &data; + s390dis.d390_get_bytes = dt_getbyte; + s390dis.d390_check_func = NULL; + + if (dtrace_dis390(&s390dis, addr, NULL, 0) != 0) + return (-1); + + /* + * If the instruction was a single-byte breakpoint, there may be + * another debugger attached to this process. The original instruction + * can't be recovered so this must fail. + */ + if (s390dis.d390_len == 2 && *opcode == FASTTRAP_INSTR) + return (-1); + + return (s390dis.d390_len); + +} + +/*========================= End of Function ========================*/
--- a/usr/src/lib/libdtrace/s390/regs.d Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/lib/libdtrace/s390/regs.d Thu Oct 08 12:44:34 2009 -0400 @@ -20,101 +20,120 @@ * CDDL HEADER END */ /* + * Copyright 2009 Sine Nomine Associates. All rights reserved. + * Use is subject to license terms. + */ +/* * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "@(#)regs.d 1.2 05/06/08 SMI" - -inline int R_G0 = 0; +inline int R_PSWM = 0; +#pragma D binding "1.0" R_PSWM +inline int R_PSWA = 1; +#pragma D binding "1.0" R_PSWA +inline int R_PC = 1; +#pragma D binding "1.0" R_PC +inline int R_G0 = 2; #pragma D binding "1.0" R_G0 -inline int R_G1 = 1; +inline int R_G1 = 3; #pragma D binding "1.0" R_G1 -inline int R_G2 = 2; +inline int R_G2 = 4; #pragma D binding "1.0" R_G2 -inline int R_G3 = 3; +inline int R_G3 = 5; #pragma D binding "1.0" R_G3 -inline int R_G4 = 4; +inline int R_G4 = 6; #pragma D binding "1.0" R_G4 -inline int R_G5 = 5; +inline int R_G5 = 7; #pragma D binding "1.0" R_G5 -inline int R_G6 = 6; +inline int R_G6 = 8; #pragma D binding "1.0" R_G6 -inline int R_G7 = 7; +inline int R_G7 = 9; #pragma D binding "1.0" R_G7 +inline int R_G8 = 10; +#pragma D binding "1.0" R_G8 +inline int R_G9 = 11; +#pragma D binding "1.0" R_G9 +inline int R_G10 = 12; +#pragma D binding "1.0" R_G10 +inline int R_G11 = 13; +#pragma D binding "1.0" R_G11 +inline int R_G12 = 14; +#pragma D binding "1.0" R_G12 +inline int R_G13 = 15; +#pragma D binding "1.0" R_G13 +inline int R_G14 = 16; +#pragma D binding "1.0" R_G14 +inline int R_G15 = 17; +#pragma D binding "1.0" R_G15 -inline int R_O0 = 8; -#pragma D binding "1.0" R_O0 -inline int R_O1 = 9; -#pragma D binding "1.0" R_O1 -inline int R_O2 = 10; -#pragma D binding "1.0" R_O2 -inline int R_O3 = 11; -#pragma D binding "1.0" R_O3 -inline int R_O4 = 12; -#pragma D binding "1.0" R_O4 -inline int R_O5 = 13; -#pragma D binding "1.0" R_O5 -inline int R_O6 = 14; -#pragma D binding "1.0" R_O6 -inline int R_O7 = 15; -#pragma D binding "1.0" R_O7 +inline int R_ILC = 18; +#pragma D binding "1.0" R_ILC -inline int R_L0 = 16; -#pragma D binding "1.0" R_L0 -inline int R_L1 = 17; -#pragma D binding "1.0" R_L1 -inline int R_L2 = 18; -#pragma D binding "1.0" R_L2 -inline int R_L3 = 19; -#pragma D binding "1.0" R_L3 -inline int R_L4 = 20; -#pragma D binding "1.0" R_L4 -inline int R_L5 = 21; -#pragma D binding "1.0" R_L5 -inline int R_L6 = 22; -#pragma D binding "1.0" R_L6 -inline int R_L7 = 23; -#pragma D binding "1.0" R_L7 +inline int R_A0 = 19; +#pragma D binding "1.0" R_A0 +inline int R_A1 = 20; +#pragma D binding "1.0" R_A1 +inline int R_A2 = 21; +#pragma D binding "1.0" R_A2 +inline int R_A3 = 22; +#pragma D binding "1.0" R_A3 +inline int R_A4 = 23; +#pragma D binding "1.0" R_A4 +inline int R_A5 = 24; +#pragma D binding "1.0" R_A5 +inline int R_A6 = 25; +#pragma D binding "1.0" R_A6 +inline int R_A7 = 26; +#pragma D binding "1.0" R_A7 +inline int R_A8 = 27; +#pragma D binding "1.0" R_A8 +inline int R_A9 = 28; +#pragma D binding "1.0" R_A9 +inline int R_A10 = 29; +#pragma D binding "1.0" R_A10 +inline int R_A11 = 30; +#pragma D binding "1.0" R_A11 +inline int R_A12 = 31; +#pragma D binding "1.0" R_A12 +inline int R_A13 = 32; +#pragma D binding "1.0" R_A13 +inline int R_A14 = 33; +#pragma D binding "1.0" R_A14 +inline int R_A15 = 34; +#pragma D binding "1.0" R_A15 -inline int R_I0 = 24; -#pragma D binding "1.0" R_I0 -inline int R_I1 = 25; -#pragma D binding "1.0" R_I1 -inline int R_I2 = 26; -#pragma D binding "1.0" R_I2 -inline int R_I3 = 27; -#pragma D binding "1.0" R_I3 -inline int R_I4 = 28; -#pragma D binding "1.0" R_I4 -inline int R_I5 = 29; -#pragma D binding "1.0" R_I5 -inline int R_I6 = 30; -#pragma D binding "1.0" R_I6 -inline int R_I7 = 31; -#pragma D binding "1.0" R_I7 - -inline int R_CCR = 32; -#pragma D binding "1.0" R_CCR -inline int R_PC = 33; -#pragma D binding "1.0" R_PC -inline int R_nPC = 34; -#pragma D binding "1.0" R_nPC -inline int R_NPC = R_nPC; -#pragma D binding "1.0" R_NPC -inline int R_Y = 35; -#pragma D binding "1.0" R_Y -inline int R_ASI = 36; -#pragma D binding "1.0" R_ASI -inline int R_FPRS = 37; -#pragma D binding "1.0" R_FPRS -inline int R_PS = R_CCR; -#pragma D binding "1.0" R_PS -inline int R_SP = R_O6; -#pragma D binding "1.0" R_SP -inline int R_FP = R_I6; -#pragma D binding "1.0" R_FP -inline int R_R0 = R_O0; -#pragma D binding "1.0" R_R0 -inline int R_R1 = R_O1; -#pragma D binding "1.0" R_R1 +inline int R_FPC = 35; +#pragma D binding "1.0" R_FPC +inline int R_F0 = 36; +#pragma D binding "1.0" R_F0 +inline int R_F1 = 37; +#pragma D binding "1.0" R_F1 +inline int R_F2 = 38; +#pragma D binding "1.0" R_F2 +inline int R_F3 = 39; +#pragma D binding "1.0" R_F3 +inline int R_F4 = 40; +#pragma D binding "1.0" R_F4 +inline int R_F5 = 41; +#pragma D binding "1.0" R_F5 +inline int R_F6 = 42; +#pragma D binding "1.0" R_F6 +inline int R_F7 = 43; +#pragma D binding "1.0" R_F7 +inline int R_F8 = 44; +#pragma D binding "1.0" R_F8 +inline int R_F9 = 45; +#pragma D binding "1.0" R_F9 +inline int R_F10 = 46; +#pragma D binding "1.0" R_F10 +inline int R_F11 = 47; +#pragma D binding "1.0" R_F11 +inline int R_F12 = 48; +#pragma D binding "1.0" R_F12 +inline int R_F13 = 49; +#pragma D binding "1.0" R_F13 +inline int R_F14 = 50; +#pragma D binding "1.0" R_F14 +inline int R_F15 = 51; +#pragma D binding "1.0" R_F15
--- a/usr/src/lib/libdtrace/s390x/Makefile Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/lib/libdtrace/s390x/Makefile Thu Oct 08 12:44:34 2009 -0400 @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -19,22 +18,30 @@ # # CDDL HEADER END # -# Copyright 2008 Sine Nomine Associates. All rights reserved. +# +# Copyright 2009 Sine Nomine Associates. All rights reserved. # Use is subject to license terms. # -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -ASFLAGS += -D_ASM + +ASFLAGS += -D_ASM -K PIC -P -MAPDIR = ../spec/s390x +MACHOBJS = dis_tables.o + include ../Makefile.com include ../../Makefile.lib.64 -SRCS += dt_asmsubr.s -OBJECTS += dt_asmsubr.o -LDFLAGS += -lgcc_s +SRCS += $(SRC)/common/dis/s390/dis_tables.c +CPPFLAGS += -I$(SRC)/common/dis/s390 +CPPFLAGS += -D_ELF64 + +LINTFLAGS64 += -erroff=E_BAD_PTR_CAST_ALIGN + +pics/%.o: $(SRC)/common/dis/s390/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) install yydebug: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64) \ $(ROOTDLIBS) $(ROOTDOBJS64)
--- a/usr/src/lib/libdtrace/s390x/dt_isadep.c Mon Oct 05 12:49:41 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,338 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "@(#)dt_isadep.c 1.6 05/06/08 SMI" - -#include <stdlib.h> -#include <assert.h> -#include <errno.h> -#include <string.h> -#include <libgen.h> - -#include <dt_impl.h> -#include <dt_pid.h> - -#define OP(x) ((x) >> 30) -#define OP2(x) (((x) >> 22) & 0x07) -#define COND(x) (((x) >> 25) & 0x0f) -#define A(x) (((x) >> 29) & 0x01) - -#define OP_BRANCH 0 - -#define OP2_BPcc 0x1 -#define OP2_Bicc 0x2 -#define OP2_BPr 0x3 -#define OP2_FBPfcc 0x5 -#define OP2_FBfcc 0x6 - -/*ARGSUSED*/ -int -dt_pid_create_entry_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, - fasttrap_probe_spec_t *ftp, const GElf_Sym *symp) -{ - ftp->ftps_type = DTFTP_ENTRY; - ftp->ftps_pc = (uintptr_t)symp->st_value; - ftp->ftps_size = (size_t)symp->st_size; - ftp->ftps_noffs = 1; - ftp->ftps_offs[0] = 0; - - if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { - dt_dprintf("fasttrap probe creation ioctl failed: %s\n", - strerror(errno)); - return (dt_set_errno(dtp, errno)); - } - - return (1); -} - -int -dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, - fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret) -{ - - uint32_t *text; - int i; - int srdepth = 0; - - if ((text = malloc(symp->st_size + 4)) == NULL) { - dt_dprintf("mr sparkle: malloc() failed\n"); - return (DT_PROC_ERR); - } - - if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) { - dt_dprintf("mr sparkle: Pread() failed\n"); - free(text); - return (DT_PROC_ERR); - } - - /* - * Leave a dummy instruction in the last slot to simplify edge - * conditions. - */ - text[symp->st_size / 4] = 0; - - ftp->ftps_type = DTFTP_RETURN; - ftp->ftps_pc = symp->st_value; - ftp->ftps_size = symp->st_size; - ftp->ftps_noffs = 0; - - for (i = 0; i < symp->st_size / 4; i++) { - /* - * If we encounter an existing tracepoint, query the - * kernel to find out the instruction that was - * replaced at this spot. - */ - while (text[i] == FASTTRAP_INSTR) { - fasttrap_instr_query_t instr; - - instr.ftiq_pid = Pstatus(P)->pr_pid; - instr.ftiq_pc = symp->st_value + i * 4; - - if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_GETINSTR, - &instr) != 0) { - - if (errno == ESRCH || errno == ENOENT) { - if (Pread(P, &text[i], 4, - instr.ftiq_pc) != 4) { - dt_dprintf("mr sparkle: " - "Pread() failed\n"); - free(text); - return (DT_PROC_ERR); - } - continue; - } - - free(text); - dt_dprintf("mr sparkle: getinstr query " - "failed: %s\n", strerror(errno)); - return (DT_PROC_ERR); - } - - text[i] = instr.ftiq_instr; - break; - } - - /* save */ - if ((text[i] & 0xc1f80000) == 0x81e00000) { - srdepth++; - continue; - } - - /* restore */ - if ((text[i] & 0xc1f80000) == 0x81e80000) { - srdepth--; - continue; - } - - if (srdepth > 0) { - /* ret */ - if (text[i] == 0x81c7e008) - goto is_ret; - - /* return */ - if (text[i] == 0x81cfe008) - goto is_ret; - - /* call or jmpl w/ restore in the slot */ - if (((text[i] & 0xc0000000) == 0x40000000 || - (text[i] & 0xc1f80000) == 0x81c00000) && - (text[i + 1] & 0xc1f80000) == 0x81e80000) - goto is_ret; - - /* call to one of the stret routines */ - if ((text[i] & 0xc0000000) == 0x40000000) { - int32_t disp = text[i] << 2; - uint64_t dest = ftp->ftps_pc + i * 4 + disp; - - dt_dprintf("dest = %llx\n", (u_longlong_t)dest); - - if (dest == stret[0] || dest == stret[1] || - dest == stret[2] || dest == stret[3]) - goto is_ret; - } - } else { - /* external call */ - if ((text[i] & 0xc0000000) == 0x40000000) { - int32_t dst = text[i] << 2; - - dst += i * 4; - - if ((uintptr_t)dst >= (uintptr_t)symp->st_size) - goto is_ret; - } - - /* jmpl into %g0 -- this includes the retl pseudo op */ - if ((text[i] & 0xfff80000) == 0x81c00000) - goto is_ret; - - /* external branch -- possible return site */ - if (OP(text[i]) == OP_BRANCH) { - int32_t dst; - int baa; - - switch (OP2(text[i])) { - case OP2_BPcc: - dst = text[i] & 0x7ffff; - dst <<= 13; - dst >>= 11; - - baa = COND(text[i]) == 8 && A(text[i]); - break; - case OP2_Bicc: - dst = text[i] & 0x3fffff; - dst <<= 10; - dst >>= 8; - - baa = COND(text[i]) == 8 && A(text[i]); - break; - case OP2_BPr: - dst = (((text[i]) >> 6) & 0xc000) | - ((text[i]) & 0x3fff); - dst <<= 16; - dst >>= 14; - - baa = 0; - break; - case OP2_FBPfcc: - dst = text[i] & 0x7ffff; - dst <<= 13; - dst >>= 11; - - baa = COND(text[i]) == 8 && A(text[i]); - break; - case OP2_FBfcc: - dst = text[i] & 0x3fffff; - dst <<= 10; - dst >>= 8; - - baa = COND(text[i]) == 8 && A(text[i]); - break; - default: - continue; - } - - dst += i * 4; - - /* - * Interpret branches outside of the function's - * bounds as potential return sites. If the - * branch is a ba,a don't skip the instruction - * in the delay slot. - */ - if ((uintptr_t)dst >= - (uintptr_t)symp->st_size) { - if (baa) - goto is_ret_baa; - else - goto is_ret; - } - } - } - - continue; -is_ret: - i++; -is_ret_baa: - dt_dprintf("return at offset %x\n", i * 4); - ftp->ftps_offs[ftp->ftps_noffs++] = i * 4; - } - - free(text); - if (ftp->ftps_noffs > 0) { - if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { - dt_dprintf("fasttrap probe creation ioctl failed: %s\n", - strerror(errno)); - return (dt_set_errno(dtp, errno)); - } - } - - - return (ftp->ftps_noffs); -} - -/*ARGSUSED*/ -int -dt_pid_create_offset_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, - fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, ulong_t off) -{ - if (off & 0x3) - return (DT_PROC_ALIGN); - - ftp->ftps_type = DTFTP_OFFSETS; - ftp->ftps_pc = (uintptr_t)symp->st_value; - ftp->ftps_size = (size_t)symp->st_size; - ftp->ftps_noffs = 1; - ftp->ftps_offs[0] = off; - - if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { - dt_dprintf("fasttrap probe creation ioctl failed: %s\n", - strerror(errno)); - return (dt_set_errno(dtp, errno)); - } - - return (1); -} - -/*ARGSUSED*/ -int -dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp, - fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, const char *pattern) -{ - ulong_t i; - - ftp->ftps_type = DTFTP_OFFSETS; - ftp->ftps_pc = (uintptr_t)symp->st_value; - ftp->ftps_size = (size_t)symp->st_size; - ftp->ftps_noffs = 0; - - /* - * If we're matching against everything, just iterate through each - * instruction in the function, otherwise look for matching offset - * names by constructing the string and comparing it against the - * pattern. - */ - if (strcmp("*", pattern) == 0) { - for (i = 0; i < symp->st_size; i += 4) { - ftp->ftps_offs[ftp->ftps_noffs++] = i; - } - } else { - char name[sizeof (i) * 2 + 1]; - - for (i = 0; i < symp->st_size; i += 4) { - (void) sprintf(name, "%lx", i); - if (gmatch(name, pattern)) - ftp->ftps_offs[ftp->ftps_noffs++] = i; - } - } - - if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { - dt_dprintf("fasttrap probe creation ioctl failed: %s\n", - strerror(errno)); - return (dt_set_errno(dtp, errno)); - } - - return (ftp->ftps_noffs); -}
--- a/usr/src/lib/libdtrace/s390x/regs.d Mon Oct 05 12:49:41 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,120 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "@(#)regs.d 1.2 05/06/08 SMI" - -inline int R_G0 = 0; -#pragma D binding "1.0" R_G0 -inline int R_G1 = 1; -#pragma D binding "1.0" R_G1 -inline int R_G2 = 2; -#pragma D binding "1.0" R_G2 -inline int R_G3 = 3; -#pragma D binding "1.0" R_G3 -inline int R_G4 = 4; -#pragma D binding "1.0" R_G4 -inline int R_G5 = 5; -#pragma D binding "1.0" R_G5 -inline int R_G6 = 6; -#pragma D binding "1.0" R_G6 -inline int R_G7 = 7; -#pragma D binding "1.0" R_G7 - -inline int R_O0 = 8; -#pragma D binding "1.0" R_O0 -inline int R_O1 = 9; -#pragma D binding "1.0" R_O1 -inline int R_O2 = 10; -#pragma D binding "1.0" R_O2 -inline int R_O3 = 11; -#pragma D binding "1.0" R_O3 -inline int R_O4 = 12; -#pragma D binding "1.0" R_O4 -inline int R_O5 = 13; -#pragma D binding "1.0" R_O5 -inline int R_O6 = 14; -#pragma D binding "1.0" R_O6 -inline int R_O7 = 15; -#pragma D binding "1.0" R_O7 - -inline int R_L0 = 16; -#pragma D binding "1.0" R_L0 -inline int R_L1 = 17; -#pragma D binding "1.0" R_L1 -inline int R_L2 = 18; -#pragma D binding "1.0" R_L2 -inline int R_L3 = 19; -#pragma D binding "1.0" R_L3 -inline int R_L4 = 20; -#pragma D binding "1.0" R_L4 -inline int R_L5 = 21; -#pragma D binding "1.0" R_L5 -inline int R_L6 = 22; -#pragma D binding "1.0" R_L6 -inline int R_L7 = 23; -#pragma D binding "1.0" R_L7 - -inline int R_I0 = 24; -#pragma D binding "1.0" R_I0 -inline int R_I1 = 25; -#pragma D binding "1.0" R_I1 -inline int R_I2 = 26; -#pragma D binding "1.0" R_I2 -inline int R_I3 = 27; -#pragma D binding "1.0" R_I3 -inline int R_I4 = 28; -#pragma D binding "1.0" R_I4 -inline int R_I5 = 29; -#pragma D binding "1.0" R_I5 -inline int R_I6 = 30; -#pragma D binding "1.0" R_I6 -inline int R_I7 = 31; -#pragma D binding "1.0" R_I7 - -inline int R_CCR = 32; -#pragma D binding "1.0" R_CCR -inline int R_PC = 33; -#pragma D binding "1.0" R_PC -inline int R_nPC = 34; -#pragma D binding "1.0" R_nPC -inline int R_NPC = R_nPC; -#pragma D binding "1.0" R_NPC -inline int R_Y = 35; -#pragma D binding "1.0" R_Y -inline int R_ASI = 36; -#pragma D binding "1.0" R_ASI -inline int R_FPRS = 37; -#pragma D binding "1.0" R_FPRS -inline int R_PS = R_CCR; -#pragma D binding "1.0" R_PS -inline int R_SP = R_O6; -#pragma D binding "1.0" R_SP -inline int R_FP = R_I6; -#pragma D binding "1.0" R_FP -inline int R_R0 = R_O0; -#pragma D binding "1.0" R_R0 -inline int R_R1 = R_O1; -#pragma D binding "1.0" R_R1
--- a/usr/src/uts/common/dtrace/profile.c Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/uts/common/dtrace/profile.c Thu Oct 08 12:44:34 2009 -0400 @@ -72,14 +72,18 @@ */ #ifdef __x86 # define PROF_ARTIFICIAL_FRAMES 10 -#elsif __sparc +#elif __sparc # ifdef DEBUG # define PROF_ARTIFICIAL_FRAMES 4 # else # define PROF_ARTIFICIAL_FRAMES 3 # endif -#elsif __s390 -# define PROF_ARTIFICIAL_FRAMES 4 +#elif __s390 +# ifdef DEBUG +# define PROF_ARTIFICIAL_FRAMES 4 +# else +# define PROF_ARTIFICIAL_FRAMES 3 +# endif #endif #define PROF_NAMELEN 15
--- a/usr/src/uts/common/sys/dtrace.h Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/uts/common/sys/dtrace.h Thu Oct 08 12:44:34 2009 -0400 @@ -2248,6 +2248,13 @@ #endif +#ifdef __s390 +# define DTRACE_INVOP_STMG 1 +# define DTRACE_INVOP_LMG 2 +# define DTRACE_INVOP_RET 3 +# define DTRACE_INVOP_NOP 4 +#endif + #ifdef __cplusplus } #endif
--- a/usr/src/uts/s390x/Makefile.rules Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/uts/s390x/Makefile.rules Thu Oct 08 12:44:34 2009 -0400 @@ -98,7 +98,7 @@ $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) -$(OBJS_DIR)/%.o: $(SRC)/common/dis/zSeries/%.c +$(OBJS_DIR)/%.o: $(SRC)/common/dis/s390/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) @@ -155,7 +155,7 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/common/os/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) -$(LINTS_DIR)/%.ln: $(SRC)/common/dis/zSeries/%.c +$(LINTS_DIR)/%.ln: $(SRC)/common/dis/s390/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) $(LINTS_DIR)/%.ln: $(SRC)/common/atomic/%.c
--- a/usr/src/uts/s390x/ml/interrupt.s Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/uts/s390x/ml/interrupt.s Thu Oct 08 12:44:34 2009 -0400 @@ -112,7 +112,7 @@ .section ".rodata" .align 8 .svcTAB: - .quad .syscall, .nosvcall, .nosvcall, .nosvcall // 0- 3 + .quad .syscall, .dtrace, .nosvcall, .nosvcall // 0- 3 .quad .nosvcall, .nosvcall, .nosvcall, .nosvcall // 4- 7 .quad .nosvcall, .nosvcall, .nosvcall, .nosvcall // 8- B .quad .nosvcall, .nosvcall, .nosvcall, .nosvcall // C- F @@ -382,7 +382,7 @@ #if defined(lint) void -() +getlgrp() {} #else /* lint */ @@ -504,6 +504,41 @@ /*------------------------------------------------------------------*/ /* */ +/* Name - .dtrace. */ +/* */ +/* Function - User probe trap encountered. */ +/* */ +/* On Entry - %r14 - return address */ +/* - %r9 - Current thread pointer */ +/* - %r11 - Syscall number (not applicable here) */ +/* */ +/*------------------------------------------------------------------*/ + +#if defined(lint) + +void +dtrace() +{} + +#else /* lint */ + +.dtrace: + + lgr %r10,%r14 + la %r6,MINFRAME(%r15) // Get A(Save Area) + aghi %r15,-SA(MINFRAME+8) + la %r2,MINFRAME(%r15) + brasl %r14,dtrace_user_probe + aghi %r15,SA(MINFRAME+8) + lgr %r14,%r10 // Restore link + br %r14 + +#endif + +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ /* Name - .nosvcall. */ /* */ /* Function - Unsupported call. */
--- a/usr/src/uts/s390x/os/lgrpplat.c Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/uts/s390x/os/lgrpplat.c Thu Oct 08 12:44:34 2009 -0400 @@ -149,7 +149,7 @@ /*------------------------------------------------------------------*/ void -lgrp_plat_init(lgrp_id_t lgrpid) +lgrp_plat_init(lgrp_init_stages_t lgrpid) { int i;
--- a/usr/src/uts/s390x/unix/Makefile Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/uts/s390x/unix/Makefile Thu Oct 08 12:44:34 2009 -0400 @@ -99,10 +99,6 @@ CLOBBERFILES = $(CLEANFILES) $(UNIX_BIN) CLEANLINTFILES += $(LINT_LIB) -# instr_size needs a special header -$(OBJS_DIR)/instr_size.o := EXTRA_OPTIONS = -I$(SRC)/common/dis/s390x -$(OBJS_DIR)/instr_size.ln := EXTRA_OPTIONS = -I$(SRC)/common/dis/s390x - CFLAGS += -DDIS_MEM #
--- a/usr/src/uts/zSeries/Makefile.files Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/uts/zSeries/Makefile.files Thu Oct 08 12:44:34 2009 -0400 @@ -148,6 +148,12 @@ # MODSTUB_OBJ = modstubs.o +# +# System z DTrace Providers +# +FBT_OBJS += fbt.o +SDT_OBJS += sdt.o + # Section 3: Misc. # ALL_DEFS += -Ds390x
--- a/usr/src/uts/zSeries/Makefile.rules Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/uts/zSeries/Makefile.rules Thu Oct 08 12:44:34 2009 -0400 @@ -51,6 +51,10 @@ $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) +$(OBJS_DIR)/%.o: $(SRC)/common/dis/s390/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + $(OBJS_DIR)/%.o: $(UTSBASE)/zSeries/dtrace/%.s $(COMPILE.s) -o $@ $<
--- a/usr/src/uts/zSeries/Makefile.zSeries.shared Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/uts/zSeries/Makefile.zSeries.shared Thu Oct 08 12:44:34 2009 -0400 @@ -208,7 +208,7 @@ # DRV_KMODS += arp bl bofi clone cn conskbd consms cpuid DRV_KMODS += crypto cryptoadm dca devinfo dump -#DRV_KMODS += dtrace fasttrap fbt lockstat profile sdt systrace +DRV_KMODS += dtrace fasttrap fbt lockstat profile sdt systrace DRV_KMODS += fssnap icmp icmp6 ip ip6 ipsecah DRV_KMODS += ipsecesp iptun iptunq iwscn keysock kmdb kstat ksyms llc1 DRV_KMODS += lofi
--- a/usr/src/uts/zSeries/dtrace/Makefile Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/uts/zSeries/dtrace/Makefile Thu Oct 08 12:44:34 2009 -0400 @@ -40,13 +40,13 @@ LINT_TARGET = $(MODULE).lint INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) -DTRACE_INC_64 = -I$(UTSBASE)/s390x/zSeries +DTRACE_OBJS += dis_tables.o + +DTRACE_INC_64 = -I$(UTSBASE)/zSeries -I$(SRC)/common/dis/s390 CFLAGS += $(CCVERBOSE) CPPFLAGS += $(DTRACE_INC_$(CLASS)) -DTRACE_XAS_64 = -xmarch=z900 - AS_CPPFLAGS += $(DTRACE_INC_64) ASFLAGS += $(DTRACE_XAS_$(CLASS))
--- a/usr/src/uts/zSeries/dtrace/dtrace_asm.s Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/uts/zSeries/dtrace/dtrace_asm.s Thu Oct 08 12:44:34 2009 -0400 @@ -280,7 +280,7 @@ #else ENTRY(dtrace_copyout) - larl %r1,.LCexmvc + larl %r1,.LCexmvc2 lghi %r0,1 // sar %a2,%r0 // Use access mode to get to user space sacf AC_ACCESS // @@ -301,7 +301,7 @@ ex %r4,0(%r1) 2: br %r14 -.lCexmvc: +.lCexmvc2: mvc 0(1,%r3),0(%r2) SET_SIZE(dtrace_copyout) @@ -317,6 +317,8 @@ /* */ /*------------------------------------------------------------------*/ +#if defined(lint) + /*ARGSUSED*/ void dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, @@ -400,6 +402,8 @@ /* */ /*------------------------------------------------------------------*/ +#if defined(lint) + /*ARGSUSED*/ void dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
--- a/usr/src/uts/zSeries/dtrace/dtrace_isa.c Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/uts/zSeries/dtrace/dtrace_isa.c Thu Oct 08 12:44:34 2009 -0400 @@ -1,72 +1,112 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END +/*------------------------------------------------------------------*/ +/* */ +/* Name - dtrace_isa. */ +/* */ +/* Function - Architecture dependent kernel support for dtrace. */ +/* */ +/* Name - Neale Ferguson */ +/* */ +/* Date - October, 2009. */ +/* */ +/*------------------------------------------------------------------*/ + +/*------------------------------------------------------------------*/ +/* L I C E N S E */ +/*------------------------------------------------------------------*/ + +/*==================================================================*/ +/* */ +/* CDDL HEADER START */ +/* */ +/* The contents of this file are subject to the terms of the */ +/* Common Development and Distribution License (the "License"). */ +/* You may not use this file except in compliance the the License. */ +/* */ +/* You can obtain a copy of the license at: */ +/* - usr/src/OPENSOLARIS.LICENSE, or, */ +/* - http://www.opensolaris.org/os/licensing. */ +/* See the License for the specific language governing permissions */ +/* and limitations under the License. */ +/* */ +/* When distributing Covered Code, include this CDDL HEADER in each */ +/* file and include the License file at usr/src/OPENSOLARIS.LICENSE.*/ +/* If applicable, add the following below this CDDL HEADER, with */ +/* the fields enclosed by brackets "[]" replaced with your own */ +/* identifying information: */ +/* Portions Copyright [yyyy] [name of copyright owner] */ +/* */ +/* CDDL HEADER END */ /* */ /* Copyright 2008 Sine Nomine Associates. */ /* All rights reserved. */ /* Use is subject to license terms. */ - */ +/* */ +/* Copyright 2005 Sun Microsystems, Inc. All rights reserved. */ +/* Use is subject to license terms. */ +/* */ +/*==================================================================*/ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ +/*------------------------------------------------------------------*/ +/* D e f i n e s */ +/*------------------------------------------------------------------*/ + +/*========================= End of Defines =========================*/ +/*------------------------------------------------------------------*/ +/* I n c l u d e s */ +/*------------------------------------------------------------------*/ + +#include <sys/types.h> +#include <sys/asm_linkage.h> #include <sys/dtrace_impl.h> -#include <sys/atomic.h> -#include <sys/model.h> +#include <sys/stack.h> #include <sys/frame.h> -#include <sys/stack.h> -#include <sys/machpcb.h> -#include <sys/procfs_isa.h> #include <sys/cmn_err.h> +#include <sys/privregs.h> #include <sys/sysmacros.h> -#define DTRACE_FMT3OP3_MASK 0x81000000 -#define DTRACE_FMT3OP3 0x80000000 -#define DTRACE_FMT3RS1_SHIFT 14 -#define DTRACE_FMT3RD_SHIFT 25 -#define DTRACE_DISP22_SHIFT 10 -#define DTRACE_RMASK 0x1f -#define DTRACE_REG_L0 16 -#define DTRACE_REG_O7 15 -#define DTRACE_REG_I0 24 -#define DTRACE_REG_I6 30 -#define DTRACE_RET 0x81c7e008 -#define DTRACE_RETL 0x81c3e008 -#define DTRACE_SAVE_MASK 0xc1f80000 -#define DTRACE_SAVE 0x81e00000 -#define DTRACE_RESTORE 0x81e80000 -#define DTRACE_CALL_MASK 0xc0000000 -#define DTRACE_CALL 0x40000000 -#define DTRACE_JMPL_MASK 0x81f10000 -#define DTRACE_JMPL 0x81c00000 -#define DTRACE_BA_MASK 0xdfc00000 -#define DTRACE_BA 0x10800000 -#define DTRACE_BA_MAX 10 +/*========================= End of Includes ========================*/ + +/*------------------------------------------------------------------*/ +/* T y p e d e f s */ +/*------------------------------------------------------------------*/ + + +/*========================= End of Typedefs ========================*/ + +/*------------------------------------------------------------------*/ +/* E x t e r n a l R e f e r e n c e s */ +/*------------------------------------------------------------------*/ + +extern uint8_t dtrace_fuword8_nocheck(void *); +extern uint16_t dtrace_fuword16_nocheck(void *); +extern uint32_t dtrace_fuword32_nocheck(void *); +extern uint64_t dtrace_fuword64_nocheck(void *); + +/*=================== End of External References ===================*/ -extern int dtrace_getupcstack_top(uint64_t *, int, uintptr_t *); -extern int dtrace_getustackdepth_top(uintptr_t *); -extern ulong_t dtrace_getreg_win(uint_t, uint_t); -extern void dtrace_putreg_win(uint_t, ulong_t); -extern int dtrace_fish(int, int, uintptr_t *); +/*------------------------------------------------------------------*/ +/* P r o t o t y p e s */ +/*------------------------------------------------------------------*/ + + +/*========================= End of Prototypes ======================*/ + +/*------------------------------------------------------------------*/ +/* G l o b a l V a r i a b l e s */ +/*------------------------------------------------------------------*/ + +int dtrace_ustackdepth_max = 2048; + +/*====================== End of Global Variables ===================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - dtrace_getpcstack. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ /* * This is similar in principle to getpcstack(), but there are several marked @@ -97,184 +137,18 @@ * don't fire through an interrupt source.) This parameter is used to * assure (b), above. */ + +/*ARGSUSED*/ void -dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, uint32_t *pc) +dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, + uint32_t *intrpc) { - struct frame *fp, *nextfp, *minfp, *stacktop; + struct frame *fp = (struct frame *)dtrace_getfp(); + struct frame *nextfp, *minfp, *stacktop; int depth = 0; - int on_intr, j = 0; - uint32_t i, r; - - fp = (struct frame *)((caddr_t)dtrace_getfp() + STACK_BIAS); - dtrace_flush_windows(); - - if (pc != NULL) { - /* - * If we've been passed a non-NULL pc, we need to determine - * whether or not the specified program counter falls in a leaf - * function. If it falls within a leaf function, we know that - * %o7 is valid in its frame (and we can just drive on). If - * it's a non-leaf, however, we know that %o7 is garbage in the - * bottom frame. To trim this frame, we simply increment - * aframes and drop into the stack-walking loop. - * - * To quickly determine if the specified program counter is in - * a leaf function, we exploit the fact that leaf functions - * tend to be short and non-leaf functions tend to frequently - * perform operations that are only permitted in a non-leaf - * function (e.g., using the %i's or %l's; calling a function; - * performing a restore). We exploit these tendencies by - * simply scanning forward from the specified %pc -- if we see - * an operation only permitted in a non-leaf, we know we're in - * a non-leaf; if we see a retl, we know we're in a leaf. - * Fortunately, one need not perform anywhere near full - * disassembly to effectively determine the former: determining - * that an instruction is a format-3 instruction and decoding - * its rd and rs1 fields, for example, requires very little - * manipulation. Overall, this method of leaf determination - * performs quite well: on average, we only examine between - * 1.5 and 2.5 instructions before making the determination. - * (Outliers do exist, however; of note is the non-leaf - * function ip_sioctl_not_ours() which -- as of this writing -- - * has a whopping 455 straight instructions that manipulate - * only %g's and %o's.) - */ - int delay = 0, branches = 0, taken = 0; - - if (depth < pcstack_limit) - pcstack[depth++] = (pc_t)(uintptr_t)pc; - - /* - * Our heuristic is exactly that -- a heuristic -- and there - * exists a possibility that we could be either be vectored - * off into the weeds (by following a bogus branch) or could - * wander off the end of the function and off the end of a - * text mapping (by not following a conditional branch at the - * end of the function that is effectively always taken). So - * as a precautionary measure, we set the NOFAULT flag. - */ - DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); - - for (;;) { - i = pc[j++]; - - if ((i & DTRACE_FMT3OP3_MASK) == DTRACE_FMT3OP3) { - /* - * This is a format-3 instruction. We can - * look at rd and rs1. - */ - r = (i >> DTRACE_FMT3RS1_SHIFT) & DTRACE_RMASK; - - if (r >= DTRACE_REG_L0) - goto nonleaf; - - r = (i >> DTRACE_FMT3RD_SHIFT) & DTRACE_RMASK; - - if (r >= DTRACE_REG_L0) - goto nonleaf; - - if ((i & DTRACE_JMPL_MASK) == DTRACE_JMPL) { - delay = 1; - continue; - } - - /* - * If we see explicit manipulation with %o7 - * as a destination register, we know that - * %o7 is likely bogus -- and we treat this - * function as a non-leaf. - */ - if (r == DTRACE_REG_O7) { - if (delay) - goto leaf; - - i &= DTRACE_JMPL_MASK; - - if (i == DTRACE_JMPL) { - delay = 1; - continue; - } - - goto nonleaf; - } - } else { - /* - * If this is a call, it may or may not be - * a leaf; we need to check the delay slot. - */ - if ((i & DTRACE_CALL_MASK) == DTRACE_CALL) { - delay = 1; - continue; - } - - /* - * If we see a ret it's not a leaf; if we - * see a retl, it is a leaf. - */ - if (i == DTRACE_RET) - goto nonleaf; - - if (i == DTRACE_RETL) - goto leaf; - - /* - * If this is a ba (annulled or not), then we - * need to actually follow the branch. No, we - * don't look at the delay slot -- hopefully - * anything that can be gleaned from the delay - * slot can also be gleaned from the branch - * target. To prevent ourselves from iterating - * infinitely, we clamp the number of branches - * that we'll follow, and we refuse to follow - * the same branch twice consecutively. In - * both cases, we abort by deciding that we're - * looking at a leaf. While in theory this - * could be wrong (we could be in the middle of - * a loop in a non-leaf that ends with a ba and - * only manipulates outputs and globals in the - * body of the loop -- therefore leading us to - * the wrong conclusion), this doesn't seem to - * crop up in practice. (Or rather, this - * condition could not be deliberately induced, - * despite concerted effort.) - */ - if ((i & DTRACE_BA_MASK) == DTRACE_BA) { - if (++branches == DTRACE_BA_MAX || - taken == j) - goto nonleaf; - - taken = j; - j += ((int)(i << DTRACE_DISP22_SHIFT) >> - DTRACE_DISP22_SHIFT) - 1; - continue; - } - - /* - * Finally, if it's a save, it should be - * treated as a leaf; if it's a restore it - * should not be treated as a leaf. - */ - if ((i & DTRACE_SAVE_MASK) == DTRACE_SAVE) - goto leaf; - - if ((i & DTRACE_SAVE_MASK) == DTRACE_RESTORE) - goto nonleaf; - } - - if (delay) { - /* - * If this was a delay slot instruction and - * we didn't pick it up elsewhere, this is a - * non-leaf. - */ - goto nonleaf; - } - } -nonleaf: - aframes++; -leaf: - DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); - } + int on_intr, last = 0; + uintptr_t pc; + uintptr_t caller = CPU->cpu_dtrace_caller; if ((on_intr = CPU_ON_INTR(CPU)) != 0) stacktop = (struct frame *)(CPU->cpu_intr_stack + SA(MINFRAME)); @@ -282,150 +156,193 @@ stacktop = (struct frame *)curthread->t_stk; minfp = fp; + aframes++; + + if (intrpc != NULL && depth < pcstack_limit) + pcstack[depth++] = (pc_t)intrpc; + while (depth < pcstack_limit) { - nextfp = (struct frame *)((caddr_t)fp->fr_savfp + STACK_BIAS); + nextfp = (struct frame *)fp->fr_savfp; + pc = fp->fr_savpc; + if (nextfp <= minfp || nextfp >= stacktop) { - if (!on_intr && nextfp == stacktop && aframes != 0) { - /* - * If we are exactly at the top of the stack - * with a non-zero number of artificial frames, - * it must be that the stack is filled with - * nothing _but_ artificial frames. In this - * case, we assert that this is so, zero - * pcstack, and return. - */ - ASSERT(aframes == 1); - ASSERT(depth == 0); - - while (depth < pcstack_limit) - pcstack[depth++] = NULL; - return; - } - if (on_intr) { /* * Hop from interrupt stack to thread stack. */ stacktop = (struct frame *)curthread->t_stk; minfp = (struct frame *)curthread->t_stkbase; - on_intr = 0; - - if (nextfp > minfp && nextfp < stacktop) - continue; - } else { - /* - * High-level interrupts may occur when %sp is - * not necessarily contained in the stack - * bounds implied by %g7 -- interrupt thread - * management runs with %pil at DISP_LEVEL, - * and high-level interrupts may thus occur - * in windows when %sp and %g7 are not self- - * consistent. If we call dtrace_getpcstack() - * from a high-level interrupt that has occurred - * in such a window, we will fail the above test - * of nextfp against minfp/stacktop. If the - * high-level interrupt has in turn interrupted - * a non-passivated interrupt thread, we - * will execute the below code with non-zero - * aframes. We therefore want to assert that - * aframes is zero _or_ we are in a high-level - * interrupt -- but because cpu_intr_actv is - * updated with high-level interrupts enabled, - * we must reduce this to only asserting that - * %pil is greater than DISP_LEVEL. - */ - ASSERT(aframes == 0 || - dtrace_getipl() > DISP_LEVEL); - pcstack[depth++] = (pc_t)fp->fr_savpc; + continue; } + /* + * This is the last frame we can process; indicate + * that we should return after processing this frame. + */ + last = 1; + } + + if (aframes > 0) { + if (--aframes == 0 && caller != NULL) { + /* + * We've just run out of artificial frames, + * and we have a valid caller -- fill it in + * now. + */ + ASSERT(depth < pcstack_limit); + pcstack[depth++] = (pc_t)caller; + caller = NULL; + } + } else { + if (depth < pcstack_limit) + pcstack[depth++] = (pc_t)pc; + } + + if (last) { while (depth < pcstack_limit) pcstack[depth++] = NULL; return; } - if (aframes > 0) { - aframes--; - } else { - pcstack[depth++] = (pc_t)fp->fr_savpc; - } - fp = nextfp; minfp = fp; } } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - dtrace_getustack_common. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + static int -dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t sp) +dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, + uintptr_t sp) { + klwp_t *lwp = ttolwp(curthread); proc_t *p = curproc; + uintptr_t oldcontext = lwp->lwp_oldcontext; + uintptr_t oldsp; + volatile uint16_t *flags = + (volatile uint16_t *)&cpu_core[CPU->cpu_id].cpuc_dtrace_flags; + size_t s1, s2; int ret = 0; ASSERT(pcstack == NULL || pcstack_limit > 0); + ASSERT(dtrace_ustackdepth_max > 0); if (p->p_model == DATAMODEL_NATIVE) { - for (;;) { - struct frame *fr = (struct frame *)(sp + STACK_BIAS); - uintptr_t pc; + s1 = sizeof (struct frame) + 2 * sizeof (long); + s2 = s1 + sizeof (siginfo_t); + } else { + s1 = sizeof (struct frame32) + 3 * sizeof (int); + s2 = s1 + sizeof (siginfo32_t); + } - if (sp == 0 || fr == NULL || - !IS_P2ALIGNED((uintptr_t)fr, STACK_ALIGN)) + while (pc != 0) { + /* + * We limit the number of times we can go around this + * loop to account for a circular stack. + */ + if (ret++ >= dtrace_ustackdepth_max) { + *flags |= CPU_DTRACE_BADSTACK; + cpu_core[CPU->cpu_id].cpuc_dtrace_illval = sp; + break; + } + + if (pcstack != NULL) { + *pcstack++ = (uint64_t)pc; + pcstack_limit--; + if (pcstack_limit <= 0) break; + } - pc = dtrace_fulword(&fr->fr_savpc); - sp = dtrace_fulword(&fr->fr_savfp); + if (sp == 0) + break; + + oldsp = sp; - if (pc == 0) - break; + if (oldcontext == sp + s1 || oldcontext == sp + s2) { + if (p->p_model == DATAMODEL_NATIVE) { + ucontext_t *ucp = (ucontext_t *)oldcontext; + greg_t *gregs = ucp->uc_mcontext.gregs; - ret++; + sp = dtrace_fulword(&gregs[REG_SP]); + pc = dtrace_fulword(&ucp->uc_mcontext.psw.pc); + + oldcontext = dtrace_fulword(&ucp->uc_link); + } else { + ucontext32_t *ucp = (ucontext32_t *)oldcontext; + greg32_t *gregs = ucp->uc_mcontext.gregs; - if (pcstack != NULL) { - *pcstack++ = pc; - pcstack_limit--; - if (pcstack_limit == 0) - break; + sp = dtrace_fuword32(&gregs[REG_SP]); + pc = dtrace_fuword32(&ucp->uc_mcontext.psw.pc); + + oldcontext = dtrace_fuword32(&ucp->uc_link); + } + } else { + if (p->p_model == DATAMODEL_NATIVE) { + struct frame *fr = (struct frame *)sp; + + pc = dtrace_fulword(&fr->fr_savpc); + sp = dtrace_fulword(&fr->fr_savfp); + } else { + struct frame32 *fr = (struct frame32 *)sp; + + pc = dtrace_fuword32(&fr->fr_savpc); + sp = dtrace_fuword32(&fr->fr_savfp); } } - } else { - for (;;) { - struct frame32 *fr = (struct frame32 *)sp; - uint32_t pc; - if (sp == 0 || - !IS_P2ALIGNED((uintptr_t)fr, STACK_ALIGN32)) - break; - - pc = dtrace_fuword32(&fr->fr_savpc); - sp = dtrace_fuword32(&fr->fr_savfp); + if (sp == oldsp) { + *flags |= CPU_DTRACE_BADSTACK; + cpu_core[CPU->cpu_id].cpuc_dtrace_illval = sp; + break; + } - if (pc == 0) - break; - - ret++; - - if (pcstack != NULL) { - *pcstack++ = pc; - pcstack_limit--; - if (pcstack_limit == 0) - break; - } + /* + * This is totally bogus: if we faulted, we're going to clear + * the fault and break. This is to deal with the apparently + * broken Java stacks on x86. + */ + if (*flags & CPU_DTRACE_FAULT) { + *flags &= ~CPU_DTRACE_FAULT; + break; } } return (ret); } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - dtrace_getupcstack. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + void dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) { klwp_t *lwp = ttolwp(curthread); proc_t *p = curproc; struct regs *rp; - uintptr_t sp; + uintptr_t pc, sp; int n; + ASSERT(DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT)); + + if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT)) + return; + if (pcstack_limit <= 0) return; @@ -441,31 +358,22 @@ if (pcstack_limit <= 0) return; - *pcstack++ = (uint64_t)rp->r_pc; - pcstack_limit--; - - if (pcstack_limit <= 0) - return; + pc = rp->r_pc; + sp = rp->r_sp; if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { - *pcstack++ = (uint64_t)rp->r_o7; + *pcstack++ = (uint64_t)pc; pcstack_limit--; if (pcstack_limit <= 0) return; + + if (p->p_model == DATAMODEL_NATIVE) + pc = dtrace_fulword((void *)rp->r_sp); + else + pc = dtrace_fuword32((void *)rp->r_sp); } - sp = rp->r_sp; - - n = dtrace_getupcstack_top(pcstack, pcstack_limit, &sp); - ASSERT(n >= 0); - ASSERT(n <= pcstack_limit); - - pcstack += n; - pcstack_limit -= n; - if (pcstack_limit <= 0) - return; - - n = dtrace_getustack_common(pcstack, pcstack_limit, sp); + n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp); ASSERT(n >= 0); ASSERT(n <= pcstack_limit); @@ -477,14 +385,24 @@ *pcstack++ = NULL; } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - dtrace_getustackdepth. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + int dtrace_getustackdepth(void) { klwp_t *lwp = ttolwp(curthread); proc_t *p = curproc; struct regs *rp; - uintptr_t sp; - int n = 1; + uintptr_t pc, sp; + int n = 0; if (lwp == NULL || p == NULL || (rp = lwp->lwp_regs) == NULL) return (0); @@ -492,30 +410,46 @@ if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT)) return (-1); + pc = rp->r_pc; sp = rp->r_sp; - n += dtrace_getustackdepth_top(&sp); - n += dtrace_getustack_common(NULL, 0, sp); + if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { + n++; - /* - * Add one more to the stack depth if we're in an entry probe as long - * as the return address is non-NULL or there are additional frames - * beyond that NULL return address. - */ - if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY) && - (rp->r_o7 != NULL || n != 1)) - n++; + if (p->p_model == DATAMODEL_NATIVE) + pc = dtrace_fulword((void *)rp->r_sp); + else + pc = dtrace_fuword32((void *)rp->r_sp); + } + + n += dtrace_getustack_common(NULL, 0, pc, sp); return (n); } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - dtrace_getufpstack. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + void dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) { klwp_t *lwp = ttolwp(curthread); - proc_t *p = ttoproc(curthread); + proc_t *p = curproc; struct regs *rp; - uintptr_t sp; + uintptr_t pc, sp, oldcontext; + volatile uint16_t *flags = + (volatile uint16_t *)&cpu_core[CPU->cpu_id].cpuc_dtrace_flags; + size_t s1, s2; + + if (*flags & CPU_DTRACE_FAULT) + return; if (pcstack_limit <= 0) return; @@ -532,68 +466,81 @@ if (pcstack_limit <= 0) return; + pc = rp->r_pc; + sp = rp->r_sp; + oldcontext = lwp->lwp_oldcontext; + + if (p->p_model == DATAMODEL_NATIVE) { + s1 = sizeof (struct frame) + 2 * sizeof (long); + s2 = s1 + sizeof (siginfo_t); + } else { + s1 = sizeof (struct frame32) + 3 * sizeof (int); + s2 = s1 + sizeof (siginfo32_t); + } + if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { + *pcstack++ = (uint64_t)pc; *fpstack++ = 0; - *pcstack++ = (uint64_t)rp->r_pc; pcstack_limit--; if (pcstack_limit <= 0) return; - *fpstack++ = (uint64_t)rp->r_sp; - *pcstack++ = (uint64_t)rp->r_o7; - pcstack_limit--; - } else { - *fpstack++ = (uint64_t)rp->r_sp; - *pcstack++ = (uint64_t)rp->r_pc; - pcstack_limit--; + if (p->p_model == DATAMODEL_NATIVE) + pc = dtrace_fulword((void *)rp->r_sp); + else + pc = dtrace_fuword32((void *)rp->r_sp); } - if (pcstack_limit <= 0) - return; + while (pc != 0) { + *pcstack++ = (uint64_t)pc; + *fpstack++ = sp; + pcstack_limit--; + if (pcstack_limit <= 0) + break; - sp = rp->r_sp; - - dtrace_flush_user_windows(); + if (sp == 0) + break; - if (p->p_model == DATAMODEL_NATIVE) { - while (pcstack_limit > 0) { - struct frame *fr = (struct frame *)(sp + STACK_BIAS); - uintptr_t pc; + if (oldcontext == sp + s1 || oldcontext == sp + s2) { + if (p->p_model == DATAMODEL_NATIVE) { + ucontext_t *ucp = (ucontext_t *)oldcontext; + greg_t *gregs = ucp->uc_mcontext.gregs; - if (sp == 0 || fr == NULL || - ((uintptr_t)&fr->fr_savpc & 3) != 0 || - ((uintptr_t)&fr->fr_savfp & 3) != 0) - break; + sp = dtrace_fulword(&gregs[REG_SP]); + pc = dtrace_fulword(&ucp->uc_mcontext.psw.pc); - pc = dtrace_fulword(&fr->fr_savpc); - sp = dtrace_fulword(&fr->fr_savfp); - - if (pc == 0) - break; + oldcontext = dtrace_fulword(&ucp->uc_link); + } else { + ucontext_t *ucp = (ucontext_t *)oldcontext; + greg_t *gregs = ucp->uc_mcontext.gregs; - *fpstack++ = sp; - *pcstack++ = pc; - pcstack_limit--; - } - } else { - while (pcstack_limit > 0) { - struct frame32 *fr = (struct frame32 *)sp; - uint32_t pc; + sp = dtrace_fuword32(&gregs[REG_SP]); + pc = dtrace_fuword32(&ucp->uc_mcontext.psw.pc); + + oldcontext = dtrace_fuword32(&ucp->uc_link); + } + } else { + if (p->p_model == DATAMODEL_NATIVE) { + struct frame *fr = (struct frame *)sp; + + pc = dtrace_fulword(&fr->fr_savpc); + sp = dtrace_fulword(&fr->fr_savfp); + } else { + struct frame32 *fr = (struct frame32 *)sp; - if (sp == 0 || - ((uintptr_t)&fr->fr_savpc & 3) != 0 || - ((uintptr_t)&fr->fr_savfp & 3) != 0) - break; + pc = dtrace_fuword32(&fr->fr_savpc); + sp = dtrace_fuword32(&fr->fr_savfp); + } + } - pc = dtrace_fuword32(&fr->fr_savpc); - sp = dtrace_fuword32(&fr->fr_savfp); - - if (pc == 0) - break; - - *fpstack++ = sp; - *pcstack++ = pc; - pcstack_limit--; + /* + * This is totally bogus: if we faulted, we're going to clear + * the fault and break. This is to deal with the apparently + * broken Java stacks on x86. + */ + if (*flags & CPU_DTRACE_FAULT) { + *flags &= ~CPU_DTRACE_FAULT; + break; } } @@ -602,81 +549,96 @@ *pcstack++ = NULL; } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - dtrace_getarg. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + +/*ARGSUSED*/ uint64_t dtrace_getarg(int arg, int aframes) { - uintptr_t val; - struct frame *fp; - uint64_t rval; + uintptr_t rval; + uintptr_t *stack; + proc_t *p = curproc; + int i; - /* - * Account for the fact that dtrace_getarg() consumes an additional - * stack frame. - */ aframes++; - if (arg < 6) { - if (dtrace_fish(aframes, DTRACE_REG_I0 + arg, &val) == 0) - return (val); - } else { - if (dtrace_fish(aframes, DTRACE_REG_I6, &val) == 0) { - /* - * We have a stack pointer; grab the argument. - */ - fp = (struct frame *)(val + STACK_BIAS); + if (p->p_model == DATAMODEL_LP64) { + struct frame *fp = (struct frame *) ((caddr_t) dtrace_getfp()); + + DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); - DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); - rval = fp->fr_argx[arg - 6]; - DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); + for (aframes -= 1; aframes; aframes--) + fp = (struct frame *)((caddr_t)fp->fr_savfp); - return (rval); + if (arg < 5) { + rval = fp->fr_argd[arg]; + } else { + fp = (struct frame *)((caddr_t)fp->fr_savfp); + rval = fp->fr_argx[arg - 6]; } - } - /* - * There are other ways to do this. But the slow, painful way works - * just fine. Because this requires some loads, we need to set - * CPU_DTRACE_NOFAULT to protect against looking for an argument that - * isn't there. - */ - fp = (struct frame *)((caddr_t)dtrace_getfp() + STACK_BIAS); - dtrace_flush_windows(); + DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); + } else { + struct frame32 *fp = (struct frame32 *) ((caddr_t) dtrace_getfp()); - DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); + DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); + + for (aframes -= 1; aframes; aframes--) + fp = (struct frame32 *)((caddr_t)fp->fr_savfp); - for (aframes -= 1; aframes; aframes--) - fp = (struct frame *)((caddr_t)fp->fr_savfp + STACK_BIAS); + if (arg < 5) { + rval = fp->fr_argd[arg]; + } else { + fp = (struct frame32 *)((caddr_t)fp->fr_savfp); + rval = fp->fr_argx[arg - 6]; + } - if (arg < 6) { - rval = fp->fr_arg[arg]; - } else { - fp = (struct frame *)((caddr_t)fp->fr_savfp + STACK_BIAS); - rval = fp->fr_argx[arg - 6]; + DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); } - DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); - return (rval); } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - dtrace_getstackdepth. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + +/*ARGSUSED*/ int dtrace_getstackdepth(int aframes) { - struct frame *fp, *nextfp, *minfp, *stacktop; + struct frame *fp = (struct frame *)dtrace_getfp(); + struct frame *nextfp, *minfp, *stacktop; int depth = 0; int on_intr; - fp = (struct frame *)((caddr_t)dtrace_getfp() + STACK_BIAS); - dtrace_flush_windows(); - if ((on_intr = CPU_ON_INTR(CPU)) != 0) - stacktop = (struct frame *)CPU->cpu_intr_stack + SA(MINFRAME); + stacktop = (struct frame *)(CPU->cpu_intr_stack + SA(MINFRAME)); else stacktop = (struct frame *)curthread->t_stk; minfp = fp; + aframes++; + for (;;) { - nextfp = (struct frame *)((caddr_t)fp->fr_savfp + STACK_BIAS); + depth++; + + nextfp = (struct frame *)fp->fr_savfp; + if (nextfp <= minfp || nextfp >= stacktop) { if (on_intr) { /* @@ -687,217 +649,122 @@ on_intr = 0; continue; } - - return (++depth); - } - - if (aframes > 0) { - aframes--; - } else { - depth++; + break; } fp = nextfp; minfp = fp; } + + if (depth <= aframes) + return (0); + + return (depth - aframes); } -/* - * This uses the same register numbering scheme as in sys/procfs_isa.h. - */ +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - dtrace_getreg. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + ulong_t dtrace_getreg(struct regs *rp, uint_t reg) { - ulong_t value; - uintptr_t fp; - struct machpcb *mpcb; - - if (reg == R_G0) + if (reg > REG_G15) { + DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); return (0); - - if (reg <= R_G7) - return ((&rp->r_g1)[reg - 1]); - - if (reg > R_I7) { - switch (reg) { - case R_CCR: - return ((rp->r_tstate >> TSTATE_CCR_SHIFT) & - TSTATE_CCR_MASK); - case R_PC: - return (rp->r_pc); - case R_nPC: - return (rp->r_npc); - case R_Y: - return (rp->r_y); - case R_ASI: - return ((rp->r_tstate >> TSTATE_ASI_SHIFT) & - TSTATE_ASI_MASK); - case R_FPRS: - return (dtrace_getfprs()); - default: - DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); - return (0); - } - } - - /* - * We reach go to the fake restore case if the probe we hit was a pid - * return probe on a restore instruction. We partially emulate the - * restore in the kernel and then execute a simple restore - * instruction that we've secreted away to do the actual register - * window manipulation. We need to go one register window further - * down to get at the %ls, and %is and we need to treat %os like %is - * to pull them out of the topmost user frame. - */ - if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAKERESTORE)) { - if (reg > R_O7) - goto fake_restore; - else - reg += R_I0 - R_O0; - - } else if (reg <= R_O7) { - return ((&rp->r_g1)[reg - 1]); - } - - if (dtrace_getotherwin() > 0) - return (dtrace_getreg_win(reg, 1)); - - mpcb = (struct machpcb *)((caddr_t)rp - REGOFF); - - if (curproc->p_model == DATAMODEL_NATIVE) { - struct frame *fr = (void *)(rp->r_sp + STACK_BIAS); - - if (mpcb->mpcb_wbcnt > 0) { - struct rwindow *rwin = (void *)mpcb->mpcb_wbuf; - int i = mpcb->mpcb_wbcnt; - do { - i--; - if ((long)mpcb->mpcb_spbuf[i] == rp->r_sp) - return (rwin[i].rw_local[reg - 16]); - } while (i > 0); - } - - DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); - value = dtrace_fulword(&fr->fr_local[reg - 16]); - DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); - } else { - struct frame32 *fr = (void *)(uintptr_t)(caddr32_t)rp->r_sp; - - if (mpcb->mpcb_wbcnt > 0) { - struct rwindow32 *rwin = (void *)mpcb->mpcb_wbuf; - int i = mpcb->mpcb_wbcnt; - do { - i--; - if ((long)mpcb->mpcb_spbuf[i] == rp->r_sp) - return (rwin[i].rw_local[reg - 16]); - } while (i > 0); - } - - DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); - value = dtrace_fuword32(&fr->fr_local[reg - 16]); - DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); } - return (value); + return ((&rp->r_g0)[reg]); +} -fake_restore: - ASSERT(R_L0 <= reg && reg <= R_I7); +/*========================= End of Function ========================*/ - /* - * We first look two user windows down to see if we can dig out - * the register we're looking for. - */ - if (dtrace_getotherwin() > 1) - return (dtrace_getreg_win(reg, 2)); +/*------------------------------------------------------------------*/ +/* */ +/* Name - dtrace_fuword8. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ - /* - * First we need to get the frame pointer and then we perform - * the same computation as in the non-fake-o-restore case. - */ - - mpcb = (struct machpcb *)((caddr_t)rp - REGOFF); - - if (dtrace_getotherwin() > 0) { - fp = dtrace_getreg_win(R_FP, 1); - goto got_fp; +uint8_t +dtrace_fuword8(void *uaddr) +{ + if ((uintptr_t)uaddr >= _userlimit) { + DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); + cpu_core[CPU->cpu_id].cpuc_dtrace_illval = (uintptr_t)uaddr; + return (0); } + return (dtrace_fuword8_nocheck(uaddr)); +} - if (curproc->p_model == DATAMODEL_NATIVE) { - struct frame *fr = (void *)(rp->r_sp + STACK_BIAS); +/*========================= End of Function ========================*/ - if (mpcb->mpcb_wbcnt > 0) { - struct rwindow *rwin = (void *)mpcb->mpcb_wbuf; - int i = mpcb->mpcb_wbcnt; - do { - i--; - if ((long)mpcb->mpcb_spbuf[i] == rp->r_sp) { - fp = rwin[i].rw_fp; - goto got_fp; - } - } while (i > 0); - } - - DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); - fp = dtrace_fulword(&fr->fr_savfp); - DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); - if (cpu_core[CPU->cpu_id].cpuc_dtrace_flags & CPU_DTRACE_FAULT) - return (0); - } else { - struct frame32 *fr = (void *)(uintptr_t)(caddr32_t)rp->r_sp; +/*------------------------------------------------------------------*/ +/* */ +/* Name - dtrace_fuword16. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ - if (mpcb->mpcb_wbcnt > 0) { - struct rwindow32 *rwin = (void *)mpcb->mpcb_wbuf; - int i = mpcb->mpcb_wbcnt; - do { - i--; - if ((long)mpcb->mpcb_spbuf[i] == rp->r_sp) { - fp = rwin[i].rw_fp; - goto got_fp; - } - } while (i > 0); - } +uint16_t +dtrace_fuword16(void *uaddr) +{ + if ((uintptr_t)uaddr >= _userlimit) { + DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); + cpu_core[CPU->cpu_id].cpuc_dtrace_illval = (uintptr_t)uaddr; + return (0); + } + return (dtrace_fuword16_nocheck(uaddr)); +} - DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); - fp = dtrace_fuword32(&fr->fr_savfp); - DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); - if (cpu_core[CPU->cpu_id].cpuc_dtrace_flags & CPU_DTRACE_FAULT) - return (0); - } -got_fp: +/*========================= End of Function ========================*/ - if (curproc->p_model == DATAMODEL_NATIVE) { - struct frame *fr = (void *)(fp + STACK_BIAS); +/*------------------------------------------------------------------*/ +/* */ +/* Name - dtrace_fuword32. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ - if (mpcb->mpcb_wbcnt > 0) { - struct rwindow *rwin = (void *)mpcb->mpcb_wbuf; - int i = mpcb->mpcb_wbcnt; - do { - i--; - if ((long)mpcb->mpcb_spbuf[i] == fp) - return (rwin[i].rw_local[reg - 16]); - } while (i > 0); - } +uint32_t +dtrace_fuword32(void *uaddr) +{ + if ((uintptr_t)uaddr >= _userlimit) { + DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); + cpu_core[CPU->cpu_id].cpuc_dtrace_illval = (uintptr_t)uaddr; + return (0); + } + return (dtrace_fuword32_nocheck(uaddr)); +} - DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); - value = dtrace_fulword(&fr->fr_local[reg - 16]); - DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); - } else { - struct frame32 *fr = (void *)(uintptr_t)(caddr32_t)fp; +/*========================= End of Function ========================*/ - if (mpcb->mpcb_wbcnt > 0) { - struct rwindow32 *rwin = (void *)mpcb->mpcb_wbuf; - int i = mpcb->mpcb_wbcnt; - do { - i--; - if ((long)mpcb->mpcb_spbuf[i] == fp) - return (rwin[i].rw_local[reg - 16]); - } while (i > 0); - } +/*------------------------------------------------------------------*/ +/* */ +/* Name - dtrace_fuword64. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ - DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); - value = dtrace_fuword32(&fr->fr_local[reg - 16]); - DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); +uint64_t +dtrace_fuword64(void *uaddr) +{ + if ((uintptr_t)uaddr >= _userlimit) { + DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); + cpu_core[CPU->cpu_id].cpuc_dtrace_illval = (uintptr_t)uaddr; + return (0); } + return (dtrace_fuword64_nocheck(uaddr)); +} - return (value); -} +/*========================= End of Function ========================*/
--- a/usr/src/uts/zSeries/dtrace/fasttrap.conf Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/uts/zSeries/dtrace/fasttrap.conf Thu Oct 08 12:44:34 2009 -0400 @@ -23,7 +23,6 @@ # Copyright 2004 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#ident "@(#)fasttrap.conf 1.3 05/06/08 SMI" name="fasttrap" parent="pseudo" instance=0;
--- a/usr/src/uts/zSeries/dtrace/fasttrap_isa.c Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/uts/zSeries/dtrace/fasttrap_isa.c Thu Oct 08 12:44:34 2009 -0400 @@ -1,33 +1,95 @@ +/*------------------------------------------------------------------*/ +/* */ +/* Name - fasttrap_isa. */ +/* */ +/* Function - Process fasttrap system calls for dtrace. */ +/* */ +/* Name - Neale Ferguson */ +/* */ +/* Date - October, 2009 */ +/* */ +/*------------------------------------------------------------------*/ + /* - * CDDL HEADER START + * Lossless User-Land Tracing on System z + * -------------------------------------- * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License - * (the "License"). You may not use this file except in compliance - * with the License. + * The Basic Idea + * + * The most important design constraint is, of course, correct execution of + * the user thread above all else. The next most important goal is rapid + * execution. We combine execution of instructions in user-land with + * emulation of certain instructions in the kernel to aim for complete + * correctness and maximal performance. + * + * The execution of most instructions is not dependent on the address; for + * these instructions it is sufficient to copy them into the user process's + * address space and execute them. To effectively single-step an instruction + * in user-land, we copy out the following sequence of instructions to scratch + * space in the user thread's ulwp_t structure. * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. + * We then set the program counter to point to this scratch space + * Once execution resumes, the original instruction is executed and + * then control flow is redirected to what was originally the subsequent + * instruction. If the kernel attemps to deliver a signal while single- + * stepping, the signal is deferred and the program counter is moved into the + * second sequence of instructions. The second sequence ends in a trap into + * the kernel where the deferred signal is then properly handled and delivered. + * + * For instructions whose execute is position dependent, we perform + * more complex operations as explained in the code. * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END + */ + +/*------------------------------------------------------------------*/ +/* L I C E N S E */ +/*------------------------------------------------------------------*/ + +/*==================================================================*/ +/* */ +/* CDDL HEADER START */ +/* */ +/* The contents of this file are subject to the terms of the */ +/* Common Development and Distribution License (the "License"). */ +/* You may not use this file except in compliance the the License. */ +/* */ +/* You can obtain a copy of the license at: */ +/* - usr/src/OPENSOLARIS.LICENSE, or, */ +/* - http://www.opensolaris.org/os/licensing. */ +/* See the License for the specific language governing permissions */ +/* and limitations under the License. */ +/* */ +/* When distributing Covered Code, include this CDDL HEADER in each */ +/* file and include the License file at usr/src/OPENSOLARIS.LICENSE.*/ +/* If applicable, add the following below this CDDL HEADER, with */ +/* the fields enclosed by brackets "[]" replaced with your own */ +/* identifying information: */ +/* Portions Copyright [yyyy] [name of copyright owner] */ +/* */ +/* CDDL HEADER END */ /* */ -/* Copyright 2008 Sine Nomine Associates. */ +/* Copyright 2009 Sine Nomine Associates. */ /* All rights reserved. */ /* Use is subject to license terms. */ - */ +/* */ +/* Copyright 2005 Sun Microsystems, Inc. All rights reserved. */ +/* Use is subject to license terms. */ +/* */ +/*==================================================================*/ + +/*------------------------------------------------------------------*/ +/* D e f i n e s */ +/*------------------------------------------------------------------*/ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ +#define JGOP1 0xc0 +#define JGOP2 0x4 +#define UNC 0xf + +/*========================= End of Defines =========================*/ + +/*------------------------------------------------------------------*/ +/* I n c l u d e s */ +/*------------------------------------------------------------------*/ #include <sys/fasttrap_isa.h> #include <sys/fasttrap_impl.h> @@ -38,165 +100,44 @@ #include <sys/stack.h> #include <sys/sysmacros.h> #include <sys/trap.h> +#include <sys/privregs.h> +#include <dis_tables.h> -#include <v9/sys/machpcb.h> -#include <v9/sys/privregs.h> +/*========================= End of Includes ========================*/ + +/*------------------------------------------------------------------*/ +/* T y p e d e f s */ +/*------------------------------------------------------------------*/ + + +/*========================= End of Typedefs ========================*/ + +/*------------------------------------------------------------------*/ +/* E x t e r n a l R e f e r e n c e s */ +/*------------------------------------------------------------------*/ + + +/*=================== End of External References ===================*/ -/* - * Lossless User-Land Tracing on SPARC - * ----------------------------------- - * - * The Basic Idea - * - * The most important design constraint is, of course, correct execution of - * the user thread above all else. The next most important goal is rapid - * execution. We combine execution of instructions in user-land with - * emulation of certain instructions in the kernel to aim for complete - * correctness and maximal performance. - * - * We take advantage of the split PC/NPC architecture to speed up logical - * single-stepping; when we copy an instruction out to the scratch space in - * the ulwp_t structure (held in the %g7 register on SPARC), we can - * effectively single step by setting the PC to our scratch space and leaving - * the NPC alone. This executes the replaced instruction and then continues - * on without having to reenter the kernel as with single- stepping. The - * obvious caveat is for instructions whose execution is PC dependant -- - * branches, call and link instructions (call and jmpl), and the rdpc - * instruction. These instructions cannot be executed in the manner described - * so they must be emulated in the kernel. - * - * Emulation for this small set of instructions if fairly simple; the most - * difficult part being emulating branch conditions. - * - * - * A Cache Heavy Portfolio - * - * It's important to note at this time that copying an instruction out to the - * ulwp_t scratch space in user-land is rather complicated. SPARC has - * separate data and instruction caches so any writes to the D$ (using a - * store instruction for example) aren't necessarily reflected in the I$. - * The flush instruction can be used to synchronize the two and must be used - * for any self-modifying code, but the flush instruction only applies to the - * primary address space (the absence of a flusha analogue to the flush - * instruction that accepts an ASI argument is an obvious omission from SPARC - * v9 where the notion of the alternate address space was introduced on - * SPARC). To correctly copy out the instruction we must use a block store - * that doesn't allocate in the D$ and ensures synchronization with the I$; - * see dtrace_blksuword32() for the implementation (this function uses - * ASI_BLK_COMMIT_S to write a block through the secondary ASI in the manner - * described). Refer to the UltraSPARC I/II manual for details on the - * ASI_BLK_COMMIT_S ASI. - * - * - * Return Subtleties - * - * When we're firing a return probe we need to expose the value returned by - * the function being traced. Since the function can set the return value - * in its last instruction, we need to fire the return probe only _after_ - * the effects of the instruction are apparent. For instructions that we - * emulate, we can call dtrace_probe() after we've performed the emulation; - * for instructions that we execute after we return to user-land, we set - * %pc to the instruction we copied out (as described above) and set %npc - * to a trap instruction stashed in the ulwp_t structure. After the traced - * instruction is executed, the trap instruction returns control to the - * kernel where we can fire the return probe. - * - * This need for a second trap in cases where we execute the traced - * instruction makes it all the more important to emulate the most common - * instructions to avoid the second trip in and out of the kernel. - * - * - * Making it Fast - * - * Since copying out an instruction is neither simple nor inexpensive for the - * CPU, we should attempt to avoid doing it in as many cases as possible. - * Since function entry and return are usually the most interesting probe - * sites, we attempt to tune the performance of the fasttrap provider around - * instructions typically in those places. - * - * Looking at a bunch of functions in libraries and executables reveals that - * most functions begin with either a save or a sethi (to setup a larger - * argument to the save) and end with a restore or an or (in the case of leaf - * functions). To try to improve performance, we emulate all of these - * instructions in the kernel. - * - * The save and restore instructions are a little tricky since they perform - * register window maniplulation. Rather than trying to tinker with the - * register windows from the kernel, we emulate the implicit add that takes - * place as part of those instructions and set the %pc to point to a simple - * save or restore we've hidden in the ulwp_t structure. If we're in a return - * probe so want to make it seem as though the tracepoint has been completely - * executed we need to remember that we've pulled this trick with restore and - * pull registers from the previous window (the one that we'll switch to once - * the simple store instruction is executed) rather than the current one. This - * is why in the case of emulating a restore we set the DTrace CPU flag - * CPU_DTRACE_FAKERESTORE before calling dtrace_probe() for the return probes - * (see fasttrap_return_common()). - */ +/*------------------------------------------------------------------*/ +/* P r o t o t y p e s */ +/*------------------------------------------------------------------*/ + +/*========================= End of Prototypes ======================*/ + +/*------------------------------------------------------------------*/ +/* G l o b a l V a r i a b l e s */ +/*------------------------------------------------------------------*/ -#define OP(x) ((x) >> 30) -#define OP2(x) (((x) >> 22) & 0x07) -#define OP3(x) (((x) >> 19) & 0x3f) -#define RCOND(x) (((x) >> 25) & 0x07) -#define COND(x) (((x) >> 25) & 0x0f) -#define A(x) (((x) >> 29) & 0x01) -#define I(x) (((x) >> 13) & 0x01) -#define RD(x) (((x) >> 25) & 0x1f) -#define RS1(x) (((x) >> 14) & 0x1f) -#define RS2(x) (((x) >> 0) & 0x1f) -#define CC(x) (((x) >> 20) & 0x03) -#define DISP16(x) ((((x) >> 6) & 0xc000) | ((x) & 0x3fff)) -#define DISP22(x) ((x) & 0x3fffff) -#define DISP19(x) ((x) & 0x7ffff) -#define DISP30(x) ((x) & 0x3fffffff) -#define SW_TRAP(x) ((x) & 0x7f) - -#define OP3_OR 0x02 -#define OP3_RD 0x28 -#define OP3_JMPL 0x38 -#define OP3_RETURN 0x39 -#define OP3_TCC 0x3a -#define OP3_SAVE 0x3c -#define OP3_RESTORE 0x3d - -#define OP3_PREFETCH 0x2d -#define OP3_CASA 0x3c -#define OP3_PREFETCHA 0x3d -#define OP3_CASXA 0x3e +/*====================== End of Global Variables ===================*/ -#define OP2_ILLTRAP 0x0 -#define OP2_BPcc 0x1 -#define OP2_Bicc 0x2 -#define OP2_BPr 0x3 -#define OP2_SETHI 0x4 -#define OP2_FBPfcc 0x5 -#define OP2_FBfcc 0x6 - -#define R_G0 0 -#define R_O0 8 -#define R_SP 14 -#define R_I0 24 -#define R_I1 25 -#define R_I2 26 -#define R_I3 27 - -/* - * Check the comment in fasttrap.h when changing these offsets or adding - * new instructions. - */ -#define FASTTRAP_OFF_SAVE 64 -#define FASTTRAP_OFF_RESTORE 68 -#define FASTTRAP_OFF_FTRET 72 -#define FASTTRAP_OFF_RETURN 76 - -#define BREAKPOINT_INSTR 0x91d02001 /* ta 1 */ - -/* - * Tunable to let users turn off the fancy save instruction optimization. - * If a program is non-ABI compliant, there's a possibility that the save - * instruction optimization could cause an error. - */ -int fasttrap_optimize_save = 1; +/*------------------------------------------------------------------*/ +/* */ +/* Name - fasttrap_anarg. */ +/* */ +/* Function - Retrieve an argument from the stack. */ +/* */ +/*------------------------------------------------------------------*/ static uint64_t fasttrap_anarg(struct regs *rp, int argno) @@ -204,7 +145,7 @@ uint64_t value; if (argno < 6) - return ((&rp->r_o0)[argno]); + return ((&rp->r_g2)[argno]); if (curproc->p_model == DATAMODEL_NATIVE) { struct frame *fr = (struct frame *)(rp->r_sp + STACK_BIAS); @@ -225,20 +166,16 @@ return (value); } -static ulong_t fasttrap_getreg(struct regs *, uint_t); -static void fasttrap_putreg(struct regs *, uint_t, ulong_t); + +/*========================= End of Function ========================*/ -int -fasttrap_probe(struct regs *rp) -{ - dtrace_probe(fasttrap_probe_id, - rp->r_o0, rp->r_o1, rp->r_o2, rp->r_o3, rp->r_o4); - - rp->r_pc = rp->r_npc; - rp->r_npc = rp->r_pc + 4; - - return (0); -} +/*------------------------------------------------------------------*/ +/* */ +/* Name - fasttrap_usdt_args. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ static void fasttrap_usdt_args(fasttrap_probe_t *probe, struct regs *rp, int argc, @@ -247,14 +184,14 @@ int i, x, cap = MIN(argc, probe->ftp_nargs); if (curproc->p_model == DATAMODEL_NATIVE) { - struct frame *fr = (struct frame *)(rp->r_sp + STACK_BIAS); + struct frame *fr = (struct frame *)rp->r_sp; uintptr_t v; for (i = 0; i < cap; i++) { x = probe->ftp_argmap[i]; - if (x < 6) - argv[i] = (&rp->r_o0)[x]; + if (x < 5) + argv[i] = (&rp->r_g2)[x]; else if (fasttrap_fulword(&fr->fr_argd[x], &v) != 0) argv[i] = 0; } @@ -266,8 +203,8 @@ for (i = 0; i < cap; i++) { x = probe->ftp_argmap[i]; - if (x < 6) - argv[i] = (&rp->r_o0)[x]; + if (x < 5) + argv[i] = (&rp->r_g2)[x]; else if (fasttrap_fuword32(&fr->fr_argd[x], &v) != 0) argv[i] = 0; } @@ -278,15 +215,28 @@ } } + +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - fasttrap_return_common. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + static void -fasttrap_return_common(struct regs *rp, uintptr_t pc, pid_t pid, - uint_t fake_restore) +fasttrap_return_common(struct regs *rp, uintptr_t pc, pid_t pid) { fasttrap_tracepoint_t *tp; fasttrap_bucket_t *bucket; fasttrap_id_t *id; kmutex_t *pid_mtx; dtrace_icookie_t cookie; + kthread_t *thrp = curthread; + proc_t *p = curproc; + uint8_t *scratch; pid_mtx = &cpu_core[CPU->cpu_id].cpuc_pid_lock; mutex_enter(pid_mtx); @@ -294,7 +244,7 @@ for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) { if (pid == tp->ftt_pid && pc == tp->ftt_pc && - !tp->ftt_proc->ftpc_defunct) + tp->ftt_proc->ftpc_acount != 0) break; } @@ -308,82 +258,56 @@ return; } - for (id = tp->ftt_retids; id != NULL; id = id->fti_next) { - fasttrap_probe_t *probe = id->fti_probe; - - if (probe->ftp_type == DTFTP_POST_OFFSETS) { - if (probe->ftp_argmap == NULL) { - dtrace_probe(probe->ftp_id, rp->r_o0, rp->r_o1, - rp->r_o2, rp->r_o3, rp->r_o4); - } else { - uintptr_t t[5]; - - fasttrap_usdt_args(probe, rp, - sizeof (t) / sizeof (t[0]), t); + if (p->p_model == DATAMODEL_LP64) { + scratch = (uint8_t *)((uintptr_t) rp->r_a0 << 32 | rp->r_a1); + } else { + scratch = (uint8_t *) rp->r_a0; + } - dtrace_probe(probe->ftp_id, t[0], t[1], - t[2], t[3], t[4]); - } - continue; - } + thrp->t_dtrace_pc = pc; + thrp->t_dtrace_scrpc = (uintptr_t) scratch; + thrp->t_dtrace_npc = pc + tp->ftt_isize; + thrp->t_dtrace_astpc = (uintptr_t) scratch + tp->ftt_isize; + thrp->t_dtrace_on = 1; - /* - * If this is only a possible return point, we must - * be looking at a potential tail call in leaf context. - * If the %npc is still within this function, then we - * must have misidentified a jmpl as a tail-call when it - * is, in fact, part of a jump table. It would be nice to - * remove this tracepoint, but this is neither the time - * nor the place. - */ - if ((tp->ftt_flags & FASTTRAP_F_RETMAYBE) && - rp->r_npc - probe->ftp_faddr < probe->ftp_fsize) - continue; + if (fasttrap_copyout(scratch, (char *)tp->ftt_instr, tp->ftt_size)) { + fasttrap_sigtrap(p, thrp, pc); + rp->r_pc = pc; + } else { - /* - * It's possible for a function to branch to the delay slot - * of an instruction that we've identified as a return site. - * We can dectect this spurious return probe activation by - * observing that in this case %npc will be %pc + 4 and %npc - * will be inside the current function (unless the user is - * doing _crazy_ instruction picking in which case there's - * very little we can do). The second check is important - * in case the last instructions of a function make a tail- - * call to the function located immediately subsequent. - */ - if (rp->r_npc == rp->r_pc + 4 && - rp->r_npc - probe->ftp_faddr < probe->ftp_fsize) - continue; - - /* - * The first argument is the offset of return tracepoint - * in the function; the remaining arguments are the return - * values. - * - * If fake_restore is set, we need to pull the return values - * out of the %i's rather than the %o's -- a little trickier. - */ - if (!fake_restore) { - dtrace_probe(probe->ftp_id, pc - probe->ftp_faddr, - rp->r_o0, rp->r_o1, rp->r_o2, rp->r_o3); + if (tp->ftt_retids != NULL) { + thrp->t_dtrace_step = 1; + thrp->t_dtrace_ret = 1; + rp->r_pc = thrp->t_dtrace_astpc; } else { - uintptr_t arg0 = fasttrap_getreg(rp, R_I0); - uintptr_t arg1 = fasttrap_getreg(rp, R_I1); - uintptr_t arg2 = fasttrap_getreg(rp, R_I2); - uintptr_t arg3 = fasttrap_getreg(rp, R_I3); - - cookie = dtrace_interrupt_disable(); - DTRACE_CPUFLAG_SET(CPU_DTRACE_FAKERESTORE); - dtrace_probe(probe->ftp_id, pc - probe->ftp_faddr, - arg0, arg1, arg2, arg3); - DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_FAKERESTORE); - dtrace_interrupt_enable(cookie); + rp->r_pc = thrp->t_dtrace_scrpc; + } + + for (id = tp->ftt_retids; id != NULL; id = id->fti_next) { + /* + * The first argument is the offset of return tracepoint + * in the function; the remaining arguments are the return + * values. + */ + dtrace_probe(id->fti_probe->ftp_id, + pc - id->fti_probe->ftp_faddr, + rp->r_g2, rp->r_g3, rp->r_g4, rp->r_g5); } } mutex_exit(pid_mtx); } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - fasttrap_pid_probe. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + int fasttrap_pid_probe(struct regs *rp) { @@ -391,13 +315,12 @@ fasttrap_tracepoint_t *tp, tp_local; fasttrap_id_t *id; pid_t pid; - uintptr_t pc = rp->r_pc; - uintptr_t npc = rp->r_npc; + uintptr_t pc = rp->r_pc; uintptr_t orig_pc = pc; fasttrap_bucket_t *bucket; kmutex_t *pid_mtx; - uint_t fake_restore = 0; dtrace_icookie_t cookie; + kthread_t *thrp = curthread; /* * It's possible that a user (in a veritable orgy of bad planning) @@ -405,20 +328,17 @@ * return probe fasttrap. In this case we need to kill the process * since it's in a unrecoverable state. */ - if (curthread->t_dtrace_step) { - ASSERT(curthread->t_dtrace_on); - fasttrap_sigtrap(p, curthread, pc); + if (thrp->t_dtrace_step) { + ASSERT(thrp->t_dtrace_on); + fasttrap_sigtrap(p, thrp, pc); return (0); } /* * Clear all user tracing flags. */ - curthread->t_dtrace_ft = 0; - curthread->t_dtrace_pc = 0; - curthread->t_dtrace_npc = 0; - curthread->t_dtrace_scrpc = 0; - curthread->t_dtrace_astpc = 0; + thrp->t_dtrace_ft = 0; + thrp->t_dtrace_pc = 0; /* * Treat a child created by a call to vfork(2) as if it were its @@ -429,17 +349,17 @@ p = p->p_parent; } - pid = p->p_pid; + pid = p->p_pid; pid_mtx = &cpu_core[CPU->cpu_id].cpuc_pid_lock; mutex_enter(pid_mtx); - bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)]; + bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)]; /* * Lookup the tracepoint that the process just hit. */ for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) { if (pid == tp->ftt_pid && pc == tp->ftt_pc && - !tp->ftt_proc->ftpc_defunct) + tp->ftt_proc->ftpc_acount != 0) break; } @@ -460,12 +380,12 @@ * We note that this was an entry probe to help ustack() find * the first caller. */ - if ((isentry = (probe->ftp_type == DTFTP_ENTRY)) != 0) { + if ((isentry = (id->fti_ptype == DTFTP_ENTRY)) != 0) { cookie = dtrace_interrupt_disable(); DTRACE_CPUFLAG_SET(CPU_DTRACE_ENTRY); } - dtrace_probe(probe->ftp_id, rp->r_o0, rp->r_o1, rp->r_o2, - rp->r_o3, rp->r_o4); + dtrace_probe(probe->ftp_id, rp->r_g2, rp->r_g3, rp->r_g4, + rp->r_g5, rp->r_g6); if (isentry) { DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_ENTRY); dtrace_interrupt_enable(cookie); @@ -482,497 +402,41 @@ tp = &tp_local; /* - * We emulate certain types of instructions do ensure correctness - * (in the case of position dependent instructions) or optimize - * common cases. The rest we have the thread execute back in user- - * land. - */ - switch (tp->ftt_type) { - case FASTTRAP_T_SAVE: - { - int32_t imm; - - /* - * This an optimization to let us handle function entry - * probes more efficiently. Many functions begin with a save - * instruction that follows the pattern: - * save %sp, <imm>, %sp - * - * Meanwhile, we've stashed the instruction: - * save %g1, %g0, %sp - * - * off of %g7, so all we have to do is stick the right value - * into %g1 and reset %pc to point to the instruction we've - * cleverly hidden (%npc should not be touched). - */ - - imm = tp->ftt_instr << 19; - imm >>= 19; - rp->r_g1 = rp->r_sp + imm; - pc = rp->r_g7 + FASTTRAP_OFF_SAVE; - break; - } - - case FASTTRAP_T_RESTORE: - { - ulong_t value; - uint_t rd; - - /* - * This is an optimization to let us handle function - * return probes more efficiently. Most non-leaf functions - * end with the sequence: - * ret - * restore <reg>, <reg_or_imm>, %oX - * - * We've stashed the instruction: - * restore %g0, %g0, %g0 - * - * off of %g7 so we just need to place the correct value - * in the right %i register (since after our fake-o - * restore, the %i's will become the %o's) and set the %pc - * to point to our hidden restore. We also set fake_restore to - * let fasttrap_return_common() know that it will find the - * return values in the %i's rather than the %o's. - */ - - if (I(tp->ftt_instr)) { - int32_t imm; - - imm = tp->ftt_instr << 19; - imm >>= 19; - value = fasttrap_getreg(rp, RS1(tp->ftt_instr)) + imm; - } else { - value = fasttrap_getreg(rp, RS1(tp->ftt_instr)) + - fasttrap_getreg(rp, RS2(tp->ftt_instr)); - } - - /* - * Convert %o's to %i's; leave %g's as they are. - */ - rd = RD(tp->ftt_instr); - fasttrap_putreg(rp, ((rd & 0x18) == 0x8) ? rd + 16 : rd, value); - - pc = rp->r_g7 + FASTTRAP_OFF_RESTORE; - fake_restore = 1; - break; - } - - case FASTTRAP_T_RETURN: - { - uintptr_t target; - - /* - * A return instruction is like a jmpl (without the link - * part) that executes an implicit restore. We've stashed - * the instruction: - * return %o0 - * - * off of %g7 so we just need to place the target in %o0 - * and set the %pc to point to the stashed return instruction. - * We use %o0 since that register disappears after the return - * executes, erasing any evidence of this tampering. - */ - if (I(tp->ftt_instr)) { - int32_t imm; - - imm = tp->ftt_instr << 19; - imm >>= 19; - target = fasttrap_getreg(rp, RS1(tp->ftt_instr)) + imm; - } else { - target = fasttrap_getreg(rp, RS1(tp->ftt_instr)) + - fasttrap_getreg(rp, RS2(tp->ftt_instr)); - } - - fasttrap_putreg(rp, R_O0, target); - - pc = rp->r_g7 + FASTTRAP_OFF_RETURN; - fake_restore = 1; - break; - } - - case FASTTRAP_T_OR: - { - ulong_t value; - - if (I(tp->ftt_instr)) { - int32_t imm; - - imm = tp->ftt_instr << 19; - imm >>= 19; - value = fasttrap_getreg(rp, RS1(tp->ftt_instr)) | imm; - } else { - value = fasttrap_getreg(rp, RS1(tp->ftt_instr)) | - fasttrap_getreg(rp, RS2(tp->ftt_instr)); - } - - fasttrap_putreg(rp, RD(tp->ftt_instr), value); - pc = rp->r_npc; - npc = pc + 4; - break; - } - - case FASTTRAP_T_SETHI: - if (RD(tp->ftt_instr) != R_G0) { - uint32_t imm32 = tp->ftt_instr << 10; - fasttrap_putreg(rp, RD(tp->ftt_instr), (ulong_t)imm32); - } - pc = rp->r_npc; - npc = pc + 4; - break; - - case FASTTRAP_T_CCR: - { - uint_t c, v, z, n, taken; - uint_t ccr = rp->r_tstate >> TSTATE_CCR_SHIFT; - - if (tp->ftt_cc != 0) - ccr >>= 4; - - c = (ccr >> 0) & 1; - v = (ccr >> 1) & 1; - z = (ccr >> 2) & 1; - n = (ccr >> 3) & 1; - - switch (tp->ftt_code) { - case 0x0: /* BN */ - taken = 0; break; - case 0x1: /* BE */ - taken = z; break; - case 0x2: /* BLE */ - taken = z | (n ^ v); break; - case 0x3: /* BL */ - taken = n ^ v; break; - case 0x4: /* BLEU */ - taken = c | z; break; - case 0x5: /* BCS (BLU) */ - taken = c; break; - case 0x6: /* BNEG */ - taken = n; break; - case 0x7: /* BVS */ - taken = v; break; - case 0x8: /* BA */ - /* - * We handle the BA case differently since the annul - * bit means something slightly different. - */ - panic("fasttrap: mishandled a branch"); - taken = 1; break; - case 0x9: /* BNE */ - taken = ~z; break; - case 0xa: /* BG */ - taken = ~(z | (n ^ v)); break; - case 0xb: /* BGE */ - taken = ~(n ^ v); break; - case 0xc: /* BGU */ - taken = ~(c | z); break; - case 0xd: /* BCC (BGEU) */ - taken = ~c; break; - case 0xe: /* BPOS */ - taken = ~n; break; - case 0xf: /* BVC */ - taken = ~v; break; - } - - if (taken & 1) { - pc = rp->r_npc; - npc = tp->ftt_dest; - } else if (tp->ftt_flags & FASTTRAP_F_ANNUL) { - /* - * Untaken annulled branches don't execute the - * instruction in the delay slot. - */ - pc = rp->r_npc + 4; - npc = pc + 4; - } else { - pc = rp->r_npc; - npc = pc + 4; - } - break; - } - - case FASTTRAP_T_FCC: - { - uint_t fcc; - uint_t taken; - uint64_t fsr; - - dtrace_getfsr(&fsr); - - if (tp->ftt_cc == 0) { - fcc = (fsr >> 10) & 0x3; - } else { - uint_t shift; - ASSERT(tp->ftt_cc <= 3); - shift = 30 + tp->ftt_cc * 2; - fcc = (fsr >> shift) & 0x3; - } - - switch (tp->ftt_code) { - case 0x0: /* FBN */ - taken = (1 << fcc) & (0|0|0|0); break; - case 0x1: /* FBNE */ - taken = (1 << fcc) & (8|4|2|0); break; - case 0x2: /* FBLG */ - taken = (1 << fcc) & (0|4|2|0); break; - case 0x3: /* FBUL */ - taken = (1 << fcc) & (8|0|2|0); break; - case 0x4: /* FBL */ - taken = (1 << fcc) & (0|0|2|0); break; - case 0x5: /* FBUG */ - taken = (1 << fcc) & (8|4|0|0); break; - case 0x6: /* FBG */ - taken = (1 << fcc) & (0|4|0|0); break; - case 0x7: /* FBU */ - taken = (1 << fcc) & (8|0|0|0); break; - case 0x8: /* FBA */ - /* - * We handle the FBA case differently since the annul - * bit means something slightly different. - */ - panic("fasttrap: mishandled a branch"); - taken = (1 << fcc) & (8|4|2|1); break; - case 0x9: /* FBE */ - taken = (1 << fcc) & (0|0|0|1); break; - case 0xa: /* FBUE */ - taken = (1 << fcc) & (8|0|0|1); break; - case 0xb: /* FBGE */ - taken = (1 << fcc) & (0|4|0|1); break; - case 0xc: /* FBUGE */ - taken = (1 << fcc) & (8|4|0|1); break; - case 0xd: /* FBLE */ - taken = (1 << fcc) & (0|0|2|1); break; - case 0xe: /* FBULE */ - taken = (1 << fcc) & (8|0|2|1); break; - case 0xf: /* FBO */ - taken = (1 << fcc) & (0|4|2|1); break; - } - - if (taken) { - pc = rp->r_npc; - npc = tp->ftt_dest; - } else if (tp->ftt_flags & FASTTRAP_F_ANNUL) { - /* - * Untaken annulled branches don't execute the - * instruction in the delay slot. - */ - pc = rp->r_npc + 4; - npc = pc + 4; - } else { - pc = rp->r_npc; - npc = pc + 4; - } - break; - } - - case FASTTRAP_T_REG: - { - uint64_t value; - uint_t taken; - uint_t reg = RS1(tp->ftt_instr); - - /* - * An ILP32 process shouldn't be using a branch predicated on - * an %i or an %l since it would violate the ABI. It's a - * violation of the ABI because we can't ensure deterministic - * behavior. We should have identified this case when we - * enabled the probe. - */ - ASSERT(p->p_model == DATAMODEL_LP64 || reg < 16); - - value = fasttrap_getreg(rp, reg); - - switch (tp->ftt_code) { - case 0x1: /* BRZ */ - taken = (value == 0); break; - case 0x2: /* BRLEZ */ - taken = (value <= 0); break; - case 0x3: /* BRLZ */ - taken = (value < 0); break; - case 0x5: /* BRNZ */ - taken = (value != 0); break; - case 0x6: /* BRGZ */ - taken = (value > 0); break; - case 0x7: /* BRGEZ */ - taken = (value <= 0); break; - default: - case 0x0: - case 0x4: - panic("fasttrap: mishandled a branch"); - } - - if (taken) { - pc = rp->r_npc; - npc = tp->ftt_dest; - } else if (tp->ftt_flags & FASTTRAP_F_ANNUL) { - /* - * Untaken annulled branches don't execute the - * instruction in the delay slot. - */ - pc = rp->r_npc + 4; - npc = pc + 4; - } else { - pc = rp->r_npc; - npc = pc + 4; - } - break; - } - - case FASTTRAP_T_ALWAYS: - /* - * BAs, BA,As... - */ - - if (tp->ftt_flags & FASTTRAP_F_ANNUL) { - /* - * Annulled branch always instructions never execute - * the instruction in the delay slot. - */ - pc = tp->ftt_dest; - npc = tp->ftt_dest + 4; - } else { - pc = rp->r_npc; - npc = tp->ftt_dest; - } - break; - - case FASTTRAP_T_RDPC: - fasttrap_putreg(rp, RD(tp->ftt_instr), rp->r_pc); - pc = rp->r_npc; - npc = pc + 4; - break; - - case FASTTRAP_T_CALL: - /* - * It's a call _and_ link remember... - */ - rp->r_o7 = rp->r_pc; - pc = rp->r_npc; - npc = tp->ftt_dest; - break; - - case FASTTRAP_T_JMPL: - pc = rp->r_npc; - - if (I(tp->ftt_instr)) { - uint_t rs1 = RS1(tp->ftt_instr); - int32_t imm; - - imm = tp->ftt_instr << 19; - imm >>= 19; - npc = fasttrap_getreg(rp, rs1) + imm; - } else { - uint_t rs1 = RS1(tp->ftt_instr); - uint_t rs2 = RS2(tp->ftt_instr); - - npc = fasttrap_getreg(rp, rs1) + - fasttrap_getreg(rp, rs2); - } - - /* - * Do the link part of the jump-and-link instruction. - */ - fasttrap_putreg(rp, RD(tp->ftt_instr), rp->r_pc); - - break; - - case FASTTRAP_T_COMMON: - { - curthread->t_dtrace_scrpc = rp->r_g7; - curthread->t_dtrace_astpc = rp->r_g7 + FASTTRAP_OFF_FTRET; - - /* - * Copy the instruction to a reserved location in the - * user-land thread structure, then set the PC to that - * location and leave the NPC alone. We take pains to ensure - * consistency in the instruction stream (See SPARC - * Architecture Manual Version 9, sections 8.4.7, A.20, and - * H.1.6; UltraSPARC I/II User's Manual, sections 3.1.1.1, - * and 13.6.4) by using the ASI ASI_BLK_COMMIT_S to copy the - * instruction into the user's address space without - * bypassing the I$. There's no AS_USER version of this ASI - * (as exist for other ASIs) so we use the lofault - * mechanism to catch faults. - */ - if (dtrace_blksuword32(rp->r_g7, &tp->ftt_instr, 1) == -1) { - /* - * If the copyout fails, then the process's state - * is not consistent (the effects of the traced - * instruction will never be seen). This process - * cannot be allowed to continue execution. - */ - fasttrap_sigtrap(curproc, curthread, pc); - return (0); - } - - curthread->t_dtrace_pc = pc; - curthread->t_dtrace_npc = npc; - curthread->t_dtrace_on = 1; - - pc = curthread->t_dtrace_scrpc; - - if (tp->ftt_retids != NULL) { - curthread->t_dtrace_step = 1; - curthread->t_dtrace_ret = 1; - npc = curthread->t_dtrace_astpc; - } - break; - } - - default: - panic("fasttrap: mishandled an instruction"); - } - - /* - * This bit me in the ass a couple of times, so lets toss this - * in as a cursory sanity check. - */ - ASSERT(pc != rp->r_g7 + 4); - ASSERT(pc != rp->r_g7 + 8); - - /* * If there were no return probes when we first found the tracepoint, * we should feel no obligation to honor any return probes that were * subsequently enabled -- they'll just have to wait until the next * time around. */ if (tp->ftt_retids != NULL) { - /* - * We need to wait until the results of the instruction are - * apparent before invoking any return probes. If this - * instruction was emulated we can just call - * fasttrap_return_common(); if it needs to be executed, we - * need to wait until we return to the kernel. - */ - if (tp->ftt_type != FASTTRAP_T_COMMON) { - fasttrap_return_common(rp, orig_pc, pid, fake_restore); - } else { - ASSERT(curthread->t_dtrace_ret != 0); - ASSERT(curthread->t_dtrace_pc == orig_pc); - ASSERT(curthread->t_dtrace_scrpc == rp->r_g7); - ASSERT(npc == curthread->t_dtrace_astpc); - } + ASSERT(thrp->t_dtrace_ret != 0); + ASSERT(thrp->t_dtrace_pc == orig_pc); } ASSERT(pc != 0); rp->r_pc = pc; - rp->r_npc = npc; return (0); } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - fasttrap_return_probe. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + int fasttrap_return_probe(struct regs *rp) { - proc_t *p = ttoproc(curthread); pid_t pid; - uintptr_t pc = curthread->t_dtrace_pc; - uintptr_t npc = curthread->t_dtrace_npc; + kthread_t *thrp = curthread; + proc_t *p = ttoproc(thrp); + uintptr_t pc = thrp->t_dtrace_pc; - curthread->t_dtrace_pc = 0; - curthread->t_dtrace_npc = 0; - curthread->t_dtrace_scrpc = 0; - curthread->t_dtrace_astpc = 0; + thrp->t_dtrace_pc = 0; /* * Treat a child created by a call to vfork(2) as if it were its @@ -984,33 +448,52 @@ } /* - * We set the %pc and %npc to their values when the traced + * We set the %pc to its value when the traced * instruction was initially executed so that it appears to * dtrace_probe() that we're on the original instruction, and so that * the user can't easily detect our complex web of lies. - * dtrace_return_probe() (our caller) will correctly set %pc and %npc + * dtrace_return_probe() (our caller) will correctly set %pc * after we return. */ rp->r_pc = pc; - rp->r_npc = npc; pid = p->p_pid; - fasttrap_return_common(rp, pc, pid, 0); + fasttrap_return_common(rp, pc, pid); return (0); } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - fasttrap_tracepoint_install. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + int fasttrap_tracepoint_install(proc_t *p, fasttrap_tracepoint_t *tp) { fasttrap_instr_t instr = FASTTRAP_INSTR; - if (uwrite(p, &instr, 4, tp->ftt_pc) != 0) + if (uwrite(p, &instr, sizeof(instr), tp->ftt_pc) != 0) return (-1); return (0); } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - fasttrap_tracepoint_remove. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + int fasttrap_tracepoint_remove(proc_t *p, fasttrap_tracepoint_t *tp) { @@ -1020,22 +503,36 @@ * Distinguish between read or write failures and a changed * instruction. */ - if (uread(p, &instr, 4, tp->ftt_pc) != 0) + if (uread(p, &instr, sizeof(instr), tp->ftt_pc) != 0) return (0); - if (instr != FASTTRAP_INSTR && instr != BREAKPOINT_INSTR) + if (instr != FASTTRAP_INSTR) return (0); - if (uwrite(p, &tp->ftt_instr, 4, tp->ftt_pc) != 0) + if (uwrite(p, &tp->ftt_instr, sizeof(instr), tp->ftt_pc) != 0) return (-1); return (0); } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - fasttrap_tracepoint_init. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + int -fasttrap_tracepoint_init(proc_t *p, fasttrap_probe_t *probe, - fasttrap_tracepoint_t *tp, uintptr_t pc) +fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, uintptr_t pc, + fasttrap_probe_type_t type) { - uint32_t instr; + uint8_t instr[FASTTRAP_MAX_INSTR_SIZE], + fmt; + size_t len = FASTTRAP_MAX_INSTR_SIZE, + first = MIN(len, PAGESIZE - (pc & PAGEOFFSET)); int32_t disp; + RIL2_t *retl; /* * Read the instruction at the given address out of the process's @@ -1043,274 +540,167 @@ * changing this instruction before we overwrite it with our trap * instruction since P_PR_LOCK is set. */ - if (uread(p, &instr, 4, pc) != 0) + if (uread(p, &instr[0], first, pc) != 0) return (-1); + if (len > first && + uread(p, &instr[first], len - first, pc + first) != 0) { + bzero(&instr[first], len - first); + len = first; + } + + tp->ftt_isize = dtrace_getfmtlen(instr, &fmt); + bcopy(instr, tp->ftt_instr, tp->ftt_size); + + /* + * pc-relative instructions need further processing. For 32-bit + * offsets then we can simply calculate a new offset based on where + * our ftt_instr lives, for 16-bit offsets we need to create a simple + * trampoline, we'll let the branch jump over our return instruction + * to a 32-bit offset jump which will take us to the desired target. + * + * For example: + * a: bras %r14,x + * becomes: + * bras %r14,y + * jg a + * y: jg x + */ + /* - * Decode the instruction to fill in the probe flags. We can have - * the process execute most instructions on its own using a pc/npc - * trick, but pc-relative control transfer present a problem since - * we're relocating the instruction. We emulate these instructions - * in the kernel. We assume a default type and over-write that as - * needed. - * - * pc-relative instructions must be emulated for correctness; - * other instructions (which represent a large set of commonly traced - * instructions) are emulated or otherwise optimized for performance. + * Create the return jump */ - tp->ftt_type = FASTTRAP_T_COMMON; - if (OP(instr) == 1) { - /* - * Call instructions. - */ - tp->ftt_type = FASTTRAP_T_CALL; - disp = DISP30(instr) << 2; - tp->ftt_dest = pc + (intptr_t)disp; + retl = (RIL2_t *) (&tp->ftt_instr + tp->ftt_isize); + retl->op1 = JGOP1; + retl->m1 = UNC; + retl->op2 = JGOP2; + retl->i2 = ((intptr_t) retl - pc + tp->ftt_isize) / 2; - } else if (OP(instr) == 0) { - /* - * Branch instructions. - * - * Unconditional branches need careful attention when they're - * annulled: annulled unconditional branches never execute - * the instruction in the delay slot. - */ - switch (OP2(instr)) { - case OP2_ILLTRAP: - case 0x7: - /* - * The compiler may place an illtrap after a call to - * a function that returns a structure. In the case of - * a returned structure, the compiler places an illtrap - * whose const22 field is the size of the returned - * structure immediately following the delay slot of - * the call. To stay out of the way, we refuse to - * place tracepoints on top of illtrap instructions. - * - * This is one of the dumbest architectural decisions - * I've ever had to work around. - * - * We also identify the only illegal op2 value (See - * SPARC Architecture Manual Version 9, E.2 table 31). - */ - return (-1); + tp->ftt_size = tp->ftt_isize + sizeof(retl); - case OP2_BPcc: - if (COND(instr) == 8) { - tp->ftt_type = FASTTRAP_T_ALWAYS; - } else { - /* - * Check for an illegal instruction. - */ - if (CC(instr) & 1) - return (-1); - tp->ftt_type = FASTTRAP_T_CCR; - tp->ftt_cc = CC(instr); - tp->ftt_code = COND(instr); - } - - if (A(instr) != 0) - tp->ftt_flags |= FASTTRAP_F_ANNUL; - - disp = DISP19(instr); - disp <<= 13; - disp >>= 11; - tp->ftt_dest = pc + (intptr_t)disp; - break; + /* + * If this instruction has an operand that is relative to PC + * then more processing is required + */ + if (fmt & IFMT_PCREL) { + intptr_t addr; - case OP2_Bicc: - if (COND(instr) == 8) { - tp->ftt_type = FASTTRAP_T_ALWAYS; - } else { - tp->ftt_type = FASTTRAP_T_CCR; - tp->ftt_cc = 0; - tp->ftt_code = COND(instr); - } - - if (A(instr) != 0) - tp->ftt_flags |= FASTTRAP_F_ANNUL; - - disp = DISP22(instr); - disp <<= 10; - disp >>= 8; - tp->ftt_dest = pc + (intptr_t)disp; - break; - - case OP2_BPr: - /* - * Check for an illegal instruction. + switch((fmt & ~IFMT_PCREL)) { + case IFMT_RIE1 : { + /* + * For these instructions we are going to get the + * jump to go to a trampoline that will jump to + * the actual target */ - if ((RCOND(instr) & 3) == 0) - return (-1); + RIE1_t *rie1 = (RIE1_t *) &tp->ftt_instr; + RIL2_t *ril2 = (RIL2_t *) (retl + 1); + intptr_t nxt = (intptr_t) (ril2 + 1); /* - * It's a violation of the v8plus ABI to use a - * register-predicated branch in a 32-bit app if - * the register used is an %l or an %i (%gs and %os - * are legit because they're not saved to the stack - * in 32-bit words when we take a trap). + * 1. Determine address of real target + * 2. Change target to be our jump instruction + * 3. Construct a jump following the return jump */ - if (p->p_model == DATAMODEL_ILP32 && RS1(instr) >= 16) - return (-1); + addr = (intptr_t) (rie1->i2 * 2 + pc); + rie1->i2 = ((intptr_t) ((intptr_t) rie1 - nxt)) / 2; + ril2->op1 = JGOP1; + ril2->m1 = UNC; + ril2->op2 = JGOP2; + ril2->i2 = ((intptr_t) &tp->ftt_instr - addr) / 2; - tp->ftt_type = FASTTRAP_T_REG; - if (A(instr) != 0) - tp->ftt_flags |= FASTTRAP_F_ANNUL; - disp = DISP16(instr); - disp <<= 16; - disp >>= 14; - tp->ftt_dest = pc + (intptr_t)disp; - tp->ftt_code = RCOND(instr); + tp->ftt_size += sizeof(ril2); break; - - case OP2_SETHI: - tp->ftt_type = FASTTRAP_T_SETHI; - break; + } + case IFMT_RIE2 : { + RIE2_t *rie2 = (RIE2_t *) &tp->ftt_instr; + RIL2_t *ril2 = (RIL2_t *) (retl + 1); + intptr_t nxt = (intptr_t) (ril2 + 1); - case OP2_FBPfcc: - if (COND(instr) == 8) { - tp->ftt_type = FASTTRAP_T_ALWAYS; - } else { - tp->ftt_type = FASTTRAP_T_FCC; - tp->ftt_cc = CC(instr); - tp->ftt_code = COND(instr); - } + addr = (intptr_t) (rie2->i4 * 2 + pc); + rie2->i4 = ((intptr_t) ((intptr_t) rie2 - nxt)) / 2; + ril2->op1 = JGOP1; + ril2->m1 = UNC; + ril2->op2 = JGOP2; + ril2->i2 = ((intptr_t) &tp->ftt_instr - addr) / 2; - if (A(instr) != 0) - tp->ftt_flags |= FASTTRAP_F_ANNUL; - - disp = DISP19(instr); - disp <<= 13; - disp >>= 11; - tp->ftt_dest = pc + (intptr_t)disp; + tp->ftt_size += sizeof(ril2); break; + } + case IFMT_RSI : { + RSI_t *rsi = (RSI_t *) &tp->ftt_instr; + RIL2_t *ril2 = (RIL2_t *) (retl + 1); + intptr_t nxt = (intptr_t) (ril2 + 1); - case OP2_FBfcc: - if (COND(instr) == 8) { - tp->ftt_type = FASTTRAP_T_ALWAYS; - } else { - tp->ftt_type = FASTTRAP_T_FCC; - tp->ftt_cc = 0; - tp->ftt_code = COND(instr); - } + addr = (intptr_t) (rsi->i2 * 2 + pc); + rsi->i2 = ((intptr_t) ((intptr_t) rsi - nxt)) / 2; + ril2->op1 = JGOP1; + ril2->m1 = UNC; + ril2->op2 = JGOP2; + ril2->i2 = ((intptr_t) &tp->ftt_instr - addr) / 2; - if (A(instr) != 0) - tp->ftt_flags |= FASTTRAP_F_ANNUL; - - disp = DISP22(instr); - disp <<= 10; - disp >>= 8; - tp->ftt_dest = pc + (intptr_t)disp; + tp->ftt_size += sizeof(ril2); break; } - - } else if (OP(instr) == 2) { - switch (OP3(instr)) { - case OP3_RETURN: - tp->ftt_type = FASTTRAP_T_RETURN; - break; - - case OP3_JMPL: - tp->ftt_type = FASTTRAP_T_JMPL; - break; - - case OP3_RD: - if (RS1(instr) == 5) - tp->ftt_type = FASTTRAP_T_RDPC; - break; + case IFMT_RIL1 : { + RIL1_t *ril1 = (RIL1_t *) &tp->ftt_instr; - case OP3_SAVE: - /* - * We optimize for save instructions at function - * entry; see the comment in fasttrap_pid_probe() - * (near FASTTRAP_T_SAVE) for details. - */ - if (fasttrap_optimize_save != 0 && - probe->ftp_type == DTFTP_ENTRY && - I(instr) == 1 && RD(instr) == R_SP) - tp->ftt_type = FASTTRAP_T_SAVE; + addr = (intptr_t) (ril1->i2 * 2 + pc); + ril1->i2 = ((intptr_t) &tp->ftt_instr - addr) / 2; break; + } + case IFMT_RIL2 : { + RIL2_t *ril2 = (RIL2_t *) &tp->ftt_instr; - case OP3_RESTORE: - /* - * We optimize restore instructions at function - * return; see the comment in fasttrap_pid_probe() - * (near FASTTRAP_T_RESTORE) for details. - * - * rd must be an %o or %g register. - */ - if ((RD(instr) & 0x10) == 0) - tp->ftt_type = FASTTRAP_T_RESTORE; + addr = (intptr_t) (ril2->i2 * 2 + pc); + ril2->i2 = ((intptr_t) &tp->ftt_instr - addr) / 2; break; + } + case IFMT_RI1 : { + RI1_t *ri1 = (RI1_t *) &tp->ftt_instr; + RIL2_t *ril2 = (RIL2_t *) (retl + 1); + intptr_t nxt = (intptr_t) (ril2 + 1); - case OP3_OR: - /* - * A large proportion of instructions in the delay - * slot of retl instructions are or's so we emulate - * these downstairs as an optimization. - */ - tp->ftt_type = FASTTRAP_T_OR; - break; - - case OP3_TCC: - /* - * Breakpoint instructions are effectively position- - * dependent since the debugger uses the %pc value - * to lookup which breakpoint was executed. As a - * result, we can't actually instrument breakpoints. - */ - if (SW_TRAP(instr) == ST_BREAKPOINT) - return (-1); - break; + addr = (intptr_t) (ri1->i2 * 2 + pc); + ri1->i2 = ((intptr_t) ((intptr_t) ri1 - nxt)) / 2; + ril2->op1 = JGOP1; + ril2->m1 = UNC; + ril2->op2 = JGOP2; + ril2->i2 = ((intptr_t) &tp->ftt_instr - addr) / 2; - case 0x19: - case 0x1d: - case 0x29: - case 0x33: - case 0x3f: - /* - * Identify illegal instructions (See SPARC - * Architecture Manual Version 9, E.2 table 32). - */ - return (-1); + tp->ftt_size += sizeof(ril2); + break; } - } else if (OP(instr) == 3) { - uint32_t op3 = OP3(instr); + case IFMT_RI2 : { + RI2_t *ri2 = (RI2_t *) &tp->ftt_instr; + RIL2_t *ril2 = (RIL2_t *) (retl + 1); + intptr_t nxt = (intptr_t) (ril2 + 1); - /* - * Identify illegal instructions (See SPARC Architecture - * Manual Version 9, E.2 table 33). - */ - if ((op3 & 0x28) == 0x28) { - if (op3 != OP3_PREFETCH && op3 != OP3_CASA && - op3 != OP3_PREFETCHA && op3 != OP3_CASXA) - return (-1); - } else { - if ((op3 & 0x0f) == 0x0c || (op3 & 0x3b) == 0x31) - return (-1); + addr = (intptr_t) (ri2->i2 * 2 + pc); + ri2->i2 = ((intptr_t) ((intptr_t) ri2 - nxt)) / 2; + ril2->op1 = JGOP1; + ril2->m1 = UNC; + ril2->op2 = JGOP2; + ril2->i2 = ((intptr_t) &tp->ftt_instr - addr) / 2; + + tp->ftt_size += sizeof(ril2); + break; + } } } - tp->ftt_instr = instr; - - /* - * We don't know how this tracepoint is going to be used, but in case - * it's used as part of a function return probe, we need to indicate - * whether it's always a return site or only potentially a return - * site. If it's part of a return probe, it's always going to be a - * return from that function if it's a restore instruction or if - * the previous instruction was a return. If we could reliably - * distinguish jump tables from return sites, this wouldn't be - * necessary. - */ - if (tp->ftt_type != FASTTRAP_T_RESTORE && - (uread(p, &instr, 4, pc - sizeof (instr)) != 0 || - !(OP(instr) == 2 && OP3(instr) == OP3_RETURN))) - tp->ftt_flags |= FASTTRAP_F_RETMAYBE; - return (0); } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + /*ARGSUSED*/ uint64_t fasttrap_getarg(void *arg, dtrace_id_t id, void *parg, int argno, int aframes) @@ -1318,6 +708,16 @@ return (fasttrap_anarg(ttolwp(curthread)->lwp_regs, argno)); } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - fasttrap_usdt_getarg. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + /*ARGSUSED*/ uint64_t fasttrap_usdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, @@ -1326,216 +726,4 @@ return (fasttrap_anarg(ttolwp(curthread)->lwp_regs, argno)); } -static uint64_t fasttrap_getreg_fast_cnt; -static uint64_t fasttrap_getreg_mpcb_cnt; -static uint64_t fasttrap_getreg_slow_cnt; - -static ulong_t -fasttrap_getreg(struct regs *rp, uint_t reg) -{ - ulong_t value; - dtrace_icookie_t cookie; - struct machpcb *mpcb; - extern ulong_t dtrace_getreg_win(uint_t, uint_t); - - /* - * We have the %os and %gs in our struct regs, but if we need to - * snag a %l or %i we need to go scrounging around in the process's - * address space. - */ - if (reg == 0) - return (0); - - if (reg < 16) - return ((&rp->r_g1)[reg - 1]); - - /* - * Before we look at the user's stack, we'll check the register - * windows to see if the information we want is in there. - */ - cookie = dtrace_interrupt_disable(); - if (dtrace_getotherwin() > 0) { - value = dtrace_getreg_win(reg, 1); - dtrace_interrupt_enable(cookie); - - atomic_add_64(&fasttrap_getreg_fast_cnt, 1); - - return (value); - } - dtrace_interrupt_enable(cookie); - - /* - * First check the machpcb structure to see if we've already read - * in the register window we're looking for; if we haven't, (and - * we probably haven't) try to copy in the value of the register. - */ - mpcb = (struct machpcb *)((caddr_t)rp - REGOFF); - - if (get_udatamodel() == DATAMODEL_NATIVE) { - struct frame *fr = (struct frame *)(rp->r_sp + STACK_BIAS); - - if (mpcb->mpcb_wbcnt > 0) { - struct rwindow *rwin = (void *)mpcb->mpcb_wbuf; - int i = mpcb->mpcb_wbcnt; - do { - i--; - if ((long)mpcb->mpcb_spbuf[i] != rp->r_sp) - continue; - - atomic_add_64(&fasttrap_getreg_mpcb_cnt, 1); - return (rwin[i].rw_local[reg - 16]); - } while (i > 0); - } - - if (fasttrap_fulword(&fr->fr_local[reg - 16], &value) != 0) - goto err; - } else { - struct frame32 *fr = - (struct frame32 *)(uintptr_t)(caddr32_t)rp->r_sp; - uint32_t *v32 = (uint32_t *)&value; - - if (mpcb->mpcb_wbcnt > 0) { - struct rwindow32 *rwin = (void *)mpcb->mpcb_wbuf; - int i = mpcb->mpcb_wbcnt; - do { - i--; - if ((long)mpcb->mpcb_spbuf[i] != rp->r_sp) - continue; - - atomic_add_64(&fasttrap_getreg_mpcb_cnt, 1); - return (rwin[i].rw_local[reg - 16]); - } while (i > 0); - } - - if (fasttrap_fuword32(&fr->fr_local[reg - 16], &v32[1]) != 0) - goto err; - - v32[0] = 0; - } - - atomic_add_64(&fasttrap_getreg_slow_cnt, 1); - return (value); - -err: - /* - * If the copy in failed, the process will be in a irrecoverable - * state, and we have no choice but to kill it. - */ - psignal(ttoproc(curthread), SIGILL); - return (0); -} - -static uint64_t fasttrap_putreg_fast_cnt; -static uint64_t fasttrap_putreg_mpcb_cnt; -static uint64_t fasttrap_putreg_slow_cnt; - -static void -fasttrap_putreg(struct regs *rp, uint_t reg, ulong_t value) -{ - dtrace_icookie_t cookie; - struct machpcb *mpcb; - extern void dtrace_putreg_win(uint_t, ulong_t); - - if (reg == 0) - return; - - if (reg < 16) { - (&rp->r_g1)[reg - 1] = value; - return; - } - - /* - * If the user process is still using some register windows, we - * can just place the value in the correct window. - */ - cookie = dtrace_interrupt_disable(); - if (dtrace_getotherwin() > 0) { - dtrace_putreg_win(reg, value); - dtrace_interrupt_enable(cookie); - atomic_add_64(&fasttrap_putreg_fast_cnt, 1); - return; - } - dtrace_interrupt_enable(cookie); - - /* - * First see if there's a copy of the register window in the - * machpcb structure that we can modify; if there isn't try to - * copy out the value. If that fails, we try to create a new - * register window in the machpcb structure. While this isn't - * _precisely_ the intended use of the machpcb structure, it - * can't cause any problems since we know at this point in the - * code that all of the user's data have been flushed out of the - * register file (since %otherwin is 0). - */ - mpcb = (struct machpcb *)((caddr_t)rp - REGOFF); - - if (get_udatamodel() == DATAMODEL_NATIVE) { - struct frame *fr = (struct frame *)(rp->r_sp + STACK_BIAS); - struct rwindow *rwin = (struct rwindow *)mpcb->mpcb_wbuf; - - if (mpcb->mpcb_wbcnt > 0) { - int i = mpcb->mpcb_wbcnt; - do { - i--; - if ((long)mpcb->mpcb_spbuf[i] != rp->r_sp) - continue; - - rwin[i].rw_local[reg - 16] = value; - atomic_add_64(&fasttrap_putreg_mpcb_cnt, 1); - return; - } while (i > 0); - } - - if (fasttrap_sulword(&fr->fr_local[reg - 16], value) != 0) { - if (mpcb->mpcb_wbcnt >= MAXWIN || copyin(fr, - &rwin[mpcb->mpcb_wbcnt], sizeof (*rwin)) != 0) - goto err; - - rwin[mpcb->mpcb_wbcnt].rw_local[reg - 16] = value; - mpcb->mpcb_spbuf[mpcb->mpcb_wbcnt] = (caddr_t)rp->r_sp; - mpcb->mpcb_wbcnt++; - atomic_add_64(&fasttrap_putreg_mpcb_cnt, 1); - return; - } - } else { - struct frame32 *fr = - (struct frame32 *)(uintptr_t)(caddr32_t)rp->r_sp; - struct rwindow32 *rwin = (struct rwindow32 *)mpcb->mpcb_wbuf; - uint32_t v32 = (uint32_t)value; - - if (mpcb->mpcb_wbcnt > 0) { - int i = mpcb->mpcb_wbcnt; - do { - i--; - if ((long)mpcb->mpcb_spbuf[i] != rp->r_sp) - continue; - - rwin[i].rw_local[reg - 16] = v32; - atomic_add_64(&fasttrap_putreg_mpcb_cnt, 1); - return; - } while (i > 0); - } - - if (fasttrap_suword32(&fr->fr_local[reg - 16], v32) != 0) { - if (mpcb->mpcb_wbcnt >= MAXWIN || copyin(fr, - &rwin[mpcb->mpcb_wbcnt], sizeof (*rwin)) != 0) - goto err; - - rwin[mpcb->mpcb_wbcnt].rw_local[reg - 16] = v32; - mpcb->mpcb_spbuf[mpcb->mpcb_wbcnt] = (caddr_t)rp->r_sp; - mpcb->mpcb_wbcnt++; - atomic_add_64(&fasttrap_putreg_mpcb_cnt, 1); - return; - } - } - - atomic_add_64(&fasttrap_putreg_slow_cnt, 1); - return; - -err: - /* - * If we couldn't record this register's value, the process is in an - * irrecoverable state and we have no choice but to euthanize it. - */ - psignal(ttoproc(curthread), SIGILL); -} +/*========================= End of Function ========================*/
--- a/usr/src/uts/zSeries/dtrace/fbt.c Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/uts/zSeries/dtrace/fbt.c Thu Oct 08 12:44:34 2009 -0400 @@ -1,1023 +1,319 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END +/*------------------------------------------------------------------*/ +/* */ +/* Name - fbt.c */ +/* */ +/* Function - Platform specific support for Dtrace FBT. */ +/* */ +/* Name - Neale Ferguson */ +/* */ +/* Date - October, 2009 */ +/* */ +/*------------------------------------------------------------------*/ + +/*------------------------------------------------------------------*/ +/* L I C E N S E */ +/*------------------------------------------------------------------*/ + +/*==================================================================*/ +/* */ +/* CDDL HEADER START */ +/* */ +/* The contents of this file are subject to the terms of the */ +/* Common Development and Distribution License (the "License"). */ +/* You may not use this file except in compliance the the License. */ +/* */ +/* You can obtain a copy of the license at: */ +/* - usr/src/OPENSOLARIS.LICENSE, or, */ +/* - http://www.opensolaris.org/os/licensing. */ +/* See the License for the specific language governing permissions */ +/* and limitations under the License. */ +/* */ +/* When distributing Covered Code, include this CDDL HEADER in each */ +/* file and include the License file at usr/src/OPENSOLARIS.LICENSE.*/ +/* If applicable, add the following below this CDDL HEADER, with */ +/* the fields enclosed by brackets "[]" replaced with your own */ +/* identifying information: */ +/* Portions Copyright [yyyy] [name of copyright owner] */ +/* */ +/* CDDL HEADER END */ /* */ /* Copyright 2008 Sine Nomine Associates. */ /* All rights reserved. */ /* Use is subject to license terms. */ - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ +/* */ +/* Copyright 2005 Sun Microsystems, Inc. All rights reserved. */ +/* Use is subject to license terms. */ +/* */ +/*==================================================================*/ + +/*------------------------------------------------------------------*/ +/* D e f i n e s */ +/*------------------------------------------------------------------*/ + +#define OP_STMG1 0xeb +#define OP_STMG2 0x24 +#define OP_LMG1 0xeb +#define OP_LMG2 0x04 +#define OP_BR 0x07 -#include <sys/errno.h> -#include <sys/stat.h> +#define UNC 0xf +#define R14 0xe +#define R4 0x4 + +#define FBT_PATCHVAL 0x0a01 + +#define FBT_ENTRY "entry" +#define FBT_RETURN "return" +#define FBT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & fbt_probetab_mask) +#define FBT_PROBETAB_SIZE 0x8000 /* 32k entries -- 128K total */ + +/*========================= End of Defines =========================*/ + +/*------------------------------------------------------------------*/ +/* I n c l u d e s */ +/*------------------------------------------------------------------*/ + #include <sys/modctl.h> -#include <sys/conf.h> -#include <sys/systm.h> -#include <sys/ddi.h> -#include <sys/sunddi.h> -#include <sys/cpuvar.h> -#include <sys/kmem.h> -#include <sys/strsubr.h> #include <sys/dtrace.h> #include <sys/kobj.h> -#include <sys/modctl.h> -#include <sys/atomic.h> -#include <vm/seg_kmem.h> -#include <sys/stack.h> -#include <sys/ctf_api.h> -#include <sys/sysmacros.h> - -static dev_info_t *fbt_devi; -static dtrace_provider_id_t fbt_id; -static uintptr_t fbt_trampoline; -static caddr_t fbt_trampoline_window; -static size_t fbt_trampoline_size; -static int fbt_verbose = 0; - -/* - * Various interesting bean counters. - */ -static int fbt_entry; -static int fbt_ret; -static int fbt_retl; -static int fbt_retl_jmptab; -static int fbt_retl_twoinstr; -static int fbt_retl_tailcall; -static int fbt_retl_tailjmpl; -static int fbt_leaf_functions; - -extern char stubs_base[]; -extern char stubs_end[]; - -#define FBT_REG_G0 0 -#define FBT_REG_G1 1 -#define FBT_REG_O0 8 -#define FBT_REG_O1 9 -#define FBT_REG_O2 10 -#define FBT_REG_O3 11 -#define FBT_REG_O4 12 -#define FBT_REG_O5 13 -#define FBT_REG_O6 14 -#define FBT_REG_O7 15 -#define FBT_REG_I0 24 -#define FBT_REG_I1 25 -#define FBT_REG_I2 26 -#define FBT_REG_I3 27 -#define FBT_REG_I4 28 -#define FBT_REG_I7 31 -#define FBT_REG_L0 16 -#define FBT_REG_L1 17 -#define FBT_REG_L2 18 -#define FBT_REG_L3 19 -#define FBT_REG_PC 5 - -#define FBT_REG_ISGLOBAL(r) ((r) < 8) -#define FBT_REG_ISOUTPUT(r) ((r) >= 8 && (r) < 16) -#define FBT_REG_ISLOCAL(r) ((r) >= 16 && (r) < 24) -#define FBT_REG_ISVOLATILE(r) \ - ((FBT_REG_ISGLOBAL(r) || FBT_REG_ISOUTPUT(r)) && (r) != FBT_REG_G0) -#define FBT_REG_NLOCALS 8 - -#define FBT_REG_MARKLOCAL(locals, r) \ - if (FBT_REG_ISLOCAL(r)) \ - (locals)[(r) - FBT_REG_L0] = 1; - -#define FBT_REG_INITLOCALS(local, locals) \ - for ((local) = 0; (local) < FBT_REG_NLOCALS; (local)++) \ - (locals)[(local)] = 0; \ - (local) = FBT_REG_L0 - -#define FBT_REG_ALLOCLOCAL(local, locals) \ - while ((locals)[(local) - FBT_REG_L0]) \ - (local)++; \ - (locals)[(local) - FBT_REG_L0] = 1; - -#define FBT_OP_MASK 0xc0000000 -#define FBT_OP_SHIFT 30 -#define FBT_OP(val) ((val) & FBT_FMT1_MASK) - -#define FBT_SIMM13_MASK 0x1fff -#define FBT_SIMM13_MAX ((int32_t)0xfff) -#define FBT_IMM22_MASK 0x3fffff -#define FBT_IMM22_SHIFT 10 -#define FBT_IMM10_MASK 0x3ff - -#define FBT_DISP30_MASK 0x3fffffff -#define FBT_DISP30(from, to) \ - (((uintptr_t)(to) - (uintptr_t)(from) >> 2) & FBT_DISP30_MASK) - -#define FBT_DISP22_MASK 0x3fffff -#define FBT_DISP22(from, to) \ - (((uintptr_t)(to) - (uintptr_t)(from) >> 2) & FBT_DISP22_MASK) - -#define FBT_DISP19_MASK 0x7ffff -#define FBT_DISP19(from, to) \ - (((uintptr_t)(to) - (uintptr_t)(from) >> 2) & FBT_DISP19_MASK) - -#define FBT_DISP16_HISHIFT 20 -#define FBT_DISP16_HIMASK (0x3 << FBT_DISP16_HISHIFT) -#define FBT_DISP16_LOMASK (0x3fff) -#define FBT_DISP16_MASK (FBT_DISP16_HIMASK | FBT_DISP16_LOMASK) -#define FBT_DISP16(val) \ - ((((val) & FBT_DISP16_HIMASK) >> 6) | ((val) & FBT_DISP16_LOMASK)) - -#define FBT_DISP14_MASK 0x3fff -#define FBT_DISP14(from, to) \ - (((uintptr_t)(to) - (uintptr_t)(from) >> 2) & FBT_DISP14_MASK) - -#define FBT_OP0 (((uint32_t)0) << FBT_OP_SHIFT) -#define FBT_OP1 (((uint32_t)1) << FBT_OP_SHIFT) -#define FBT_OP2 (((uint32_t)2) << FBT_OP_SHIFT) -#define FBT_ILLTRAP 0 - -#define FBT_ANNUL_SHIFT 29 -#define FBT_ANNUL (1 << FBT_ANNUL_SHIFT) - -#define FBT_FMT3_OP3_SHIFT 19 -#define FBT_FMT3_OP_MASK 0xc1f80000 -#define FBT_FMT3_OP(val) ((val) & FBT_FMT3_OP_MASK) - -#define FBT_FMT3_RD_SHIFT 25 -#define FBT_FMT3_RD_MASK (0x1f << FBT_FMT3_RD_SHIFT) -#define FBT_FMT3_RD(val) \ - (((val) & FBT_FMT3_RD_MASK) >> FBT_FMT3_RD_SHIFT) - -#define FBT_FMT3_RS1_SHIFT 14 -#define FBT_FMT3_RS1_MASK (0x1f << FBT_FMT3_RS1_SHIFT) -#define FBT_FMT3_RS1(val) \ - (((val) & FBT_FMT3_RS1_MASK) >> FBT_FMT3_RS1_SHIFT) -#define FBT_FMT3_RS1_SET(val, rs1) \ - (val) = ((val) & ~FBT_FMT3_RS1_MASK) | ((rs1) << FBT_FMT3_RS1_SHIFT) - -#define FBT_FMT3_RS2_SHIFT 0 -#define FBT_FMT3_RS2_MASK (0x1f << FBT_FMT3_RS2_SHIFT) -#define FBT_FMT3_RS2(val) \ - (((val) & FBT_FMT3_RS2_MASK) >> FBT_FMT3_RS2_SHIFT) -#define FBT_FMT3_RS2_SET(val, rs2) \ - (val) = ((val) & ~FBT_FMT3_RS2_MASK) | ((rs2) << FBT_FMT3_RS2_SHIFT) +#include <sys/stat.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/conf.h> +#include <dis_tables.h> -#define FBT_FMT3_IMM_SHIFT 13 -#define FBT_FMT3_IMM (1 << FBT_FMT3_IMM_SHIFT) -#define FBT_FMT3_SIMM13_MASK FBT_SIMM13_MASK - -#define FBT_FMT3_ISIMM(val) ((val) & FBT_FMT3_IMM) -#define FBT_FMT3_SIMM13(val) ((val) & FBT_FMT3_SIMM13_MASK) - -#define FBT_FMT2_OP2_SHIFT 22 -#define FBT_FMT2_OP2_MASK (0x7 << FBT_FMT2_OP2_SHIFT) -#define FBT_FMT2_RD_SHIFT 25 - -#define FBT_FMT1_OP(val) ((val) & FBT_OP_MASK) -#define FBT_FMT1_DISP30(val) ((val) & FBT_DISP30_MASK) - -#define FBT_FMT2_OP2_BPCC (0x01 << FBT_FMT2_OP2_SHIFT) -#define FBT_FMT2_OP2_BCC (0x02 << FBT_FMT2_OP2_SHIFT) -#define FBT_FMT2_OP2_BPR (0x03 << FBT_FMT2_OP2_SHIFT) -#define FBT_FMT2_OP2_SETHI (0x04 << FBT_FMT2_OP2_SHIFT) - -#define FBT_FMT2_COND_SHIFT 25 -#define FBT_FMT2_COND_BA (0x8 << FBT_FMT2_COND_SHIFT) -#define FBT_FMT2_COND_BL (0x3 << FBT_FMT2_COND_SHIFT) -#define FBT_FMT2_COND_BGE (0xb << FBT_FMT2_COND_SHIFT) - -#define FBT_OP_RESTORE (FBT_OP2 | (0x3d << FBT_FMT3_OP3_SHIFT)) -#define FBT_OP_SAVE (FBT_OP2 | (0x3c << FBT_FMT3_OP3_SHIFT)) -#define FBT_OP_JMPL (FBT_OP2 | (0x38 << FBT_FMT3_OP3_SHIFT)) -#define FBT_OP_RETURN (FBT_OP2 | (0x39 << FBT_FMT3_OP3_SHIFT)) -#define FBT_OP_CALL FBT_OP1 -#define FBT_OP_SETHI (FBT_OP0 | FBT_FMT2_OP2_SETHI) -#define FBT_OP_ADD (FBT_OP2 | (0x00 << FBT_FMT3_OP3_SHIFT)) -#define FBT_OP_OR (FBT_OP2 | (0x02 << FBT_FMT3_OP3_SHIFT)) -#define FBT_OP_SUB (FBT_OP2 | (0x04 << FBT_FMT3_OP3_SHIFT)) -#define FBT_OP_CC (FBT_OP2 | (0x10 << FBT_FMT3_OP3_SHIFT)) -#define FBT_OP_BA (FBT_OP0 | FBT_FMT2_OP2_BCC | FBT_FMT2_COND_BA) -#define FBT_OP_BL (FBT_OP0 | FBT_FMT2_OP2_BCC | FBT_FMT2_COND_BL) -#define FBT_OP_BGE (FBT_OP0 | FBT_FMT2_OP2_BCC | FBT_FMT2_COND_BGE) -#define FBT_OP_BAPCC (FBT_OP0 | FBT_FMT2_OP2_BPCC | FBT_FMT2_COND_BA) -#define FBT_OP_RD (FBT_OP2 | (0x28 << FBT_FMT3_OP3_SHIFT)) - -#define FBT_ORLO(rs, val, rd) \ - (FBT_OP_OR | ((rs) << FBT_FMT3_RS1_SHIFT) | \ - ((rd) << FBT_FMT3_RD_SHIFT) | FBT_FMT3_IMM | ((val) & FBT_IMM10_MASK)) - -#define FBT_ORSIMM13(rs, val, rd) \ - (FBT_OP_OR | ((rs) << FBT_FMT3_RS1_SHIFT) | \ - ((rd) << FBT_FMT3_RD_SHIFT) | FBT_FMT3_IMM | ((val) & FBT_SIMM13_MASK)) - -#define FBT_ADDSIMM13(rs, val, rd) \ - (FBT_OP_ADD | ((rs) << FBT_FMT3_RS1_SHIFT) | \ - ((rd) << FBT_FMT3_RD_SHIFT) | FBT_FMT3_IMM | ((val) & FBT_SIMM13_MASK)) - -#define FBT_ADD(rs1, rs2, rd) \ - (FBT_OP_ADD | ((rs1) << FBT_FMT3_RS1_SHIFT) | \ - ((rs2) << FBT_FMT3_RS2_SHIFT) | ((rd) << FBT_FMT3_RD_SHIFT)) - -#define FBT_CMP(rs1, rs2) \ - (FBT_OP_SUB | FBT_OP_CC | ((rs1) << FBT_FMT3_RS1_SHIFT) | \ - ((rs2) << FBT_FMT3_RS2_SHIFT) | (FBT_REG_G0 << FBT_FMT3_RD_SHIFT)) - -#define FBT_MOV(rs, rd) \ - (FBT_OP_OR | (FBT_REG_G0 << FBT_FMT3_RS1_SHIFT) | \ - ((rs) << FBT_FMT3_RS2_SHIFT) | ((rd) << FBT_FMT3_RD_SHIFT)) - -#define FBT_SETHI(val, reg) \ - (FBT_OP_SETHI | (reg << FBT_FMT2_RD_SHIFT) | \ - ((val >> FBT_IMM22_SHIFT) & FBT_IMM22_MASK)) +/*========================= End of Includes ========================*/ -#define FBT_CALL(orig, dest) (FBT_OP_CALL | FBT_DISP30(orig, dest)) - -#define FBT_RET \ - (FBT_OP_JMPL | (FBT_REG_I7 << FBT_FMT3_RS1_SHIFT) | \ - (FBT_REG_G0 << FBT_FMT3_RD_SHIFT) | FBT_FMT3_IMM | (sizeof (pc_t) << 1)) - -#define FBT_SAVEIMM(rd, val, rs1) \ - (FBT_OP_SAVE | ((rs1) << FBT_FMT3_RS1_SHIFT) | \ - ((rd) << FBT_FMT3_RD_SHIFT) | FBT_FMT3_IMM | ((val) & FBT_SIMM13_MASK)) - -#define FBT_RESTORE(rd, rs1, rs2) \ - (FBT_OP_RESTORE | ((rs1) << FBT_FMT3_RS1_SHIFT) | \ - ((rd) << FBT_FMT3_RD_SHIFT) | ((rs2) << FBT_FMT3_RS2_SHIFT)) - -#define FBT_RETURN(rs1, val) \ - (FBT_OP_RETURN | ((rs1) << FBT_FMT3_RS1_SHIFT) | \ - FBT_FMT3_IMM | ((val) & FBT_SIMM13_MASK)) - -#define FBT_BA(orig, dest) (FBT_OP_BA | FBT_DISP22(orig, dest)) -#define FBT_BAA(orig, dest) (FBT_BA(orig, dest) | FBT_ANNUL) -#define FBT_BL(orig, dest) (FBT_OP_BL | FBT_DISP22(orig, dest)) -#define FBT_BGE(orig, dest) (FBT_OP_BGE | FBT_DISP22(orig, dest)) -#define FBT_BDEST(va, instr) ((uintptr_t)(va) + \ - (((int32_t)(((instr) & FBT_DISP22_MASK) << 10)) >> 8)) -#define FBT_BPCCDEST(va, instr) ((uintptr_t)(va) + \ - (((int32_t)(((instr) & FBT_DISP19_MASK) << 13)) >> 11)) -#define FBT_BPRDEST(va, instr) ((uintptr_t)(va) + \ - (((int32_t)((FBT_DISP16(instr)) << 16)) >> 14)) - -/* - * We're only going to treat a save as safe if (a) both rs1 and rd are - * %sp and (b) if the instruction has a simm, the value isn't 0. - */ -#define FBT_IS_SAVE(instr) \ - (FBT_FMT3_OP(instr) == FBT_OP_SAVE && \ - FBT_FMT3_RD(instr) == FBT_REG_O6 && \ - FBT_FMT3_RS1(instr) == FBT_REG_O6 && \ - !(FBT_FMT3_ISIMM(instr) && FBT_FMT3_SIMM13(instr) == 0)) - -#define FBT_IS_BA(instr) (((instr) & ~FBT_DISP22_MASK) == FBT_OP_BA) -#define FBT_IS_BAPCC(instr) (((instr) & ~FBT_DISP22_MASK) == FBT_OP_BAPCC) - -#define FBT_IS_RDPC(instr) ((FBT_FMT3_OP(instr) == FBT_OP_RD) && \ - (FBT_FMT3_RD(instr) == FBT_REG_PC)) - -#define FBT_IS_PCRELATIVE(instr) \ - ((((instr) & FBT_OP_MASK) == FBT_OP0 && \ - ((instr) & FBT_FMT2_OP2_MASK) != FBT_FMT2_OP2_SETHI) || \ - ((instr) & FBT_OP_MASK) == FBT_OP1 || \ - FBT_IS_RDPC(instr)) - -#define FBT_IS_CTI(instr) \ - ((((instr) & FBT_OP_MASK) == FBT_OP0 && \ - ((instr) & FBT_FMT2_OP2_MASK) != FBT_FMT2_OP2_SETHI) || \ - ((instr) & FBT_OP_MASK) == FBT_OP1 || \ - (FBT_FMT3_OP(instr) == FBT_OP_JMPL) || \ - (FBT_FMT3_OP(instr) == FBT_OP_RETURN)) - -#define FBT_PROBENAME_ENTRY "entry" -#define FBT_PROBENAME_RETURN "return" -#define FBT_ESTIMATE_ID (UINT32_MAX) -#define FBT_COUNTER(id, count) if ((id) != FBT_ESTIMATE_ID) (count)++ - -#define FBT_ENTENT_MAXSIZE (16 * sizeof (uint32_t)) -#define FBT_RETENT_MAXSIZE (11 * sizeof (uint32_t)) -#define FBT_RETLENT_MAXSIZE (23 * sizeof (uint32_t)) -#define FBT_ENT_MAXSIZE \ - MAX(MAX(FBT_ENTENT_MAXSIZE, FBT_RETENT_MAXSIZE), FBT_RETLENT_MAXSIZE) +/*------------------------------------------------------------------*/ +/* T y p e d e f s */ +/*------------------------------------------------------------------*/ typedef struct fbt_probe { - char *fbtp_name; + struct fbt_probe *fbtp_hashnext; + uint8_t *fbtp_patchpoint; + uint16_t fbtp_patchval; + int8_t fbtp_rval; + uint8_t fbtp_savedval; + uintptr_t fbtp_roffset; dtrace_id_t fbtp_id; - uintptr_t fbtp_addr; + char *fbtp_name; struct modctl *fbtp_ctl; int fbtp_loadcnt; int fbtp_symndx; int fbtp_primary; - int fbtp_return; - uint32_t *fbtp_patchpoint; - uint32_t fbtp_patchval; - uint32_t fbtp_savedval; struct fbt_probe *fbtp_next; } fbt_probe_t; -typedef struct fbt_trampoline { - uintptr_t fbtt_va; - uintptr_t fbtt_limit; - uintptr_t fbtt_next; -} fbt_trampoline_t; +/*========================= End of Typedefs ========================*/ + +/*------------------------------------------------------------------*/ +/* E x t e r n a l R e f e r e n c e s */ +/*------------------------------------------------------------------*/ -static caddr_t -fbt_trampoline_map(uintptr_t tramp, size_t size) -{ - uintptr_t offs; - page_t **ppl; + +/*=================== End of External References ===================*/ + +/*------------------------------------------------------------------*/ +/* P r o t o t y p e s */ +/*------------------------------------------------------------------*/ - ASSERT(fbt_trampoline_window == NULL); - ASSERT(fbt_trampoline_size == 0); - ASSERT(fbt_trampoline == NULL); +static int fbt_open(dev_t *, int, int, cred_t *); +static int fbt_info(dev_info_t *, ddi_info_cmd_t, void *, void **); +static int fbt_attach(dev_info_t *, ddi_attach_cmd_t); +static int fbt_detach(dev_info_t *, ddi_detach_cmd_t); +static int fbt_enable(void *, dtrace_id_t, void *); +static void fbt_provide_module(void *, struct modctl *); +static void fbt_disable(void *, dtrace_id_t, void *); +static void fbt_suspend(void *, dtrace_id_t, void *); +static void fbt_resume(void *, dtrace_id_t, void *); +static void fbt_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *); +static void fbt_cleanup(dev_info_t *); +static void fbt_destroy(void *, dtrace_id_t, void *); + +/*========================= End of Prototypes ======================*/ - size += tramp & PAGEOFFSET; - fbt_trampoline = tramp & PAGEMASK; - fbt_trampoline_size = (size + PAGESIZE - 1) & PAGEMASK; - fbt_trampoline_window = - vmem_alloc(heap_arena, fbt_trampoline_size, VM_SLEEP); +/*------------------------------------------------------------------*/ +/* G l o b a l V a r i a b l e s */ +/*------------------------------------------------------------------*/ - (void) as_pagelock(&kas, &ppl, (caddr_t)fbt_trampoline, - fbt_trampoline_size, S_WRITE); +static struct cb_ops fbt_cb_ops = { + fbt_open, /* open */ + nodev, /* close */ + nulldev, /* strategy */ + nulldev, /* print */ + nodev, /* dump */ + nodev, /* read */ + nodev, /* write */ + nodev, /* ioctl */ + nodev, /* devmap */ + nodev, /* mmap */ + nodev, /* segmap */ + nochpoll, /* poll */ + ddi_prop_op, /* cb_prop_op */ + 0, /* streamtab */ + D_NEW | D_MP /* Driver compatibility flag */ +}; - for (offs = 0; offs < fbt_trampoline_size; offs += PAGESIZE) { - hat_devload(kas.a_hat, fbt_trampoline_window + offs, PAGESIZE, - hat_getpfnum(kas.a_hat, (caddr_t)fbt_trampoline + offs), - PROT_READ | PROT_WRITE, - HAT_LOAD_LOCK | HAT_LOAD_NOCONSIST); - } +static struct dev_ops fbt_ops = { + DEVO_REV, /* devo_rev */ + 0, /* refcnt */ + fbt_info, /* get_dev_info */ + nulldev, /* identify */ + nulldev, /* probe */ + fbt_attach, /* attach */ + fbt_detach, /* detach */ + nodev, /* reset */ + &fbt_cb_ops, /* driver operations */ + NULL, /* bus operations */ + nodev, /* dev power */ + ddi_quiesce_not_needed, /* quiesce */ +}; - as_pageunlock(&kas, ppl, (caddr_t)fbt_trampoline, fbt_trampoline_size, - S_WRITE); +/* + * Module linkage information for the kernel. + */ +static struct modldrv modldrv = { + &mod_driverops, /* module type (this is a pseudo driver) */ + "Function Boundary Tracing", /* name of module */ + &fbt_ops, /* driver ops */ +}; - return (fbt_trampoline_window + (tramp & PAGEOFFSET)); -} +static struct modlinkage modlinkage = { + MODREV_1, + (void *)&modldrv, + NULL +}; -static void -fbt_trampoline_unmap() -{ - ASSERT(fbt_trampoline_window != NULL); - ASSERT(fbt_trampoline_size != 0); - ASSERT(fbt_trampoline != NULL); - - membar_enter(); - sync_icache((caddr_t)fbt_trampoline, fbt_trampoline_size); - sync_icache(fbt_trampoline_window, fbt_trampoline_size); +static dtrace_pattr_t fbt_attr = { + { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, + { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, + { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, + { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, + { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, +}; - hat_unload(kas.a_hat, fbt_trampoline_window, fbt_trampoline_size, - HAT_UNLOAD_UNLOCK); - - vmem_free(heap_arena, fbt_trampoline_window, fbt_trampoline_size); +static dtrace_pops_t fbt_pops = { + NULL, + fbt_provide_module, + fbt_enable, + fbt_disable, + fbt_suspend, + fbt_resume, + fbt_getargdesc, + NULL, + NULL, + fbt_destroy +}; - fbt_trampoline_window = NULL; - fbt_trampoline = NULL; - fbt_trampoline_size = 0; -} +static dev_info_t *fbt_devi; +static dtrace_provider_id_t fbt_id; +static fbt_probe_t **fbt_probetab; +static int fbt_probetab_size; +static int fbt_probetab_mask; +static int fbt_verbose = 0; + +/*====================== End of Global Variables ===================*/ -static uintptr_t -fbt_patch_entry(uint32_t *instr, uint32_t id, fbt_trampoline_t *tramp, - int nargs) +/*------------------------------------------------------------------*/ +/* */ +/* Name - fbt_invop. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + +static int +fbt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t rval) { - uint32_t *tinstr = (uint32_t *)tramp->fbtt_next; - uint32_t first = *instr; - uintptr_t va = tramp->fbtt_va; - uintptr_t base = tramp->fbtt_next; - - if (tramp->fbtt_next + FBT_ENTENT_MAXSIZE > tramp->fbtt_limit) { - /* - * There isn't sufficient room for this entry; return failure. - */ - return (0); - } - - FBT_COUNTER(id, fbt_entry); - - if (FBT_IS_SAVE(first)) { - *tinstr++ = first; - } else { - *tinstr++ = FBT_SAVEIMM(FBT_REG_O6, -SA(MINFRAME), FBT_REG_O6); - } - - if (id > (uint32_t)FBT_SIMM13_MAX) { - *tinstr++ = FBT_SETHI(id, FBT_REG_O0); - *tinstr++ = FBT_ORLO(FBT_REG_O0, id, FBT_REG_O0); - } else { - *tinstr++ = FBT_ORSIMM13(FBT_REG_G0, id, FBT_REG_O0); - } - - if (nargs >= 1) - *tinstr++ = FBT_MOV(FBT_REG_I0, FBT_REG_O1); - - if (nargs >= 2) - *tinstr++ = FBT_MOV(FBT_REG_I1, FBT_REG_O2); - - if (nargs >= 3) - *tinstr++ = FBT_MOV(FBT_REG_I2, FBT_REG_O3); + uintptr_t stack0, stack1, stack2, stack3, stack4; + fbt_probe_t *fbt = fbt_probetab[FBT_ADDR2NDX(addr)]; - if (nargs >= 4) - *tinstr++ = FBT_MOV(FBT_REG_I3, FBT_REG_O4); - - if (nargs >= 5) - *tinstr++ = FBT_MOV(FBT_REG_I4, FBT_REG_O5); - - if (FBT_IS_SAVE(first)) { - uintptr_t ret = (uintptr_t)instr - sizeof (uint32_t); - - *tinstr++ = FBT_SETHI(ret, FBT_REG_G1); - *tinstr = FBT_CALL((uintptr_t)tinstr - base + va, dtrace_probe); - tinstr++; - *tinstr++ = FBT_ORLO(FBT_REG_G1, ret, FBT_REG_O7); - } else { - uintptr_t slot = *--tinstr; - uintptr_t ret = (uintptr_t)instr + sizeof (uint32_t); - uint32_t delay = first; + for (; fbt != NULL; fbt = fbt->fbtp_hashnext) { + if ((uintptr_t)fbt->fbtp_patchpoint == addr) { + if (fbt->fbtp_roffset == 0) { + int i = 0; + /* + * When accessing the arguments on the stack, + * we must protect against accessing beyond + * the stack. We can safely set NOFAULT here + * -- we know that interrupts are already + * disabled. + */ + DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); + CPU->cpu_dtrace_caller = stack[i++]; +#ifdef __amd64 + /* + * On amd64, stack[0] contains the dereferenced + * stack pointer, stack[1] contains savfp, + * stack[2] contains savpc. We want to step + * over these entries. + */ + i += 2; +#endif + stack0 = stack[i++]; + stack1 = stack[i++]; + stack2 = stack[i++]; + stack3 = stack[i++]; + stack4 = stack[i++]; + DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | + CPU_DTRACE_BADADDR); - *tinstr = FBT_CALL((uintptr_t)tinstr - base + va, dtrace_probe); - tinstr++; - *tinstr++ = slot; - *tinstr++ = FBT_RESTORE(FBT_REG_G0, FBT_REG_G0, FBT_REG_G0); + dtrace_probe(fbt->fbtp_id, stack0, stack1, + stack2, stack3, stack4); - if (FBT_IS_BA(first) || FBT_IS_BAPCC(first)) { - /* - * This is a special case: we are instrumenting a - * a non-annulled branch-always (or variant). We'll - * return directly to the destination of the branch, - * copying the instruction in the delay slot here, - * and then executing it in the slot of a ba. - */ - if (FBT_IS_BA(first)) { - ret = FBT_BDEST(instr, *instr); + CPU->cpu_dtrace_caller = NULL; } else { - ret = FBT_BPCCDEST(instr, *instr); +#ifdef __amd64 + /* + * On amd64, we instrument the ret, not the + * leave. We therefore need to set the caller + * to assure that the top frame of a stack() + * action is correct. + */ + DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); + CPU->cpu_dtrace_caller = stack[0]; + DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | + CPU_DTRACE_BADADDR); +#endif + + dtrace_probe(fbt->fbtp_id, fbt->fbtp_roffset, + rval, 0, 0, 0); + CPU->cpu_dtrace_caller = NULL; } - delay = *(instr + 1); - } - - if ((first & FBT_OP_MASK) != FBT_OP0 || - (first & FBT_FMT2_OP2_MASK) != FBT_FMT2_OP2_BPR) { - *tinstr = FBT_BA((uintptr_t)tinstr - base + va, ret); - tinstr++; - *tinstr++ = delay; - } else { - /* - * If this is a branch-on-register, we have a little - * more work to do: because the displacement is only - * sixteen bits, we're going to thunk the branch into - * the trampoline, and then ba,a to the appropriate - * destination in the branch targets. That is, we're - * constructing this sequence in the trampoline: - * - * br[cc] %[rs], 1f - * <delay-instruction> - * ba,a <not-taken-destination> - * 1: ba,a <taken-destination> - * - */ - uintptr_t targ = FBT_BPRDEST(instr, first); - - *tinstr = first & ~(FBT_DISP16_MASK); - *tinstr |= FBT_DISP14(tinstr, &tinstr[3]); - tinstr++; - *tinstr++ = *(instr + 1); - *tinstr = FBT_BAA((uintptr_t)tinstr - base + va, - ret + sizeof (uint32_t)); - tinstr++; - *tinstr = FBT_BAA((uintptr_t)tinstr - base + va, targ); - tinstr++; + return (fbt->fbtp_rval); } } - tramp->fbtt_va += (uintptr_t)tinstr - tramp->fbtt_next; - tramp->fbtt_next = (uintptr_t)tinstr; - - return (1); -} - -/* - * We are patching control-transfer/restore couplets. There are three - * variants of couplet: - * - * (a) return rs1 + imm - * delay - * - * (b) jmpl rs1 + (rs2 | offset), rd - * restore rs1, rs2 | imm, rd - * - * (c) call displacement - * restore rs1, rs2 | imm, rd - * - * If rs1 in (a) is anything other than %i7, or imm is anything other than 8, - * or delay is a DCTI, we fail. If rd from the jmpl in (b) is something other - * than %g0 (a ret or a tail-call through a function pointer) or %o7 (a call - * through a register), we fail. - * - * Note that rs1 and rs2 in the restore instructions in (b) and (c) are - * potentially outputs and/or globals. Because these registers cannot be - * relied upon across the call to dtrace_probe(), we move rs1 into an unused - * local, ls0, and rs2 into an unused local, ls1, and restructure the restore - * to be: - * - * restore ls0, ls1, rd - * - * Likewise, rs1 and rs2 in the jmpl of case (b) may be outputs and/or globals. - * If the jmpl uses outputs or globals, we restructure it to be: - * - * jmpl ls2 + (ls3 | offset), (%g0 | %o7) - * - */ -/*ARGSUSED*/ -static int -fbt_canpatch_return(uint32_t *instr, int offset, const char *name) -{ - int rd; - - if (FBT_FMT3_OP(*instr) == FBT_OP_RETURN) { - uint32_t delay = *(instr + 1); - - if (*instr != FBT_RETURN(FBT_REG_I7, 8)) { - /* - * It's unclear if we should warn about this or not. - * We really wouldn't expect the compiler to generate - * return instructions with something other than %i7 - * as rs1 and 8 as the simm13 -- it would just be - * mean-spirited. That said, such a construct isn't - * necessarily incorrect. Sill, we err on the side of - * caution and warn about it... - */ - cmn_err(CE_NOTE, "cannot instrument return of %s at " - "%p: non-canonical return instruction", name, - (void *)instr); - return (0); - } - - if (FBT_IS_CTI(delay)) { - /* - * This is even weirder -- a DCTI coupled with a - * return instruction. Similar constructs are used to - * return from utraps, but these typically have the - * return in the slot -- and we wouldn't expect to see - * it in the kernel regardless. At any rate, we don't - * want to try to instrument this construct, whatever - * it may be. - */ - cmn_err(CE_NOTE, "cannot instrument return of %s at " - "%p: CTI in delay slot of return instruction", - name, (void *)instr); - return (0); - } - - if (FBT_IS_PCRELATIVE(delay)) { - /* - * This is also very weird, but might be correct code - * if the function is (for example) returning the - * address of the delay instruction of the return as - * its return value (e.g. "rd %pc, %o0" in the slot). - * Perhaps correct, but still too weird to not warn - * about it... - */ - cmn_err(CE_NOTE, "cannot instrument return of %s at " - "%p: PC-relative instruction in delay slot of " - "return instruction", name, (void *)instr); - return (0); - } - - return (1); - } - - if (FBT_FMT3_OP(*(instr + 1)) != FBT_OP_RESTORE) - return (0); - - if (FBT_FMT1_OP(*instr) == FBT_OP_CALL) - return (1); - - if (FBT_FMT3_OP(*instr) != FBT_OP_JMPL) - return (0); - - rd = FBT_FMT3_RD(*instr); - - if (rd == FBT_REG_I7 || rd == FBT_REG_O7 || rd == FBT_REG_G0) - return (1); - - /* - * We have encountered a jmpl that is storing the calling %pc in - * some register besides %i7, %o7 or %g0. This is strange; emit - * a warning and fail. - */ - cmn_err(CE_NOTE, "cannot instrument return of %s at %p: unexpected " - "jmpl destination register", name, (void *)instr); return (0); } -static int -fbt_canpatch_retl(uint32_t *instr, int offset, const char *name) -{ - if (FBT_FMT1_OP(*instr) == FBT_OP_CALL || - (FBT_FMT3_OP(*instr) == FBT_OP_JMPL && - FBT_FMT3_RD(*instr) == FBT_REG_O7)) { - /* - * If this is a call (or a jmpl that links into %o7), we can - * patch it iff the next instruction uses %o7 as a destination - * register. Because there is an ABI responsibility to - * restore %o7 to the value before the call/jmpl, we don't - * particularly care how this routine is managing to restore - * it (mov, add, ld or divx for all we care). If it doesn't - * seem to be restoring it at all, however, we'll refuse - * to patch it. - */ - uint32_t delay = *(instr + 1); - uint32_t op, rd; - - op = FBT_FMT1_OP(delay); - rd = FBT_FMT3_RD(delay); - - if (op != FBT_OP2 || rd != FBT_REG_O7) { - /* - * This is odd. Before we assume that we're looking - * at something bizarre (and warn accordingly), we'll - * check to see if it's obviously a jump table entry. - */ - if (*instr < (uintptr_t)instr && - *instr >= (uintptr_t)instr - offset) - return (0); - - cmn_err(CE_NOTE, "cannot instrument return of %s at " - "%p: leaf jmpl/call delay isn't restoring %%o7", - name, (void *)instr); - return (0); - } - - return (1); - } - - if (offset == sizeof (uint32_t)) { - /* - * If this is the second instruction in the function, we're - * going to allow it to be patched if the first instruction - * is a patchable return-from-leaf instruction. - */ - if (fbt_canpatch_retl(instr - 1, 0, name)) - return (1); - } - - if (FBT_FMT3_OP(*instr) != FBT_OP_JMPL) - return (0); - - if (FBT_FMT3_RD(*instr) != FBT_REG_G0) - return (0); - - return (1); -} - -/*ARGSUSED*/ -static uint32_t -fbt_patch_return(uint32_t *instr, uint32_t *funcbase, uint32_t *funclim, - int offset, uint32_t id, fbt_trampoline_t *tramp, const char *name) -{ - uint32_t *tinstr = (uint32_t *)tramp->fbtt_next; - uint32_t cti = *instr, restore = *(instr + 1), rs1, dest; - uintptr_t va = tramp->fbtt_va; - uintptr_t base = tramp->fbtt_next; - uint32_t locals[FBT_REG_NLOCALS], local; - - if (tramp->fbtt_next + FBT_RETENT_MAXSIZE > tramp->fbtt_limit) { - /* - * There isn't sufficient room for this entry; return failure. - */ - return (FBT_ILLTRAP); - } - - FBT_COUNTER(id, fbt_ret); - - if (FBT_FMT3_OP(*instr) == FBT_OP_RETURN) { - /* - * To handle the case of the return instruction, we'll emit a - * restore, followed by the instruction in the slot (which - * we'll transplant here), and then another save. While it - * may seem intellectually unsatisfying to emit the additional - * restore/save couplet, one can take solace in the fact that - * we don't do this if the instruction in the return delay - * slot is a nop -- which it is nearly 90% of the time with - * gcc. (And besides, this couplet can't induce unnecessary - * spill/fill traps; rewriting the delay instruction to be - * in terms of the current window hardly seems worth the - * trouble -- let alone the risk.) - */ - uint32_t delay = *(instr + 1); - ASSERT(*instr == FBT_RETURN(FBT_REG_I7, 8)); - - cti = FBT_RET; - restore = FBT_RESTORE(FBT_REG_G0, FBT_REG_G0, FBT_REG_G0); - - if (delay != FBT_SETHI(0, FBT_REG_G0)) { - *tinstr++ = restore; - *tinstr++ = delay; - *tinstr++ = FBT_SAVEIMM(FBT_REG_O6, - -SA(MINFRAME), FBT_REG_O6); - } - } - - FBT_REG_INITLOCALS(local, locals); - - /* - * Mark the locals used in the jmpl. - */ - if (FBT_FMT3_OP(cti) == FBT_OP_JMPL) { - uint32_t rs1 = FBT_FMT3_RS1(cti); - FBT_REG_MARKLOCAL(locals, rs1); - - if (!FBT_FMT3_ISIMM(cti)) { - uint32_t rs2 = FBT_FMT3_RS2(cti); - FBT_REG_MARKLOCAL(locals, rs2); - } - } - - /* - * And mark the locals used in the restore. - */ - rs1 = FBT_FMT3_RS1(restore); - FBT_REG_MARKLOCAL(locals, rs1); - - if (!FBT_FMT3_ISIMM(restore)) { - uint32_t rs2 = FBT_FMT3_RS2(restore); - FBT_REG_MARKLOCAL(locals, rs2); - } - - if (FBT_FMT3_OP(cti) == FBT_OP_JMPL) { - uint32_t rs1 = FBT_FMT3_RS1(cti); - - if (FBT_REG_ISVOLATILE(rs1)) { - FBT_REG_ALLOCLOCAL(local, locals); - FBT_FMT3_RS1_SET(cti, local); - *tinstr++ = FBT_MOV(rs1, local); - } - - if (!FBT_FMT3_ISIMM(cti)) { - uint32_t rs2 = FBT_FMT3_RS2(cti); - - if (FBT_REG_ISVOLATILE(rs2)) { - FBT_REG_ALLOCLOCAL(local, locals); - FBT_FMT3_RS2_SET(cti, local); - *tinstr++ = FBT_MOV(rs2, local); - } - } - } - - rs1 = FBT_FMT3_RS1(restore); - - if (FBT_REG_ISVOLATILE(rs1)) { - FBT_REG_ALLOCLOCAL(local, locals); - FBT_FMT3_RS1_SET(restore, local); - *tinstr++ = FBT_MOV(rs1, local); - } - - if (!FBT_FMT3_ISIMM(restore)) { - uint32_t rs2 = FBT_FMT3_RS2(restore); - - if (FBT_REG_ISVOLATILE(rs2)) { - FBT_REG_ALLOCLOCAL(local, locals); - FBT_FMT3_RS2_SET(restore, local); - *tinstr++ = FBT_MOV(rs2, local); - } - } - - if (id > (uint32_t)FBT_SIMM13_MAX) { - *tinstr++ = FBT_SETHI(id, FBT_REG_O0); - *tinstr++ = FBT_ORLO(FBT_REG_O0, id, FBT_REG_O0); - } else { - *tinstr++ = FBT_ORSIMM13(FBT_REG_G0, id, FBT_REG_O0); - } - - if (offset > (uint32_t)FBT_SIMM13_MAX) { - *tinstr++ = FBT_SETHI(offset, FBT_REG_O1); - *tinstr++ = FBT_ORLO(FBT_REG_O1, offset, FBT_REG_O1); - } else { - *tinstr++ = FBT_ORSIMM13(FBT_REG_G0, offset, FBT_REG_O1); - } +/*========================= End of Function ========================*/ - *tinstr = FBT_CALL((uintptr_t)tinstr - base + va, dtrace_probe); - tinstr++; - - if (FBT_FMT3_RD(restore) == FBT_REG_O0) { - /* - * If the destination register of the restore is %o0, we - * need to perform the implied calculation to derive the - * return value. - */ - uint32_t add = (restore & ~FBT_FMT3_OP_MASK) | FBT_OP_ADD; - add &= ~FBT_FMT3_RD_MASK; - *tinstr++ = add | (FBT_REG_O2 << FBT_FMT3_RD_SHIFT); - } else { - *tinstr++ = FBT_MOV(FBT_REG_I0, FBT_REG_O2); - } - - /* - * If the control transfer instruction is %pc-relative (i.e. a - * call), we need to reset it appropriately. - */ - if (FBT_FMT1_OP(cti) == FBT_OP_CALL) { - dest = (uintptr_t)instr + (FBT_FMT1_DISP30(cti) << 2); - *tinstr = FBT_CALL((uintptr_t)tinstr - base + va, dest); - tinstr++; - } else { - *tinstr++ = cti; - } - - *tinstr++ = restore; - tramp->fbtt_va += (uintptr_t)tinstr - tramp->fbtt_next; - tramp->fbtt_next = (uintptr_t)tinstr; - - return (FBT_BAA(instr, va)); -} - -static uint32_t -fbt_patch_retl(uint32_t *instr, uint32_t *funcbase, uint32_t *funclim, - int offset, uint32_t id, fbt_trampoline_t *tramp, const char *name) -{ - uint32_t *tinstr = (uint32_t *)tramp->fbtt_next; - uintptr_t va = tramp->fbtt_va; - uintptr_t base = tramp->fbtt_next; - uint32_t cti = *instr, dest; - int annul = 0; - - FBT_COUNTER(id, fbt_retl); - - if (tramp->fbtt_next + FBT_RETLENT_MAXSIZE > tramp->fbtt_limit) { - /* - * There isn't sufficient room for this entry; return failure. - */ - return (FBT_ILLTRAP); - } - - if (offset == sizeof (uint32_t) && - fbt_canpatch_retl(instr - 1, 0, name)) { - *tinstr++ = *instr; - annul = 1; - FBT_COUNTER(id, fbt_retl_twoinstr); - } else { - if (FBT_FMT3_OP(cti) == FBT_OP_JMPL && - FBT_FMT3_RD(cti) != FBT_REG_O7 && - FBT_FMT3_RS1(cti) != FBT_REG_O7) { - annul = 1; - *tinstr++ = *(instr + 1); - } - } - - *tinstr++ = FBT_SAVEIMM(FBT_REG_O6, -SA(MINFRAME), FBT_REG_O6); - - if (FBT_FMT3_OP(cti) == FBT_OP_JMPL) { - uint32_t rs1, rs2, o2i = FBT_REG_I0 - FBT_REG_O0; - - /* - * If we have a jmpl and it's in terms of output registers, we - * need to rewrite it to be in terms of the corresponding input - * registers. If it's in terms of the globals, we'll rewrite - * it to be in terms of locals. - */ - rs1 = FBT_FMT3_RS1(cti); - - if (FBT_REG_ISOUTPUT(rs1)) - rs1 += o2i; - - if (FBT_REG_ISGLOBAL(rs1)) { - *tinstr++ = FBT_MOV(rs1, FBT_REG_L0); - rs1 = FBT_REG_L0; - } - - FBT_FMT3_RS1_SET(cti, rs1); - - if (!FBT_FMT3_ISIMM(cti)) { - rs2 = FBT_FMT3_RS2(cti); - - if (FBT_REG_ISOUTPUT(rs2)) - rs2 += o2i; - - if (FBT_REG_ISGLOBAL(rs2)) { - *tinstr++ = FBT_MOV(rs2, FBT_REG_L1); - rs2 = FBT_REG_L1; - } - - FBT_FMT3_RS2_SET(cti, rs2); - } - - /* - * Now we need to check the rd and source register for the jmpl; - * If neither rd nor the source register is %o7, then we might - * have a jmp that is actually part of a jump table. We need - * to generate the code to compare it to the base and limit of - * the function. - */ - if (FBT_FMT3_RD(cti) != FBT_REG_O7 && rs1 != FBT_REG_I7) { - uintptr_t base = (uintptr_t)funcbase; - uintptr_t limit = (uintptr_t)funclim; - - FBT_COUNTER(id, fbt_retl_jmptab); - - if (FBT_FMT3_ISIMM(cti)) { - *tinstr++ = FBT_ADDSIMM13(rs1, - FBT_FMT3_SIMM13(cti), FBT_REG_L2); - } else { - *tinstr++ = FBT_ADD(rs1, rs2, FBT_REG_L2); - } - - *tinstr++ = FBT_SETHI(base, FBT_REG_L3); - *tinstr++ = FBT_ORLO(FBT_REG_L3, base, FBT_REG_L3); - *tinstr++ = FBT_CMP(FBT_REG_L2, FBT_REG_L3); - *tinstr++ = FBT_BL(0, 8 * sizeof (uint32_t)); - *tinstr++ = FBT_SETHI(limit, FBT_REG_L3); - *tinstr++ = FBT_ORLO(FBT_REG_L3, limit, FBT_REG_L3); - *tinstr++ = FBT_CMP(FBT_REG_L2, FBT_REG_L3); - *tinstr++ = FBT_BGE(0, 4 * sizeof (uint32_t)); - *tinstr++ = FBT_SETHI(0, FBT_REG_G0); - *tinstr++ = cti; - *tinstr++ = FBT_RESTORE(FBT_REG_G0, - FBT_REG_G0, FBT_REG_G0); - } - } - - if (id > (uint32_t)FBT_SIMM13_MAX) { - *tinstr++ = FBT_SETHI(id, FBT_REG_O0); - *tinstr++ = FBT_ORLO(FBT_REG_O0, id, FBT_REG_O0); - } else { - *tinstr++ = FBT_ORSIMM13(FBT_REG_G0, id, FBT_REG_O0); - } - - if (offset > (uint32_t)FBT_SIMM13_MAX) { - *tinstr++ = FBT_SETHI(offset, FBT_REG_O1); - *tinstr++ = FBT_ORLO(FBT_REG_O1, offset, FBT_REG_O1); - } else { - *tinstr++ = FBT_ORSIMM13(FBT_REG_G0, offset, FBT_REG_O1); - } - - *tinstr = FBT_CALL((uintptr_t)tinstr - base + va, dtrace_probe); - tinstr++; - *tinstr++ = FBT_MOV(FBT_REG_I0, FBT_REG_O2); - - /* - * If the control transfer instruction is %pc-relative (i.e. a - * call), we need to reset it appropriately. - */ - if (FBT_FMT1_OP(cti) == FBT_OP_CALL) { - FBT_COUNTER(id, fbt_retl_tailcall); - dest = (uintptr_t)instr + (FBT_FMT1_DISP30(cti) << 2); - *tinstr = FBT_CALL((uintptr_t)tinstr - base + va, dest); - tinstr++; - annul = 1; - } else { - if (FBT_FMT3_OP(cti) == FBT_OP_JMPL) { - *tinstr++ = cti; - - if (FBT_FMT3_RD(cti) == FBT_REG_O7) { - FBT_COUNTER(id, fbt_retl_tailjmpl); - annul = 1; - } - } else { - *tinstr++ = FBT_RET; - } - } - - *tinstr++ = FBT_RESTORE(FBT_REG_G0, FBT_REG_G0, FBT_REG_G0); - - tramp->fbtt_va += (uintptr_t)tinstr - tramp->fbtt_next; - tramp->fbtt_next = (uintptr_t)tinstr; - - return (annul ? FBT_BAA(instr, va) : FBT_BA(instr, va)); -} +/*------------------------------------------------------------------*/ +/* */ +/* Name - fbt_provide_module. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ /*ARGSUSED*/ static void fbt_provide_module(void *arg, struct modctl *ctl) { struct module *mp = ctl->mod_mp; - char *modname = ctl->mod_modname; - char *str = mp->strings; - int nsyms = mp->nsyms; - Shdr *symhdr = mp->symhdr; - size_t symsize; - char *name; - int i; + char *str = mp->strings; + int nsyms = mp->nsyms; + Shdr *symhdr = mp->symhdr; + char *modname = ctl->mod_modname; + char *name; + RSY1_t *rsy; + RR_t *rr; fbt_probe_t *fbt, *retfbt; - fbt_trampoline_t tramp; - uintptr_t offset; - int primary = 0; - ctf_file_t *fp = NULL; - int error; - int estimate = 1; - uint32_t faketramp[50]; - size_t fbt_size = 0; + size_t symsize; + int i, size; + uint8_t fmt; /* * Employees of dtrace and their families are ineligible. Void @@ -1062,42 +358,10 @@ return; } - if (mp->fbt_tab != NULL) - estimate = 0; - - /* - * This is a hack for unix/genunix/krtld. - */ - primary = vmem_contains(heap_arena, (void *)ctl, - sizeof (struct modctl)) == 0; - kobj_textwin_alloc(mp); - - /* - * Open the CTF data for the module. We'll use this to determine the - * functions that can be instrumented. Note that this call can fail, - * in which case we'll use heuristics to determine the functions that - * can be instrumented. (But in particular, leaf functions will not be - * instrumented.) - */ - fp = ctf_modopen(mp, &error); - -forreal: - if (!estimate) { - tramp.fbtt_next = - (uintptr_t)fbt_trampoline_map((uintptr_t)mp->fbt_tab, - mp->fbt_size); - tramp.fbtt_limit = tramp.fbtt_next + mp->fbt_size; - tramp.fbtt_va = (uintptr_t)mp->fbt_tab; - } - for (i = 1; i < nsyms; i++) { - ctf_funcinfo_t f; - uint32_t *instr, *base, *limit; + uint8_t *instr, *limit; Sym *sym = (Sym *)(symhdr->sh_addr + i * symsize); - int have_ctf = 0, is_leaf = 0, nargs, cti = 0; - int (*canpatch)(uint32_t *, int, const char *); - uint32_t (*patch)(uint32_t *, uint32_t *, uint32_t *, int, - uint32_t, fbt_trampoline_t *, const char *); + int j; if (ELF_ST_TYPE(sym->st_info) != STT_FUNC) continue; @@ -1134,47 +398,6 @@ continue; } - if (strstr(name, "__relocatable") != NULL) { - /* - * Anything with the string "__relocatable" anywhere - * in the function name is considered to be a function - * that may be manually relocated before execution. - * Because FBT uses a PC-relative technique for - * instrumentation, these functions cannot safely - * be instrumented by us. - */ - continue; - } - - if (strstr(name, "ip_ocsum") == name) { - /* - * The ip_ocsum_* family of routines are all ABI - * violators. (They expect incoming arguments in the - * globals!) Break the ABI? No soup for you! - */ - continue; - } - - /* - * We want to scan the function for one (and only one) save. - * Any more indicates that something fancy is going on. - */ - base = (uint32_t *)sym->st_value; - limit = (uint32_t *)(sym->st_value + sym->st_size); - - /* - * We don't want to interpose on the module stubs. - */ - if (base >= (uint32_t *)stubs_base && - base <= (uint32_t *)stubs_end) - continue; - - /* - * We can't safely trace a zero-length function... - */ - if (base == limit) - continue; - /* * Due to 4524008, _init and _fini may have a bloated st_size. * While this bug was fixed quite some time ago, old drivers @@ -1194,335 +417,194 @@ if (strcmp(name, "_fini") == 0) continue; - instr = base; - /* - * While we try hard to only trace safe functions (that is, - * functions at TL=0), one unsafe function manages to otherwise - * appear safe: prom_trap(). We could discover prom_trap() - * if we added an additional rule: in order to trace a - * function, we must either (a) discover a restore or (b) - * determine that the function does not have any unlinked - * control transfers to another function (i.e., the function - * never returns). Unfortunately, as of this writing, one - * legitimate function (resume_from_zombie()) transfers - * control to a different function (_resume_from_idle()) - * without executing a restore. Barring a rule to figure out - * that resume_from_zombie() is safe while prom_trap() is not, - * we resort to hard-coding prom_trap() here. + * In order to be eligible, the function must begin with the + * following sequence: + * + * stmg %rx,%ry,xxx */ - if (strcmp(name, "prom_trap") == 0) - continue; - - if (fp != NULL && ctf_func_info(fp, i, &f) != CTF_ERR) { - nargs = f.ctc_argc; - have_ctf = 1; - } else { - nargs = 32; - } - - /* - * If the first instruction of the function is a branch and - * it's not a branch-always-not-annulled, we're going to refuse - * to patch it. - */ - if ((*instr & FBT_OP_MASK) == FBT_OP0 && - (*instr & FBT_FMT2_OP2_MASK) != FBT_FMT2_OP2_SETHI && - (*instr & FBT_FMT2_OP2_MASK) != FBT_FMT2_OP2_BPR) { - if (!FBT_IS_BA(*instr) && !FBT_IS_BAPCC(*instr)) { - if (have_ctf) { - cmn_err(CE_NOTE, "cannot instrument %s:" - " begins with non-ba, " - "non-br CTI", name); - } - continue; - } - } - - while (!FBT_IS_SAVE(*instr)) { - /* - * Before we assume that this is a leaf routine, check - * forward in the basic block for a save. - */ - int op = *instr & FBT_OP_MASK; - int op2 = *instr & FBT_FMT2_OP2_MASK; + instr = (uint8_t *)sym->st_value; + limit = (uint8_t *)(sym->st_value + sym->st_size); - if (op == FBT_OP0 && op2 != FBT_FMT2_OP2_SETHI) { - /* - * This is a CTI. If we see a subsequent - * save, we will refuse to process this - * routine unless both of the following are - * true: - * - * (a) The branch is not annulled - * - * (b) The subsequent save is in the delay - * slot of the branch - */ - if ((*instr & FBT_ANNUL) || - !FBT_IS_SAVE(*(instr + 1))) { - cti = 1; - } else { - instr++; - break; - } - } - - if (op == FBT_OP1) - cti = 1; - - if (++instr == limit) + while (instr < limit) { + if ((size = dtrace_getfmtlen(instr, &fmt)) <= 0) break; - } - if (instr < limit && cti) { - /* - * If we found a CTI before the save, we need to not - * do anything. But if we have CTF information, this - * is weird enough that it merits a message. - */ - if (!have_ctf) - continue; - - cmn_err(CE_NOTE, "cannot instrument %s: " - "save not in first basic block", name); - continue; - } - - if (instr == limit) { - if (!have_ctf) - continue; - is_leaf = 1; - - if (!estimate) - fbt_leaf_functions++; - - canpatch = fbt_canpatch_retl; - patch = fbt_patch_retl; - } else { - canpatch = fbt_canpatch_return; - patch = fbt_patch_return; - } - - if (!have_ctf && !is_leaf) { - /* - * Before we assume that this isn't something tricky, - * look for other saves. If we find them, there are - * multiple entry points here (or something), and we'll - * leave it alone. - */ - while (++instr < limit) { - if (FBT_IS_SAVE(*instr)) + if (fmt == IFMT_RSY1) { + rsy = (RSY1_t *) instr; + if ((rsy->op1 == OP_STMG1) && (rsy->op2 == OP_STMG2)) break; } - if (instr != limit) - continue; + instr += size; + } + + if (instr >= limit) { + /* + * We either don't save the frame pointer in this + * function, or we ran into some disassembly + * screw-up. Either way, we bail. + */ + continue; } - instr = base; - - if (FBT_IS_CTI(*instr)) { - /* - * If we have a CTI, we want to be sure that we don't - * have a CTI or a PC-relative instruction in the - * delay slot -- we want to be able to thunk the - * instruction into the trampoline without worrying - * about either DCTIs or relocations. It would be - * very odd for the compiler to generate this kind of - * code, so we warn about it if we have CTF - * information. - */ - if (FBT_IS_CTI(*(instr + 1))) { - if (!have_ctf) - continue; - - cmn_err(CE_NOTE, "cannot instrument %s: " - "CTI in delay slot of first instruction", - name); - continue; - } - - if (FBT_IS_PCRELATIVE(*(instr + 1))) { - if (!have_ctf) - continue; + fbt = kmem_zalloc(sizeof (fbt_probe_t), KM_SLEEP); + fbt->fbtp_name = name; + fbt->fbtp_id = dtrace_probe_create(fbt_id, modname, name, + FBT_ENTRY, 3, fbt); + fbt->fbtp_patchpoint = instr; + fbt->fbtp_ctl = ctl; + fbt->fbtp_loadcnt = ctl->mod_loadcnt; + fbt->fbtp_rval = DTRACE_INVOP_STMG; + fbt->fbtp_savedval = *instr; + fbt->fbtp_patchval = FBT_PATCHVAL; - cmn_err(CE_NOTE, "cannot instrument %s: " - "PC-relative instruction in delay slot of" - " first instruction", name); - continue; - } - } + fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)]; + fbt->fbtp_symndx = i; + fbt_probetab[FBT_ADDR2NDX(instr)] = fbt; - if (estimate) { - tramp.fbtt_next = (uintptr_t)faketramp; - tramp.fbtt_limit = tramp.fbtt_next + sizeof (faketramp); - (void) fbt_patch_entry(instr, FBT_ESTIMATE_ID, - &tramp, nargs); - fbt_size += tramp.fbtt_next - (uintptr_t)faketramp; - } else { - fbt = kmem_zalloc(sizeof (fbt_probe_t), KM_SLEEP); - fbt->fbtp_name = name; - fbt->fbtp_ctl = ctl; - fbt->fbtp_id = dtrace_probe_create(fbt_id, modname, - name, FBT_PROBENAME_ENTRY, 1, fbt); - fbt->fbtp_patchval = FBT_BAA(instr, tramp.fbtt_va); - - if (!fbt_patch_entry(instr, fbt->fbtp_id, - &tramp, nargs)) { - cmn_err(CE_WARN, "unexpectedly short FBT table " - "in module %s (sym %d of %d)", modname, - i, nsyms); - break; - } - - fbt->fbtp_patchpoint = - (uint32_t *)((uintptr_t)mp->textwin + - ((uintptr_t)instr - (uintptr_t)mp->text)); - fbt->fbtp_savedval = *instr; - - fbt->fbtp_loadcnt = ctl->mod_loadcnt; - fbt->fbtp_primary = primary; - fbt->fbtp_symndx = i; - mp->fbt_nentries++; - } + mp->fbt_nentries++; retfbt = NULL; again: - if (++instr == limit) + if (instr >= limit) + continue; + + /* + * If this disassembly fails, then we've likely walked off into + * a jump table or some other unsuitable area. Bail out of the + * disassembly now. + */ + if ((size = dtrace_getfmtlen(instr, &fmt)) <= 0) continue; - offset = (uintptr_t)instr - (uintptr_t)base; - - if (!(*canpatch)(instr, offset, name)) - goto again; + /* + * We only instrument BR %r14 or BR %r4 to avoid matching + * against a jump table. + */ + if (fmt == IFMT_RR) { + rr = (RR_t *) instr; - if (estimate) { - tramp.fbtt_next = (uintptr_t)faketramp; - tramp.fbtt_limit = tramp.fbtt_next + sizeof (faketramp); - (void) (*patch)(instr, base, limit, - offset, FBT_ESTIMATE_ID, &tramp, name); - fbt_size += tramp.fbtt_next - (uintptr_t)faketramp; - - goto again; + if (!((rr->opcode = OP_BR) && (rr->r1 == UNC) && + ((rr->r2 == R14) || (rr->r2 == R4)))) { + instr += size; + goto again; + } } - fbt = kmem_zalloc(sizeof (fbt_probe_t), KM_SLEEP); - fbt->fbtp_name = name; - fbt->fbtp_ctl = ctl; + fbt = kmem_zalloc(sizeof (fbt_probe_t), KM_SLEEP); + fbt->fbtp_name = name; if (retfbt == NULL) { fbt->fbtp_id = dtrace_probe_create(fbt_id, modname, - name, FBT_PROBENAME_RETURN, 1, fbt); + name, FBT_RETURN, + 3, fbt); } else { retfbt->fbtp_next = fbt; - fbt->fbtp_id = retfbt->fbtp_id; + fbt->fbtp_id = retfbt->fbtp_id; } - fbt->fbtp_return = 1; - retfbt = fbt; + retfbt = fbt; + fbt->fbtp_patchpoint = instr; + fbt->fbtp_ctl = ctl; + fbt->fbtp_loadcnt = ctl->mod_loadcnt; - if ((fbt->fbtp_patchval = (*patch)(instr, base, limit, offset, - fbt->fbtp_id, &tramp, name)) == FBT_ILLTRAP) { - cmn_err(CE_WARN, "unexpectedly short FBT table " - "in module %s (sym %d of %d)", modname, i, nsyms); - break; - } + fbt->fbtp_rval = DTRACE_INVOP_RET; + fbt->fbtp_roffset = (uintptr_t)(instr - (uint8_t *)sym->st_value); - fbt->fbtp_patchpoint = (uint32_t *)((uintptr_t)mp->textwin + - ((uintptr_t)instr - (uintptr_t)mp->text)); - fbt->fbtp_savedval = *instr; - fbt->fbtp_loadcnt = ctl->mod_loadcnt; - fbt->fbtp_primary = primary; - fbt->fbtp_symndx = i; + fbt->fbtp_savedval = *instr; + fbt->fbtp_patchval = FBT_PATCHVAL; + fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)]; + fbt->fbtp_symndx = i; + fbt_probetab[FBT_ADDR2NDX(instr)] = fbt; + mp->fbt_nentries++; + instr += size; goto again; } +} - if (estimate) { - /* - * Slosh on another entry's worth... - */ - fbt_size += FBT_ENT_MAXSIZE; - mp->fbt_size = fbt_size; - mp->fbt_tab = kobj_texthole_alloc(mp->text, fbt_size); +/*========================= End of Function ========================*/ - if (mp->fbt_tab == NULL) { - cmn_err(CE_WARN, "couldn't allocate FBT table " - "for module %s", modname); - } else { - estimate = 0; - goto forreal; - } - } else { - fbt_trampoline_unmap(); - } - -error: - if (fp != NULL) - ctf_close(fp); -} +/*------------------------------------------------------------------*/ +/* */ +/* Name - fbt_destroy. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ /*ARGSUSED*/ static void fbt_destroy(void *arg, dtrace_id_t id, void *parg) { - fbt_probe_t *fbt = parg, *next; + fbt_probe_t *fbt = parg, *next, *hash, *last; struct modctl *ctl = fbt->fbtp_ctl; + int ndx; do { if (ctl != NULL && ctl->mod_loadcnt == fbt->fbtp_loadcnt) { if ((ctl->mod_loadcnt == fbt->fbtp_loadcnt && - ctl->mod_loaded) || fbt->fbtp_primary) { + ctl->mod_loaded)) { ((struct module *) (ctl->mod_mp))->fbt_nentries--; } } + /* + * Now we need to remove this probe from the fbt_probetab. + */ + ndx = FBT_ADDR2NDX(fbt->fbtp_patchpoint); + last = NULL; + hash = fbt_probetab[ndx]; + + while (hash != fbt) { + ASSERT(hash != NULL); + last = hash; + hash = hash->fbtp_hashnext; + } + + if (last != NULL) { + last->fbtp_hashnext = fbt->fbtp_hashnext; + } else { + fbt_probetab[ndx] = fbt->fbtp_hashnext; + } + next = fbt->fbtp_next; kmem_free(fbt, sizeof (fbt_probe_t)); + fbt = next; } while (fbt != NULL); } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - fbt_enable. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + /*ARGSUSED*/ -static void +static int fbt_enable(void *arg, dtrace_id_t id, void *parg) { - fbt_probe_t *fbt = parg, *f; + fbt_probe_t *fbt = parg; struct modctl *ctl = fbt->fbtp_ctl; ctl->mod_nenabled++; - for (f = fbt; f != NULL; f = f->fbtp_next) { - if (f->fbtp_patchpoint == NULL) { - /* - * Due to a shortened FBT table, this entry was never - * completed; refuse to enable it. - */ - if (fbt_verbose) { - cmn_err(CE_NOTE, "fbt is failing for probe %s " - "(short FBT table in %s)", - fbt->fbtp_name, ctl->mod_modname); - } - - return; - } - } - - /* - * If this module has disappeared since we discovered its probes, - * refuse to enable it. - */ - if (!fbt->fbtp_primary && !ctl->mod_loaded) { + if (!ctl->mod_loaded) { if (fbt_verbose) { cmn_err(CE_NOTE, "fbt is failing for probe %s " "(module %s unloaded)", fbt->fbtp_name, ctl->mod_modname); } - return; + return (0); } /* @@ -1537,36 +619,52 @@ fbt->fbtp_name, ctl->mod_modname); } - return; + return (0); } for (; fbt != NULL; fbt = fbt->fbtp_next) *fbt->fbtp_patchpoint = fbt->fbtp_patchval; + + return (0); } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - fbt_disable. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + /*ARGSUSED*/ static void fbt_disable(void *arg, dtrace_id_t id, void *parg) { - fbt_probe_t *fbt = parg, *f; + fbt_probe_t *fbt = parg; struct modctl *ctl = fbt->fbtp_ctl; ASSERT(ctl->mod_nenabled > 0); ctl->mod_nenabled--; - for (f = fbt; f != NULL; f = f->fbtp_next) { - if (f->fbtp_patchpoint == NULL) - return; - } - - if ((!fbt->fbtp_primary && !ctl->mod_loaded) || - (ctl->mod_loadcnt != fbt->fbtp_loadcnt)) + if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt)) return; for (; fbt != NULL; fbt = fbt->fbtp_next) *fbt->fbtp_patchpoint = fbt->fbtp_savedval; } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - fbt_suspend. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + /*ARGSUSED*/ static void fbt_suspend(void *arg, dtrace_id_t id, void *parg) @@ -1574,18 +672,25 @@ fbt_probe_t *fbt = parg; struct modctl *ctl = fbt->fbtp_ctl; - if (!fbt->fbtp_primary && !ctl->mod_loaded) - return; + ASSERT(ctl->mod_nenabled > 0); - if (ctl->mod_loadcnt != fbt->fbtp_loadcnt) + if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt)) return; - ASSERT(ctl->mod_nenabled > 0); - for (; fbt != NULL; fbt = fbt->fbtp_next) *fbt->fbtp_patchpoint = fbt->fbtp_savedval; } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - fbt_resume. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + /*ARGSUSED*/ static void fbt_resume(void *arg, dtrace_id_t id, void *parg) @@ -1593,18 +698,25 @@ fbt_probe_t *fbt = parg; struct modctl *ctl = fbt->fbtp_ctl; - if (!fbt->fbtp_primary && !ctl->mod_loaded) - return; + ASSERT(ctl->mod_nenabled > 0); - if (ctl->mod_loadcnt != fbt->fbtp_loadcnt) + if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt)) return; - ASSERT(ctl->mod_nenabled > 0); - for (; fbt != NULL; fbt = fbt->fbtp_next) *fbt->fbtp_patchpoint = fbt->fbtp_patchval; } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - fbt_getargdesc. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + /*ARGSUSED*/ static void fbt_getargdesc(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc) @@ -1622,7 +734,7 @@ if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt)) goto err; - if (fbt->fbtp_return && desc->dtargd_ndx == 0) { + if (fbt->fbtp_roffset != 0 && desc->dtargd_ndx == 0) { (void) strcpy(desc->dtargd_native, "int"); return; } @@ -1639,22 +751,26 @@ * If we have a parent container, we must manually import it. */ if ((parent = ctf_parent_name(fp)) != NULL) { - struct modctl *mod; + struct modctl *mp = &modules; + struct modctl *mod = NULL; /* * We must iterate over all modules to find the module that * is our parent. */ - for (mod = &modules; mod != NULL; mod = mod->mod_next) { - if (strcmp(mod->mod_filename, parent) == 0) + do { + if (strcmp(mp->mod_modname, parent) == 0) { + mod = mp; break; - } + } + } while ((mp = mp->mod_next) != &modules); if (mod == NULL) goto err; - if ((pfp = ctf_modopen(mod->mod_mp, &error)) == NULL) + if ((pfp = ctf_modopen(mod->mod_mp, &error)) == NULL) { goto err; + } if (ctf_import(fp, pfp) != 0) { ctf_close(pfp); @@ -1667,7 +783,7 @@ if (ctf_func_info(fp, fbt->fbtp_symndx, &f) == CTF_ERR) goto err; - if (fbt->fbtp_return) { + if (fbt->fbtp_roffset != 0) { if (desc->dtargd_ndx > 1) goto err; @@ -1695,26 +811,35 @@ desc->dtargd_ndx = DTRACE_ARGNONE; } -static dtrace_pattr_t fbt_attr = { -{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -}; +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - fbt_cleanup. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ -static dtrace_pops_t fbt_pops = { - NULL, - fbt_provide_module, - fbt_enable, - fbt_disable, - fbt_suspend, - fbt_resume, - fbt_getargdesc, - NULL, - NULL, - fbt_destroy -}; +static void +fbt_cleanup(dev_info_t *devi) +{ + dtrace_invop_remove(fbt_invop); + ddi_remove_minor_node(devi, NULL); + kmem_free(fbt_probetab, fbt_probetab_size * sizeof (fbt_probe_t *)); + fbt_probetab = NULL; + fbt_probetab_mask = 0; +} + +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - fbt_attach. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ static int fbt_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) @@ -1728,19 +853,39 @@ return (DDI_FAILURE); } + if (fbt_probetab_size == 0) + fbt_probetab_size = FBT_PROBETAB_SIZE; + + fbt_probetab_mask = fbt_probetab_size - 1; + fbt_probetab = + kmem_zalloc(fbt_probetab_size * sizeof (fbt_probe_t *), KM_SLEEP); + + dtrace_invop_add(fbt_invop); + if (ddi_create_minor_node(devi, "fbt", S_IFCHR, 0, DDI_PSEUDO, NULL) == DDI_FAILURE || - dtrace_register("fbt", &fbt_attr, DTRACE_PRIV_KERNEL, 0, + dtrace_register("fbt", &fbt_attr, DTRACE_PRIV_KERNEL, NULL, &fbt_pops, NULL, &fbt_id) != 0) { - ddi_remove_minor_node(devi, NULL); + fbt_cleanup(devi); return (DDI_FAILURE); } ddi_report_dev(devi); fbt_devi = devi; + return (DDI_SUCCESS); } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - fbt_detach. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + static int fbt_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) { @@ -1756,10 +901,21 @@ if (dtrace_unregister(fbt_id) != 0) return (DDI_FAILURE); - ddi_remove_minor_node(devi, NULL); + fbt_cleanup(devi); + return (DDI_SUCCESS); } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - fbt_info. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + /*ARGSUSED*/ static int fbt_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) @@ -1781,6 +937,16 @@ return (error); } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - fbt_open. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + /*ARGSUSED*/ static int fbt_open(dev_t *devp, int flag, int otyp, cred_t *cred_p) @@ -1788,52 +954,15 @@ return (0); } -static struct cb_ops fbt_cb_ops = { - fbt_open, /* open */ - nodev, /* close */ - nulldev, /* strategy */ - nulldev, /* print */ - nodev, /* dump */ - nodev, /* read */ - nodev, /* write */ - nodev, /* ioctl */ - nodev, /* devmap */ - nodev, /* mmap */ - nodev, /* segmap */ - nochpoll, /* poll */ - ddi_prop_op, /* cb_prop_op */ - 0, /* streamtab */ - D_NEW | D_MP /* Driver compatibility flag */ -}; +/*========================= End of Function ========================*/ -static struct dev_ops fbt_ops = { - DEVO_REV, /* devo_rev */ - 0, /* refcnt */ - fbt_info, /* get_dev_info */ - nulldev, /* identify */ - nulldev, /* probe */ - fbt_attach, /* attach */ - fbt_detach, /* detach */ - nodev, /* reset */ - &fbt_cb_ops, /* driver operations */ - NULL, /* bus operations */ - nodev /* dev power */ -}; - -/* - * Module linkage information for the kernel. - */ -static struct modldrv modldrv = { - &mod_driverops, /* module type (this is a pseudo driver) */ - "Function Boundary Tracing", /* name of module */ - &fbt_ops, /* driver ops */ -}; - -static struct modlinkage modlinkage = { - MODREV_1, - (void *)&modldrv, - NULL -}; +/*------------------------------------------------------------------*/ +/* */ +/* Name - _init. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ int _init(void) @@ -1841,14 +970,50 @@ return (mod_install(&modlinkage)); } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - _info. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + int _info(struct modinfo *modinfop) { return (mod_info(&modlinkage, modinfop)); } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - _fini. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + + int _fini(void) { return (mod_remove(&modlinkage)); } + +/*========================= End of Function ========================*/ + + + + + + + + + + + + +
--- a/usr/src/uts/zSeries/dtrace/fbt.conf Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/uts/zSeries/dtrace/fbt.conf Thu Oct 08 12:44:34 2009 -0400 @@ -23,6 +23,5 @@ # Copyright 2003 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#ident "@(#)fbt.conf 1.2 05/06/08 SMI" name="fbt" parent="pseudo" instance=0;
--- a/usr/src/uts/zSeries/dtrace/sdt.c Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/uts/zSeries/dtrace/sdt.c Thu Oct 08 12:44:34 2009 -0400 @@ -1,33 +1,67 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END +/*------------------------------------------------------------------*/ +/* */ +/* Name - sdt.c */ +/* */ +/* Function - Platform specific support for Dtrace SDT. */ +/* */ +/* Name - Neale Ferguson */ +/* */ +/* Date - October, 2009 */ +/* */ +/*------------------------------------------------------------------*/ + +/*------------------------------------------------------------------*/ +/* L I C E N S E */ +/*------------------------------------------------------------------*/ + +/*==================================================================*/ +/* */ +/* CDDL HEADER START */ +/* */ +/* The contents of this file are subject to the terms of the */ +/* Common Development and Distribution License (the "License"). */ +/* You may not use this file except in compliance the the License. */ +/* */ +/* You can obtain a copy of the license at: */ +/* - usr/src/OPENSOLARIS.LICENSE, or, */ +/* - http://www.opensolaris.org/os/licensing. */ +/* See the License for the specific language governing permissions */ +/* and limitations under the License. */ +/* */ +/* When distributing Covered Code, include this CDDL HEADER in each */ +/* file and include the License file at usr/src/OPENSOLARIS.LICENSE.*/ +/* If applicable, add the following below this CDDL HEADER, with */ +/* the fields enclosed by brackets "[]" replaced with your own */ +/* identifying information: */ +/* Portions Copyright [yyyy] [name of copyright owner] */ +/* */ +/* CDDL HEADER END */ /* */ /* Copyright 2008 Sine Nomine Associates. */ /* All rights reserved. */ /* Use is subject to license terms. */ - */ -/* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ +/* */ +/* Copyright 2004 Sun Microsystems, Inc. All rights reserved. */ +/* Use is subject to license terms. */ +/* */ +/*==================================================================*/ + +/*------------------------------------------------------------------*/ +/* D e f i n e s */ +/*------------------------------------------------------------------*/ +#define SDT_PATCHVAL 0xf0 +#define SDT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & sdt_probetab_mask) +#define SDT_PROBETAB_SIZE 0x1000 /* 4k entries -- 16K total */ + +/*========================= End of Defines =========================*/ + +/*------------------------------------------------------------------*/ +/* I n c l u d e s */ +/*------------------------------------------------------------------*/ + +#include <sys/types.h> +#include <sys/asm_linkage.h> #include <sys/modctl.h> #include <sys/sunddi.h> #include <sys/dtrace.h> @@ -36,309 +70,56 @@ #include <sys/conf.h> #include <vm/seg_kmem.h> #include <sys/stack.h> +#include <sys/frame.h> +#include <sys/dtrace_impl.h> +#include <sys/cmn_err.h> +#include <sys/sysmacros.h> +#include <sys/privregs.h> #include <sys/sdt_impl.h> +/*========================= End of Includes ========================*/ + +/*------------------------------------------------------------------*/ +/* T y p e d e f s */ +/*------------------------------------------------------------------*/ + + +/*========================= End of Typedefs ========================*/ + +/*------------------------------------------------------------------*/ +/* E x t e r n a l R e f e r e n c e s */ +/*------------------------------------------------------------------*/ + + +/*=================== End of External References ===================*/ + +/*------------------------------------------------------------------*/ +/* P r o t o t y p e s */ +/*------------------------------------------------------------------*/ + +static int sdt_open(dev_t *, int, int, cred_t *); +static int sdt_info(dev_info_t *, ddi_info_cmd_t, void *, void **); +static int sdt_attach(dev_info_t *, ddi_attach_cmd_t); +static int sdt_detach(dev_info_t *, ddi_detach_cmd_t); +static int sdt_enable(void *, dtrace_id_t, void *); +static void sdt_provide_module(void *, struct modctl *); +static void sdt_disable(void *, dtrace_id_t, void *); +static void sdt_suspend(void *, dtrace_id_t, void *); +static void sdt_resume(void *, dtrace_id_t, void *); +static void sdt_cleanup(dev_info_t *); +static void sdt_destroy(void *, dtrace_id_t, void *); + +/*========================= End of Prototypes ======================*/ + +/*------------------------------------------------------------------*/ +/* G l o b a l V a r i a b l e s */ +/*------------------------------------------------------------------*/ + static dev_info_t *sdt_devi; - -int sdt_verbose = 0; - -#define SDT_REG_G0 0 -#define SDT_REG_O0 8 -#define SDT_REG_O1 9 -#define SDT_REG_O2 10 -#define SDT_REG_O3 11 -#define SDT_REG_O4 12 -#define SDT_REG_O5 13 -#define SDT_REG_I0 24 -#define SDT_REG_I1 25 -#define SDT_REG_I2 26 -#define SDT_REG_I3 27 -#define SDT_REG_I4 28 -#define SDT_REG_I5 29 - -#define SDT_SIMM13_MASK 0x1fff -#define SDT_SIMM13_MAX ((int32_t)0xfff) -#define SDT_CALL(from, to) (((uint32_t)1 << 30) | \ - (((uintptr_t)(to) - (uintptr_t)(from) >> 2) & \ - 0x3fffffff)) -#define SDT_SAVE (0x9de3a000 | (-SA(MINFRAME) & SDT_SIMM13_MASK)) -#define SDT_RET 0x81c7e008 -#define SDT_RESTORE 0x81e80000 - -#define SDT_OP_SETHI 0x1000000 -#define SDT_OP_OR 0x80100000 - -#define SDT_FMT2_RD_SHIFT 25 -#define SDT_IMM22_SHIFT 10 -#define SDT_IMM22_MASK 0x3fffff -#define SDT_IMM10_MASK 0x3ff - -#define SDT_FMT3_RD_SHIFT 25 -#define SDT_FMT3_RS1_SHIFT 14 -#define SDT_FMT3_RS2_SHIFT 0 -#define SDT_FMT3_IMM (1 << 13) - -#define SDT_MOV(rs, rd) \ - (SDT_OP_OR | (SDT_REG_G0 << SDT_FMT3_RS1_SHIFT) | \ - ((rs) << SDT_FMT3_RS2_SHIFT) | ((rd) << SDT_FMT3_RD_SHIFT)) - -#define SDT_ORLO(rs, val, rd) \ - (SDT_OP_OR | ((rs) << SDT_FMT3_RS1_SHIFT) | \ - ((rd) << SDT_FMT3_RD_SHIFT) | SDT_FMT3_IMM | ((val) & SDT_IMM10_MASK)) - -#define SDT_ORSIMM13(rs, val, rd) \ - (SDT_OP_OR | ((rs) << SDT_FMT3_RS1_SHIFT) | \ - ((rd) << SDT_FMT3_RD_SHIFT) | SDT_FMT3_IMM | ((val) & SDT_SIMM13_MASK)) - -#define SDT_SETHI(val, reg) \ - (SDT_OP_SETHI | (reg << SDT_FMT2_RD_SHIFT) | \ - ((val >> SDT_IMM22_SHIFT) & SDT_IMM22_MASK)) - -#define SDT_ENTRY_SIZE (11 * sizeof (uint32_t)) - -static void -sdt_initialize(sdt_probe_t *sdp, uint32_t **trampoline) -{ - uint32_t *instr = *trampoline; - - *instr++ = SDT_SAVE; - - if (sdp->sdp_id > (uint32_t)SDT_SIMM13_MAX) { - *instr++ = SDT_SETHI(sdp->sdp_id, SDT_REG_O0); - *instr++ = SDT_ORLO(SDT_REG_O0, sdp->sdp_id, SDT_REG_O0); - } else { - *instr++ = SDT_ORSIMM13(SDT_REG_G0, sdp->sdp_id, SDT_REG_O0); - } - - *instr++ = SDT_MOV(SDT_REG_I0, SDT_REG_O1); - *instr++ = SDT_MOV(SDT_REG_I1, SDT_REG_O2); - *instr++ = SDT_MOV(SDT_REG_I2, SDT_REG_O3); - *instr++ = SDT_MOV(SDT_REG_I3, SDT_REG_O4); - *instr = SDT_CALL(instr, dtrace_probe); - instr++; - *instr++ = SDT_MOV(SDT_REG_I4, SDT_REG_O5); - - *instr++ = SDT_RET; - *instr++ = SDT_RESTORE; - *trampoline = instr; -} - -/*ARGSUSED*/ -static void -sdt_provide_module(void *arg, struct modctl *ctl) -{ - struct module *mp = ctl->mod_mp; - char *modname = ctl->mod_modname; - int primary, nprobes = 0; - sdt_probedesc_t *sdpd; - sdt_probe_t *sdp, *old; - uint32_t *tab; - sdt_provider_t *prov; - int len; - - /* - * One for all, and all for one: if we haven't yet registered all of - * our providers, we'll refuse to provide anything. - */ - for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) { - if (prov->sdtp_id == DTRACE_PROVNONE) - return; - } - - if (mp->sdt_nprobes != 0 || (sdpd = mp->sdt_probes) == NULL) - return; - - kobj_textwin_alloc(mp); - - /* - * Hack to identify unix/genunix/krtld. - */ - primary = vmem_contains(heap_arena, (void *)ctl, - sizeof (struct modctl)) == 0; - - /* - * If there hasn't been an sdt table allocated, we'll do so now. - */ - if (mp->sdt_tab == NULL) { - for (; sdpd != NULL; sdpd = sdpd->sdpd_next) { - nprobes++; - } - - /* - * We could (should?) determine precisely the size of the - * table -- but a reasonable maximum will suffice. - */ - mp->sdt_size = nprobes * SDT_ENTRY_SIZE; - mp->sdt_tab = kobj_texthole_alloc(mp->text, mp->sdt_size); - - if (mp->sdt_tab == NULL) { - cmn_err(CE_WARN, "couldn't allocate SDT table " - "for module %s", modname); - return; - } - } - - tab = (uint32_t *)mp->sdt_tab; - - for (sdpd = mp->sdt_probes; sdpd != NULL; sdpd = sdpd->sdpd_next) { - char *name = sdpd->sdpd_name, *func, *nname; - int i, j; - sdt_provider_t *prov; - ulong_t offs; - dtrace_id_t id; - - for (prov = sdt_providers; prov->sdtp_prefix != NULL; prov++) { - char *prefix = prov->sdtp_prefix; - - if (strncmp(name, prefix, strlen(prefix)) == 0) { - name += strlen(prefix); - break; - } - } - - nname = kmem_alloc(len = strlen(name) + 1, KM_SLEEP); - - for (i = 0, j = 0; name[j] != '\0'; i++) { - if (name[j] == '_' && name[j + 1] == '_') { - nname[i] = '-'; - j += 2; - } else { - nname[i] = name[j++]; - } - } - - nname[i] = '\0'; - - sdp = kmem_zalloc(sizeof (sdt_probe_t), KM_SLEEP); - sdp->sdp_loadcnt = ctl->mod_loadcnt; - sdp->sdp_primary = primary; - sdp->sdp_ctl = ctl; - sdp->sdp_name = nname; - sdp->sdp_namelen = len; - sdp->sdp_provider = prov; - - func = kobj_searchsym(mp, sdpd->sdpd_offset + - (uintptr_t)mp->text, &offs); - - if (func == NULL) - func = "<unknown>"; - - /* - * We have our provider. Now create the probe. - */ - if ((id = dtrace_probe_lookup(prov->sdtp_id, modname, - func, nname)) != DTRACE_IDNONE) { - old = dtrace_probe_arg(prov->sdtp_id, id); - ASSERT(old != NULL); - - sdp->sdp_next = old->sdp_next; - sdp->sdp_id = id; - old->sdp_next = sdp; - } else { - sdp->sdp_id = dtrace_probe_create(prov->sdtp_id, - modname, func, nname, 1, sdp); - - mp->sdt_nprobes++; - } - - sdp->sdp_patchval = SDT_CALL((uintptr_t)mp->text + - sdpd->sdpd_offset, tab); - sdp->sdp_patchpoint = (uint32_t *)((uintptr_t)mp->textwin + - sdpd->sdpd_offset); - sdp->sdp_savedval = *sdp->sdp_patchpoint; - sdt_initialize(sdp, &tab); - } -} - -/*ARGSUSED*/ -static void -sdt_destroy(void *arg, dtrace_id_t id, void *parg) -{ - sdt_probe_t *sdp = parg, *old; - struct modctl *ctl = sdp->sdp_ctl; - - if (ctl != NULL && ctl->mod_loadcnt == sdp->sdp_loadcnt) { - if ((ctl->mod_loadcnt == sdp->sdp_loadcnt && - ctl->mod_loaded) || sdp->sdp_primary) { - ((struct module *)(ctl->mod_mp))->sdt_nprobes--; - } - } - - while (sdp != NULL) { - old = sdp; - kmem_free(sdp->sdp_name, sdp->sdp_namelen); - sdp = sdp->sdp_next; - kmem_free(old, sizeof (sdt_probe_t)); - } -} - -/*ARGSUSED*/ -static void -sdt_enable(void *arg, dtrace_id_t id, void *parg) -{ - sdt_probe_t *sdp = parg; - struct modctl *ctl = sdp->sdp_ctl; - - ctl->mod_nenabled++; - - /* - * If this module has disappeared since we discovered its probes, - * refuse to enable it. - */ - if (!sdp->sdp_primary && !ctl->mod_loaded) { - if (sdt_verbose) { - cmn_err(CE_NOTE, "sdt is failing for probe %s " - "(module %s unloaded)", - sdp->sdp_name, ctl->mod_modname); - } - goto err; - } - - /* - * Now check that our modctl has the expected load count. If it - * doesn't, this module must have been unloaded and reloaded -- and - * we're not going to touch it. - */ - if (ctl->mod_loadcnt != sdp->sdp_loadcnt) { - if (sdt_verbose) { - cmn_err(CE_NOTE, "sdt is failing for probe %s " - "(module %s reloaded)", - sdp->sdp_name, ctl->mod_modname); - } - goto err; - } - - while (sdp != NULL) { - *sdp->sdp_patchpoint = sdp->sdp_patchval; - sdp = sdp->sdp_next; - } - -err: - ; -} - -/*ARGSUSED*/ -static void -sdt_disable(void *arg, dtrace_id_t id, void *parg) -{ - sdt_probe_t *sdp = parg; - struct modctl *ctl = sdp->sdp_ctl; - - ASSERT(ctl->mod_nenabled > 0); - ctl->mod_nenabled--; - - if ((!sdp->sdp_primary && !ctl->mod_loaded) || - (ctl->mod_loadcnt != sdp->sdp_loadcnt)) - goto err; - - while (sdp != NULL) { - *sdp->sdp_patchpoint = sdp->sdp_savedval; - sdp = sdp->sdp_next; - } - -err: - ; -} +static int sdt_verbose = 0; +static sdt_probe_t **sdt_probetab; +static int sdt_probetab_size; +static int sdt_probetab_mask; static dtrace_pops_t sdt_pops = { NULL, @@ -353,88 +134,6 @@ sdt_destroy }; -static int -sdt_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) -{ - sdt_provider_t *prov; - - switch (cmd) { - case DDI_ATTACH: - break; - case DDI_RESUME: - return (DDI_SUCCESS); - default: - return (DDI_FAILURE); - } - - if (ddi_create_minor_node(devi, "sdt", S_IFCHR, 0, - DDI_PSEUDO, NULL) == DDI_FAILURE) { - ddi_remove_minor_node(devi, NULL); - return (DDI_FAILURE); - } - - ddi_report_dev(devi); - sdt_devi = devi; - - for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) { - if (dtrace_register(prov->sdtp_name, prov->sdtp_attr, - DTRACE_PRIV_KERNEL, 0, - &sdt_pops, prov, &prov->sdtp_id) != 0) { - cmn_err(CE_WARN, "failed to register sdt provider %s", - prov->sdtp_name); - } - } - - return (DDI_SUCCESS); -} - -static int -sdt_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) -{ - sdt_provider_t *prov; - - switch (cmd) { - case DDI_DETACH: - break; - case DDI_SUSPEND: - return (DDI_SUCCESS); - default: - return (DDI_FAILURE); - } - - for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) { - if (prov->sdtp_id != DTRACE_PROVNONE) { - if (dtrace_unregister(prov->sdtp_id) != 0) - return (DDI_FAILURE); - prov->sdtp_id = DTRACE_PROVNONE; - } - } - - ddi_remove_minor_node(devi, NULL); - return (DDI_SUCCESS); -} - -/*ARGSUSED*/ -static int -sdt_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) -{ - int error; - - switch (infocmd) { - case DDI_INFO_DEVT2DEVINFO: - *result = (void *)sdt_devi; - error = DDI_SUCCESS; - break; - case DDI_INFO_DEVT2INSTANCE: - *result = (void *)0; - error = DDI_SUCCESS; - break; - default: - error = DDI_FAILURE; - } - return (error); -} - /*ARGSUSED*/ static int sdt_open(dev_t *devp, int flag, int otyp, cred_t *cred_p) @@ -471,7 +170,8 @@ nodev, /* reset */ &sdt_cb_ops, /* driver operations */ NULL, /* bus operations */ - nodev /* dev power */ + nodev, /* dev power */ + ddi_quiesce_not_needed, /* quiesce */ }; /* @@ -489,20 +189,465 @@ NULL }; +/*====================== End of Global Variables ===================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - sdt_invop. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + +/*ARGSUSED*/ +static int +sdt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax) +{ + uintptr_t stack0, stack1, stack2, stack3, stack4; + int i = 0; + sdt_probe_t *sdt = sdt_probetab[SDT_ADDR2NDX(addr)]; + +#ifdef __amd64 + /* + * On amd64, stack[0] contains the dereferenced stack pointer, + * stack[1] contains savfp, stack[2] contains savpc. We want + * to step over these entries. + */ + i += 3; +#endif + + for (; sdt != NULL; sdt = sdt->sdp_hashnext) { + if ((uintptr_t)sdt->sdp_patchpoint == addr) { + /* + * When accessing the arguments on the stack, we must + * protect against accessing beyond the stack. We can + * safely set NOFAULT here -- we know that interrupts + * are already disabled. + */ + DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); + stack0 = stack[i++]; + stack1 = stack[i++]; + stack2 = stack[i++]; + stack3 = stack[i++]; + stack4 = stack[i++]; + DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | + CPU_DTRACE_BADADDR); + + dtrace_probe(sdt->sdp_id, stack0, stack1, + stack2, stack3, stack4); + + return (DTRACE_INVOP_NOP); + } + } + + return (0); +} + +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - sdt_provide_module. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + +/*ARGSUSED*/ +static void +sdt_provide_module(void *arg, struct modctl *ctl) +{ + struct module *mp = ctl->mod_mp; + char *modname = ctl->mod_modname; + sdt_probedesc_t *sdpd; + sdt_probe_t *sdp, *old; + sdt_provider_t *prov; + int len; + + /* + * One for all, and all for one: if we haven't yet registered all of + * our providers, we'll refuse to provide anything. + */ + for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) { + if (prov->sdtp_id == DTRACE_PROVNONE) + return; + } + + if (mp->sdt_nprobes != 0 || (sdpd = mp->sdt_probes) == NULL) + return; + + for (sdpd = mp->sdt_probes; sdpd != NULL; sdpd = sdpd->sdpd_next) { + char *name = sdpd->sdpd_name, *func, *nname; + int i, j; + sdt_provider_t *prov; + ulong_t offs; + dtrace_id_t id; + + for (prov = sdt_providers; prov->sdtp_prefix != NULL; prov++) { + char *prefix = prov->sdtp_prefix; + + if (strncmp(name, prefix, strlen(prefix)) == 0) { + name += strlen(prefix); + break; + } + } + + nname = kmem_alloc(len = strlen(name) + 1, KM_SLEEP); + + for (i = 0, j = 0; name[j] != '\0'; i++) { + if (name[j] == '_' && name[j + 1] == '_') { + nname[i] = '-'; + j += 2; + } else { + nname[i] = name[j++]; + } + } + + nname[i] = '\0'; + + sdp = kmem_zalloc(sizeof (sdt_probe_t), KM_SLEEP); + sdp->sdp_loadcnt = ctl->mod_loadcnt; + sdp->sdp_ctl = ctl; + sdp->sdp_name = nname; + sdp->sdp_namelen = len; + sdp->sdp_provider = prov; + + func = kobj_searchsym(mp, sdpd->sdpd_offset, &offs); + + if (func == NULL) + func = "<unknown>"; + + /* + * We have our provider. Now create the probe. + */ + if ((id = dtrace_probe_lookup(prov->sdtp_id, modname, + func, nname)) != DTRACE_IDNONE) { + old = dtrace_probe_arg(prov->sdtp_id, id); + ASSERT(old != NULL); + + sdp->sdp_next = old->sdp_next; + sdp->sdp_id = id; + old->sdp_next = sdp; + } else { + sdp->sdp_id = dtrace_probe_create(prov->sdtp_id, + modname, func, nname, 3, sdp); + + mp->sdt_nprobes++; + } + + sdp->sdp_hashnext = + sdt_probetab[SDT_ADDR2NDX(sdpd->sdpd_offset)]; + sdt_probetab[SDT_ADDR2NDX(sdpd->sdpd_offset)] = sdp; + + sdp->sdp_patchval = SDT_PATCHVAL; + sdp->sdp_patchpoint = (uint8_t *)sdpd->sdpd_offset; + sdp->sdp_savedval = *sdp->sdp_patchpoint; + } +} + +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - sdt_destroy. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + +/*ARGSUSED*/ +static void +sdt_destroy(void *arg, dtrace_id_t id, void *parg) +{ + sdt_probe_t *sdp = parg, *old, *last, *hash; + struct modctl *ctl = sdp->sdp_ctl; + int ndx; + + if (ctl != NULL && ctl->mod_loadcnt == sdp->sdp_loadcnt) { + if ((ctl->mod_loadcnt == sdp->sdp_loadcnt && + ctl->mod_loaded)) { + ((struct module *)(ctl->mod_mp))->sdt_nprobes--; + } + } + + while (sdp != NULL) { + old = sdp; + + /* + * Now we need to remove this probe from the sdt_probetab. + */ + ndx = SDT_ADDR2NDX(sdp->sdp_patchpoint); + last = NULL; + hash = sdt_probetab[ndx]; + + while (hash != sdp) { + ASSERT(hash != NULL); + last = hash; + hash = hash->sdp_hashnext; + } + + if (last != NULL) { + last->sdp_hashnext = sdp->sdp_hashnext; + } else { + sdt_probetab[ndx] = sdp->sdp_hashnext; + } + + kmem_free(sdp->sdp_name, sdp->sdp_namelen); + sdp = sdp->sdp_next; + kmem_free(old, sizeof (sdt_probe_t)); + } +} + +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - sdt_enable. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + +/*ARGSUSED*/ +static int +sdt_enable(void *arg, dtrace_id_t id, void *parg) +{ + sdt_probe_t *sdp = parg; + struct modctl *ctl = sdp->sdp_ctl; + + ctl->mod_nenabled++; + + /* + * If this module has disappeared since we discovered its probes, + * refuse to enable it. + */ + if (!ctl->mod_loaded) { + if (sdt_verbose) { + cmn_err(CE_NOTE, "sdt is failing for probe %s " + "(module %s unloaded)", + sdp->sdp_name, ctl->mod_modname); + } + goto err; + } + + /* + * Now check that our modctl has the expected load count. If it + * doesn't, this module must have been unloaded and reloaded -- and + * we're not going to touch it. + */ + if (ctl->mod_loadcnt != sdp->sdp_loadcnt) { + if (sdt_verbose) { + cmn_err(CE_NOTE, "sdt is failing for probe %s " + "(module %s reloaded)", + sdp->sdp_name, ctl->mod_modname); + } + goto err; + } + + while (sdp != NULL) { + *sdp->sdp_patchpoint = sdp->sdp_patchval; + sdp = sdp->sdp_next; + } +err: + return (0); +} + +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - sdt_disable. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + +/*ARGSUSED*/ +static void +sdt_disable(void *arg, dtrace_id_t id, void *parg) +{ + sdt_probe_t *sdp = parg; + struct modctl *ctl = sdp->sdp_ctl; + + ctl->mod_nenabled--; + + if (!ctl->mod_loaded || ctl->mod_loadcnt != sdp->sdp_loadcnt) + goto err; + + while (sdp != NULL) { + *sdp->sdp_patchpoint = sdp->sdp_savedval; + sdp = sdp->sdp_next; + } + +err: + ; +} + +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - sdt_attach. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + +/*ARGSUSED*/ +static int +sdt_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) +{ + sdt_provider_t *prov; + + if (ddi_create_minor_node(devi, "sdt", S_IFCHR, + 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { + cmn_err(CE_NOTE, "/dev/sdt couldn't create minor node"); + ddi_remove_minor_node(devi, NULL); + return (DDI_FAILURE); + } + + ddi_report_dev(devi); + sdt_devi = devi; + + if (sdt_probetab_size == 0) + sdt_probetab_size = SDT_PROBETAB_SIZE; + + sdt_probetab_mask = sdt_probetab_size - 1; + sdt_probetab = + kmem_zalloc(sdt_probetab_size * sizeof (sdt_probe_t *), KM_SLEEP); + dtrace_invop_add(sdt_invop); + + for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) { + if (dtrace_register(prov->sdtp_name, prov->sdtp_attr, + DTRACE_PRIV_KERNEL, NULL, + &sdt_pops, prov, &prov->sdtp_id) != 0) { + cmn_err(CE_WARN, "failed to register sdt provider %s", + prov->sdtp_name); + } + } + + return (DDI_SUCCESS); +} + +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - sdt_detach. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + +/*ARGSUSED*/ +static int +sdt_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ + sdt_provider_t *prov; + + switch (cmd) { + case DDI_DETACH: + break; + + case DDI_SUSPEND: + return (DDI_SUCCESS); + + default: + return (DDI_FAILURE); + } + + for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) { + if (prov->sdtp_id != DTRACE_PROVNONE) { + if (dtrace_unregister(prov->sdtp_id) != 0) + return (DDI_FAILURE); + + prov->sdtp_id = DTRACE_PROVNONE; + } + } + + dtrace_invop_remove(sdt_invop); + kmem_free(sdt_probetab, sdt_probetab_size * sizeof (sdt_probe_t *)); + + return (DDI_SUCCESS); +} + +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - sdt_info. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + +/*ARGSUSED*/ +static int +sdt_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) +{ + int error; + + switch (infocmd) { + case DDI_INFO_DEVT2DEVINFO: + *result = (void *)sdt_devi; + error = DDI_SUCCESS; + break; + case DDI_INFO_DEVT2INSTANCE: + *result = (void *)0; + error = DDI_SUCCESS; + break; + default: + error = DDI_FAILURE; + } + return (error); +} + +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - _init. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + int _init(void) { return (mod_install(&modlinkage)); } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - _info. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + int _info(struct modinfo *modinfop) { return (mod_info(&modlinkage, modinfop)); } +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - _fini. */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + int _fini(void) { return (mod_remove(&modlinkage)); } + +/*========================= End of Function ========================*/
--- a/usr/src/uts/zSeries/dtrace/sdt.conf Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/uts/zSeries/dtrace/sdt.conf Thu Oct 08 12:44:34 2009 -0400 @@ -23,6 +23,5 @@ # Copyright 2003 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#ident "@(#)sdt.conf 1.2 05/06/08 SMI" name="sdt" parent="pseudo" instance=0;
--- a/usr/src/uts/zSeries/fasttrap/Makefile Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/uts/zSeries/fasttrap/Makefile Thu Oct 08 12:44:34 2009 -0400 @@ -33,7 +33,7 @@ LINTS = $(FASTTRAP_OBJS:%.o=$(LINTS_DIR)/%.ln) ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE) ROOTLINK = $(ROOT_DTRACE_DIR)/$(MODULE) -CONF_SRCDIR = $(UTSBASE)/s390x/dtrace +CONF_SRCDIR = $(UTSBASE)/zSeries/dtrace include $(UTSBASE)/zSeries/Makefile.zSeries @@ -41,7 +41,7 @@ LINT_TARGET = $(MODULE).lint INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOTLINK) $(ROOT_CONFFILE) -CFLAGS += $(CCVERBOSE) +CFLAGS += $(CCVERBOSE) -I$(SRC)/common/dis/s390 -I$(SRC)/common LDFLAGS += -Ndrv/dtrace LDFLAGS += -dy
--- a/usr/src/uts/zSeries/fbt/Makefile Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/uts/zSeries/fbt/Makefile Thu Oct 08 12:44:34 2009 -0400 @@ -33,7 +33,7 @@ LINTS = $(FBT_OBJS:%.o=$(LINTS_DIR)/%.ln) ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE) ROOTLINK = $(ROOT_DTRACE_DIR)/$(MODULE) -CONF_SRCDIR = $(UTSBASE)/s390x/dtrace +CONF_SRCDIR = $(UTSBASE)/zSeries/dtrace include $(UTSBASE)/zSeries/Makefile.zSeries @@ -41,7 +41,7 @@ LINT_TARGET = $(MODULE).lint INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOTLINK) $(ROOT_CONFFILE) -CFLAGS += $(CCVERBOSE) +CFLAGS += $(CCVERBOSE) -I$(SRC)/common/dis/s390 LDFLAGS += -Ndrv/dtrace -Nmisc/ctf LDFLAGS += -dy
--- a/usr/src/uts/zSeries/sdt/Makefile Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/uts/zSeries/sdt/Makefile Thu Oct 08 12:44:34 2009 -0400 @@ -33,7 +33,7 @@ LINTS = $(SDT_OBJS:%.o=$(LINTS_DIR)/%.ln) ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE) ROOTLINK = $(ROOT_DTRACE_DIR)/$(MODULE) -CONF_SRCDIR = $(UTSBASE)/s390x/dtrace +CONF_SRCDIR = $(UTSBASE)/zSeries/dtrace include $(UTSBASE)/zSeries/Makefile.zSeries
--- a/usr/src/uts/zSeries/sys/fasttrap_isa.h Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/uts/zSeries/sys/fasttrap_isa.h Thu Oct 08 12:44:34 2009 -0400 @@ -37,58 +37,32 @@ extern "C" { #endif +#define FASTTRAP_MAX_INSTR_SIZE 256 + /* - * This is our reserved trap instruction: ta 0x38 + * This is our reserved trap instruction: svc 01 */ -#define FASTTRAP_INSTR 0x91d02038 +#define FASTTRAP_INSTR 0x0a01 #define FASTTRAP_SUNWDTRACE_SIZE 64 -typedef uint32_t fasttrap_instr_t; +typedef uint16_t fasttrap_instr_t; typedef struct fasttrap_machtp { - fasttrap_instr_t ftmt_instr; /* original instruction */ - uintptr_t ftmt_dest; /* destination of DCTI */ - uint8_t ftmt_type; /* emulation type */ - uint8_t ftmt_flags; /* emulation flags */ - uint8_t ftmt_cc; /* which cc to look at */ - uint8_t ftmt_code; /* branch condition */ + uint8_t ftmt_instr[FASTTRAP_MAX_INSTR_SIZE]; /* orig. instr. */ + uint8_t ftmt_isize; /* instruction size */ + uint8_t ftmt_size; /* dtrace instruction sequence size */ } fasttrap_machtp_t; -#define ftt_instr ftt_mtp.ftmt_instr -#define ftt_dest ftt_mtp.ftmt_dest -#define ftt_type ftt_mtp.ftmt_type -#define ftt_flags ftt_mtp.ftmt_flags -#define ftt_cc ftt_mtp.ftmt_cc -#define ftt_code ftt_mtp.ftmt_code - -#define FASTTRAP_T_COMMON 0x00 /* common case -- no emulation */ -#define FASTTRAP_T_CCR 0x01 /* integer condition code branch */ -#define FASTTRAP_T_FCC 0x02 /* floating-point branch */ -#define FASTTRAP_T_REG 0x03 /* register predicated branch */ -#define FASTTRAP_T_ALWAYS 0x04 /* branch always */ -#define FASTTRAP_T_CALL 0x05 /* call instruction */ -#define FASTTRAP_T_JMPL 0x06 /* jmpl instruction */ -#define FASTTRAP_T_RDPC 0x07 /* rdpc instruction */ -#define FASTTRAP_T_RETURN 0x08 /* return instruction */ - -/* - * For performance rather than correctness. - */ -#define FASTTRAP_T_SAVE 0x10 /* save instruction (func entry only) */ -#define FASTTRAP_T_RESTORE 0x11 /* restore instruction */ -#define FASTTRAP_T_OR 0x12 /* mov instruction */ -#define FASTTRAP_T_SETHI 0x13 /* sethi instruction (includes nop) */ - -#define FASTTRAP_F_ANNUL 0x01 /* branch is annulled */ -#define FASTTRAP_F_RETMAYBE 0x02 /* not definitely a return site */ +#define ftt_instr ftt_mtp.ftmt_instr +#define ftt_size ftt_mtp.ftmt_size +#define ftt_isize ftt_mtp.ftmt_isize #define FASTTRAP_AFRAMES 3 #define FASTTRAP_RETURN_AFRAMES 4 #define FASTTRAP_ENTRY_AFRAMES 3 #define FASTTRAP_OFFSET_AFRAMES 3 - #ifdef __cplusplus } #endif
--- a/usr/src/uts/zSeries/sys/procfs_isa.h Mon Oct 05 12:49:41 2009 -0400 +++ b/usr/src/uts/zSeries/sys/procfs_isa.h Thu Oct 08 12:44:34 2009 -0400 @@ -60,7 +60,7 @@ typedef uint32_t instr_t; /* - * General register access (sparc). + * General register access (s390x). * Don't confuse definitions here with definitions in <sys/regset.h>. * Registers are 32 bits for ILP32, 64 bits for LP64. * The floating point registers follow the access registers. For convenience @@ -84,40 +84,41 @@ #define R_G13 (15) #define R_G14 (16) #define R_G15 (17) -#define R_A0 (18) -#define R_A1 (19) -#define R_A2 (20) -#define R_A3 (21) -#define R_A4 (22) -#define R_A5 (23) -#define R_A6 (24) -#define R_A7 (25) -#define R_A8 (26) -#define R_A9 (27) -#define R_A10 (28) -#define R_A11 (29) -#define R_A12 (30) -#define R_A13 (31) -#define R_A14 (32) -#define R_A15 (33) -#define R_FPC (34) -#define R_F0 (35) -#define R_F1 (36) -#define R_F2 (37) -#define R_F3 (38) -#define R_F4 (39) -#define R_F5 (40) -#define R_F6 (41) -#define R_F7 (42) -#define R_F8 (43) -#define R_F9 (44) -#define R_F10 (45) -#define R_F11 (46) -#define R_F12 (47) -#define R_F13 (48) -#define R_F14 (49) -#define R_F15 (50) -#define NPRGREG 51 +#define R_ILC (18) +#define R_A0 (19) +#define R_A1 (20) +#define R_A2 (21) +#define R_A3 (22) +#define R_A4 (23) +#define R_A5 (24) +#define R_A6 (25) +#define R_A7 (26) +#define R_A8 (27) +#define R_A9 (28) +#define R_A10 (29) +#define R_A11 (30) +#define R_A12 (31) +#define R_A13 (32) +#define R_A14 (33) +#define R_A15 (34) +#define R_FPC (35) +#define R_F0 (36) +#define R_F1 (37) +#define R_F2 (38) +#define R_F3 (39) +#define R_F4 (40) +#define R_F5 (41) +#define R_F6 (42) +#define R_F7 (43) +#define R_F8 (44) +#define R_F9 (45) +#define R_F10 (46) +#define R_F11 (47) +#define R_F12 (48) +#define R_F13 (49) +#define R_F14 (50) +#define R_F15 (51) +#define NPRGREG 52 /* * The following defines are for portability (see <sys/regset.h>).