10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Copyright 2009 Jason King. All rights reserved.
29 * Use is subject to license terms.
30 */
31
32
33 #include <sys/byteorder.h>
34 #include <stdarg.h>
35
36 #if !defined(DIS_STANDALONE)
37 #include <stdio.h>
38 #endif /* DIS_STANDALONE */
39
40 #include "libdisasm.h"
41 #include "libdisasm_impl.h"
42 #include "dis_sparc.h"
43 #include "dis_sparc_fmt.h"
44
45 extern char *strncpy(char *, const char *, size_t);
46 extern size_t strlen(const char *);
47 extern int strcmp(const char *, const char *);
48 extern int strncmp(const char *, const char *, size_t);
49 extern size_t strlcat(char *, const char *, size_t);
50 extern size_t strlcpy(char *, const char *, size_t);
51 extern int snprintf(char *, size_t, const char *, ...);
52 extern int vsnprintf(char *, size_t, const char *, va_list);
53
54 /*
55 * This file has the functions that do all the dirty work of outputting the
56 * disassembled instruction
57 *
58 * All the non-static functions follow the format_fcn (in dis_sparc.h):
59 * Input:
60 * disassembler handle/context
61 * instruction to disassemble
62 * instruction definition pointer (inst_t *)
63 * index in the table of the instruction
64 * Return:
65 * 0 Success
66 * !0 Invalid instruction
67 *
68 * Generally, instructions found in the same table use the same output format
69 * or have a few minor differences (which are described in the 'flags' field
70 * of the instruction definition. In some cases, certain instructions differ
71 * radically enough from those in the same table, that their own format
72 * function is used.
681 int i;
682
683 for (i = bitlen - 1; i >= 0; --i) {
684 (void) fprintf(stderr, ((val & (1L << i)) != 0) ? "1" : "0");
685
686 if (i % 4 == 0 && i != 0)
687 (void) fprintf(stderr, " ");
688 }
689 }
690 #endif /* DIS_STANDALONE */
691
692
693 /*
694 * print out a call instruction
695 * format: call address <name>
696 */
697 /* ARGSUSED1 */
698 int
699 fmt_call(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
700 {
701 ifmt_t *f = (ifmt_t *)&instr;
702
703 int32_t disp;
704 size_t curlen;
705
706 int octal = ((dhp->dh_flags & DIS_OCTAL) != 0);
707
708 if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
709 prt_field("op", f->f1.op, 2);
710 prt_field("disp30", f->f1.disp30, 30);
711 }
712
713 disp = sign_extend(f->f1.disp30, 30) * 4;
714
715 prt_name(dhp, inp->in_data.in_def.in_name, 1);
716
717 bprintf(dhp, (octal != 0) ? "%s0%-11lo" : "%s0x%-10lx",
718 (disp < 0) ? "-" : "+",
719 (disp < 0) ? (-disp) : disp);
720
721 (void) strlcat(dhp->dh_buf, " <", dhp->dh_buflen);
722
723 curlen = strlen(dhp->dh_buf);
724 dhp->dh_lookup(dhp->dh_data, dhp->dh_addr + (int64_t)disp,
725 dhp->dh_buf + curlen, dhp->dh_buflen - curlen - 1, NULL,
726 NULL);
727 (void) strlcat(dhp->dh_buf, ">", dhp->dh_buflen);
728
729
730 return (0);
731 }
732
733 int
734 fmt_sethi(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
735 {
736 ifmt_t *f = (ifmt_t *)&instr;
737
738 if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
739 prt_field("op", f->f2.op, 2);
740 prt_field("op2", f->f2.op2, 3);
741 prt_field("rd", f->f2.rd, 5);
742 prt_field("imm22", f->f2.imm22, 22);
743 }
744
745 if (idx == 0) {
746 /* unimp / illtrap */
747 prt_name(dhp, inp->in_data.in_def.in_name, 1);
748 prt_imm(dhp, f->f2.imm22, 0);
749 return (0);
750 }
751
752 if (f->f2.imm22 == 0 && f->f2.rd == 0) {
753 prt_name(dhp, "nop", 0);
754 return (0);
755 }
756
757 /* ?? Should we return -1 if rd == 0 && disp != 0 */
758
759 prt_name(dhp, inp->in_data.in_def.in_name, 1);
760
761 bprintf(dhp,
762 ((dhp->dh_flags & DIS_OCTAL) != 0) ?
763 "%%hi(0%lo), %s" : "%%hi(0x%lx), %s",
764 f->f2.imm22 << 10,
765 reg_names[f->f2.rd]);
766
767 return (0);
768 }
769
770 /* ARGSUSED3 */
771 int
772 fmt_branch(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
773 {
774 const char *name = inp->in_data.in_def.in_name;
775 const char *r = NULL;
776 const char *annul = "";
777 const char *pred = "";
778
779 char buf[15];
780
781 ifmt_t *f = (ifmt_t *)&instr;
782
783 size_t curlen;
784 int32_t disp;
785 uint32_t flags = inp->in_data.in_def.in_flags;
786 int octal = ((dhp->dh_flags & DIS_OCTAL) != 0);
787
788 if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
789 prt_field("op", f->f2.op, 2);
790 prt_field("op2", f->f2.op2, 3);
791
792 switch (FLG_DISP_VAL(flags)) {
793 case DISP22:
794 prt_field("cond", f->f2a.cond, 4);
795 prt_field("a", f->f2a.a, 1);
796 prt_field("disp22", f->f2a.disp22, 22);
797 break;
798
799 case DISP19:
800 prt_field("cond", f->f2a.cond, 4);
801 prt_field("a", f->f2a.a, 1);
802 prt_field("p", f->f2b.p, 1);
803 prt_field("cc", f->f2b.cc, 2);
804 prt_field("disp19", f->f2b.disp19, 19);
805 break;
806
807 case DISP16:
808 prt_field("bit 28", ((instr & (1L << 28)) >> 28), 1);
809 prt_field("rcond", f->f2c.cond, 3);
810 prt_field("p", f->f2c.p, 1);
811 prt_field("rs1", f->f2c.rs1, 5);
812 prt_field("d16hi", f->f2c.d16hi, 2);
813 prt_field("d16lo", f->f2c.d16lo, 14);
814 break;
815 }
816 }
817
818 if (f->f2b.op2 == 0x01 && idx == 0x00 && f->f2b.p == 1 &&
819 f->f2b.cc == 0x02 && ((dhp->dh_debug & DIS_DEBUG_SYN_ALL) != 0)) {
820 name = "iprefetch";
821 flags = FLG_RS1(REG_NONE)|FLG_DISP(DISP19);
822 }
823
824
825 switch (FLG_DISP_VAL(flags)) {
826 case DISP22:
827 disp = sign_extend(f->f2a.disp22, 22);
828 break;
829
830 case DISP19:
831 disp = sign_extend(f->f2b.disp19, 19);
832 break;
833
834 case DISP16:
835 disp = sign_extend((f->f2c.d16hi << 14)|f->f2c.d16lo, 16);
836 break;
837
838 }
839
840 disp *= 4;
841
842 if ((FLG_RS1_VAL(flags) == REG_ICC) || (FLG_RS1_VAL(flags) == REG_FCC))
843 r = get_regname(dhp, FLG_RS1_VAL(flags), f->f2b.cc);
844 else
845 r = get_regname(dhp, FLG_RS1_VAL(flags), f->f2c.rs1);
846
847 if (r == NULL)
848 return (-1);
849
850 if (f->f2a.a == 1)
851 annul = ",a";
852
853 if ((flags & FLG_PRED) != 0) {
854 if (f->f2b.p == 0) {
855 pred = ",pn";
856 } else {
857 if ((dhp->dh_debug & DIS_DEBUG_COMPAT) != 0)
858 pred = ",pt";
859 }
860 }
861
862 (void) snprintf(buf, sizeof (buf), "%s%s%s", name, annul, pred);
863 prt_name(dhp, buf, 1);
864
865
866 switch (FLG_DISP_VAL(flags)) {
867 case DISP22:
868 bprintf(dhp,
869 (octal != 0) ? "%s0%-11lo <" : "%s0x%-10lx <",
870 (disp < 0) ? "-" : "+",
871 (disp < 0) ? (-disp) : disp);
872 break;
873
874 case DISP19:
875 bprintf(dhp,
876 (octal != 0) ? "%s, %s0%-5lo <" :
877 "%s, %s0x%-04lx <", r,
878 (disp < 0) ? "-" : "+",
879 (disp < 0) ? (-disp) : disp);
880 break;
881
882 case DISP16:
883 bprintf(dhp,
884 (octal != 0) ? "%s, %s0%-6lo <" : "%s, %s0x%-5lx <",
885 r,
886 (disp < 0) ? "-" : "+",
887 (disp < 0) ? (-disp) : disp);
888 break;
889 }
890
891 curlen = strlen(dhp->dh_buf);
892 dhp->dh_lookup(dhp->dh_data, dhp->dh_addr + (int64_t)disp,
893 dhp->dh_buf + curlen, dhp->dh_buflen - curlen - 1, NULL, NULL);
894
895 (void) strlcat(dhp->dh_buf, ">", dhp->dh_buflen);
896
897 return (0);
898 }
899
900
901
902 /*
903 * print out the compare and swap instructions (casa/casxa)
904 * format: casa/casxa [%rs1] imm_asi, %rs2, %rd
905 * casa/casxa [%rs1] %asi, %rs2, %rd
906 *
907 * If DIS_DEBUG_SYN_ALL is set, synthetic instructions are emitted
908 * when an immediate ASI value is given as follows:
909 *
910 * casa [%rs1]#ASI_P, %rs2, %rd -> cas [%rs1], %rs2, %rd
911 * casa [%rs1]#ASI_P_L, %rs2, %rd -> casl [%rs1], %rs2, %rd
912 * casxa [%rs1]#ASI_P, %rs2, %rd -> casx [%rs1], %rs2, %rd
913 * casxa [%rs1]#ASI_P_L, %rs2, %rd -> casxl [%rs1], %rs2, %rd
914 */
915 static int
916 fmt_cas(dis_handle_t *dhp, uint32_t instr, const char *name)
917 {
918 ifmt_t *f = (ifmt_t *)&instr;
919 const char *asistr = NULL;
920 int noasi = 0;
921
922 asistr = get_asi_name(f->f3.asi);
923
924 if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT)) != 0) {
925 if (f->f3.op3 == 0x3c && f->f3.i == 0) {
926 if (f->f3.asi == 0x80) {
927 noasi = 1;
928 name = "cas";
929 }
930
931 if (f->f3.asi == 0x88) {
932 noasi = 1;
933 name = "casl";
934 }
935 }
936
937 if (f->f3.op3 == 0x3e && f->f3.i == 0) {
938 if (f->f3.asi == 0x80) {
939 noasi = 1;
940 name = "casx";
941 }
942
943 if (f->f3.asi == 0x88) {
944 noasi = 1;
945 name = "casxl";
946 }
947 }
948 }
949
950 prt_name(dhp, name, 1);
951
952 bprintf(dhp, "[%s]", reg_names[f->f3.rs1]);
953
954 if (noasi == 0) {
955 (void) strlcat(dhp->dh_buf, " ", dhp->dh_buflen);
956 prt_asi(dhp, instr);
957 }
958
959 bprintf(dhp, ", %s, %s", reg_names[f->f3.rs2], reg_names[f->f3.rd]);
960
961 if (noasi == 0 && asistr != NULL)
962 bprintf(dhp, "\t<%s>", asistr);
963
964 return (0);
965 }
966
967 /*
968 * format a load/store instruction
969 * format: ldXX [%rs1 + %rs2], %rd load, i==0
970 * ldXX [%rs1 +/- nn], %rd load, i==1
971 * ldXX [%rs1 + %rs2] #XX, %rd load w/ imm_asi, i==0
972 * ldXX [%rs1 +/- nn] %asi, %rd load from asi[%asi], i==1
973 *
974 * stXX %rd, [%rs1 + %rs2] store, i==0
975 * stXX %rd, [%rs1 +/- nn] store, i==1
982 * If DIS_DEBUG_SYNTH_ALL or DIS_DEBUG_COMPAT are set,
983 * When %rs1, %rs2 or nn are 0, they are not printed, i.e.
984 * [ %rs1 + 0x0 ], %rd -> [%rs1], %rd for example
985 *
986 * The following synthetic instructions are also implemented:
987 *
988 * stb %g0, [addr] -> clrb [addr] DIS_DEBUG_SYNTH_ALL
989 * sth %g0, [addr] -> crlh [addr] DIS_DEBUG_SYNTH_ALL
990 * stw %g0, [addr] -> clr [addr] DIS_DEBUG_SYNTH_ALL|DIS_DEBUG_COMPAT
991 * stx %g0, [addr] -> clrx [addr] DIS_DEBUG_SYNTH_ALL
992 *
993 * If DIS_DEBUG_COMPAT is set, the following substitutions also take place
994 * lduw -> ld
995 * ldtw -> ld
996 * stuw -> st
997 * sttw -> st
998 */
999 int
1000 fmt_ls(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
1001 {
1002 ifmt_t *f = (ifmt_t *)&instr;
1003 const char *regstr = NULL;
1004 const char *asistr = NULL;
1005
1006 const char *iname = inp->in_data.in_def.in_name;
1007 uint32_t flags = inp->in_data.in_def.in_flags;
1008
1009 if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
1010 prt_field("op", f->f3.op, 2);
1011 prt_field("op3", f->f3.op3, 6);
1012 prt_field("rs1", f->f3.rs1, 5);
1013 prt_field("i", f->f3.i, 1);
1014 if (f->f3.i != 0) {
1015 prt_field("simm13", f->f3a.simm13, 13);
1016 } else {
1017 if ((flags & FLG_ASI) != 0)
1018 prt_field("imm_asi", f->f3.asi, 8);
1019 prt_field("rs2", f->f3.rs2, 5);
1020 }
1021 prt_field("rd", f->f3.rd, 5);
1022 }
1023
1024 if (idx == 0x2d || idx == 0x3d) {
1025 /* prefetch / prefetcha */
1026
1027 prt_name(dhp, iname, 1);
1028
1029 prt_address(dhp, instr, 0);
1030
1031 if (idx == 0x3d) {
1032 (void) strlcat(dhp->dh_buf, " ", dhp->dh_buflen);
1033 prt_asi(dhp, instr);
1034 }
1035
1036 (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen);
1037
1038 /* fcn field is the same as rd */
1039 if (prefetch_str[f->f3.rd] != NULL)
1040 (void) strlcat(dhp->dh_buf, prefetch_str[f->f3.rd],
1041 dhp->dh_buflen);
1042 else
1043 prt_imm(dhp, f->f3.rd, 0);
1044
1045 if (idx == 0x3d && f->f3.i == 0) {
1046 asistr = get_asi_name(f->f3.asi);
1047 if (asistr != NULL)
1048 bprintf(dhp, "\t<%s>", asistr);
1049 }
1050
1051 return (0);
1052 }
1053
1054 /* casa / casxa */
1055 if (idx == 0x3c || idx == 0x3e)
1056 return (fmt_cas(dhp, instr, iname));
1057
1058 /* synthetic instructions & special cases */
1059 switch (idx) {
1060 case 0x00:
1061 /* ld */
1062 if ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0)
1063 iname = "lduw";
1064 break;
1065
1066 case 0x03:
1067 if ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0)
1068 iname = "ldtw";
1069 break;
1070
1071 case 0x04:
1072 /* stw */
1073 if ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0)
1074 iname = "stuw";
1075
1076 if ((dhp->dh_flags & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL))
1077 == 0)
1078 break;
1079
1080 if (f->f3.rd == 0) {
1081 iname = "clr";
1082 flags = FLG_RD(REG_NONE);
1083 }
1084 break;
1085
1086 case 0x05:
1087 /* stb */
1088 if ((dhp->dh_flags & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL))
1089 == 0)
1090 break;
1091
1092 if (f->f3.rd == 0) {
1093 iname = "clrb";
1094 flags = FLG_RD(REG_NONE);
1095 }
1096 break;
1097
1098 case 0x06:
1099 /* sth */
1100 if ((dhp->dh_flags & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL))
1101 == 0)
1102 break;
1103
1104 if (f->f3.rd == 0) {
1105 iname = "clrh";
1106 flags = FLG_RD(REG_NONE);
1107 }
1108 break;
1109
1110 case 0x07:
1111 if ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0)
1112 iname = "sttw";
1113 break;
1114
1115 case 0x0e:
1116 /* stx */
1117
1118 if ((dhp->dh_flags & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL))
1119 == 0)
1120 break;
1121
1122 if (f->f3.rd == 0) {
1123 iname = "clrx";
1124 flags = FLG_RD(REG_NONE);
1125 }
1126 break;
1127
1128 case 0x13:
1129 /* ldtwa */
1130 if (((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0) &&
1131 ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) != 0))
1132 iname = "ldtwa";
1133 break;
1134
1135 case 0x17:
1136 /* sttwa */
1137 if (((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0) &&
1138 ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) != 0))
1139 iname = "sttwa";
1140 break;
1141
1142 case 0x21:
1143 case 0x25:
1144 /*
1145 * on sparcv8 it merely says that rd != 1 should generate an
1146 * exception, on v9, it is illegal
1147 */
1148 if ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) == 0)
1149 break;
1150
1151 iname = (idx == 0x21) ? "ldx" : "stx";
1152
1153 if (f->f3.rd > 1)
1154 return (-1);
1155
1156 break;
1157
1195 if (asistr != NULL)
1196 bprintf(dhp, "\t<%s>", asistr);
1197
1198 return (0);
1199
1200 default:
1201 break;
1202 }
1203
1204 }
1205
1206 regstr = get_regname(dhp, FLG_RD_VAL(flags), f->f3.rd);
1207
1208 if (f->f3.i == 0)
1209 asistr = get_asi_name(f->f3.asi);
1210
1211 prt_name(dhp, iname, 1);
1212
1213 if ((flags & FLG_STORE) != 0) {
1214 if (regstr[0] != '\0') {
1215 (void) strlcat(dhp->dh_buf, regstr, dhp->dh_buflen);
1216 (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen);
1217 }
1218
1219 prt_address(dhp, instr, 0);
1220 if ((flags & FLG_ASI) != 0) {
1221 (void) strlcat(dhp->dh_buf, " ", dhp->dh_buflen);
1222 prt_asi(dhp, instr);
1223 }
1224 } else {
1225 prt_address(dhp, instr, 0);
1226 if ((flags & FLG_ASI) != 0) {
1227 (void) strlcat(dhp->dh_buf, " ", dhp->dh_buflen);
1228 prt_asi(dhp, instr);
1229 }
1230
1231 if (regstr[0] != '\0') {
1232 (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen);
1233 (void) strlcat(dhp->dh_buf, regstr, dhp->dh_buflen);
1234 }
1235 }
1236
1237 if ((flags & FLG_ASI) != 0 && asistr != NULL)
1238 bprintf(dhp, "\t<%s>", asistr);
1239
1240 return (0);
1241 }
1242
1243 static int
1244 fmt_cpop(dis_handle_t *dhp, uint32_t instr, const inst_t *inp)
1245 {
1246 ifmt_t *f = (ifmt_t *)&instr;
1247 int flags = FLG_P1(REG_CP)|FLG_P2(REG_CP)|FLG_NOIMM|FLG_P3(REG_CP);
1248
1249 if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
1250 prt_field("op", f->fcp.op, 2);
1251 prt_field("op3", f->fcp.op3, 6);
1252 prt_field("opc", f->fcp.opc, 9);
1253 prt_field("rs1", f->fcp.rs1, 5);
1254 prt_field("rs2", f->fcp.rs2, 5);
1255 prt_field("rd", f->fcp.rd, 5);
1256 }
1257
1258 prt_name(dhp, inp->in_data.in_def.in_name, 1);
1259 prt_imm(dhp, f->fcp.opc, 0);
1260
1261 (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen);
1262 (void) prt_aluargs(dhp, instr, flags);
1263
1264 return (0);
1265 }
1266
1267 static int
1268 dis_fmt_rdwr(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
1269 {
1270 const char *psr_str = "%psr";
1271 const char *wim_str = "%wim";
1272 const char *tbr_str = "%tbr";
1273
1274 const char *name = inp->in_data.in_def.in_name;
1275 const char *regstr = NULL;
1276
1277 ifmt_t *f = (ifmt_t *)&instr;
1278
1279 int rd = (idx < 0x30);
1280 int v9 = (dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI));
1281 int ridx = f->f3.rs1;
1282 int i, first;
1283 int pr_rs1 = 1;
1284 int pr_rs2 = 1;
1285
1286 int use_mask = 1;
1287 uint32_t mask;
1288
1289 if (rd == 0)
1375 mask = v9_asr_wrmask;
1376 } else {
1377 regstr = asr_names[ridx];
1378 mask = asr_wrmask;
1379 }
1380
1381 /*
1382 * sir is shoehorned in here, per Ultrasparc 2007
1383 * hyperprivileged edition, section 7.88, all of
1384 * these must be true to distinguish from WRasr
1385 */
1386 if (v9 != 0 && f->f3.rd == 15 && f->f3.rs1 == 0 &&
1387 f->f3.i == 1) {
1388 prt_name(dhp, "sir", 1);
1389 prt_imm(dhp, sign_extend(f->f3a.simm13, 13),
1390 IMM_SIGNED);
1391 return (0);
1392 }
1393
1394 /* synth: mov */
1395 if ((dhp->dh_debug & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL))
1396 == 0)
1397 break;
1398
1399 if (v9 == 0) {
1400 if (f->f3.rs1 == 0) {
1401 name = "mov";
1402 pr_rs1 = 0;
1403 }
1404
1405 if ((f->f3.i == 0 && f->f3.rs2 == 0) ||
1406 (f->f3.i == 1 && f->f3a.simm13 == 0)) {
1407 name = "mov";
1408 pr_rs2 = 0;
1409 }
1410 }
1411
1412 if (pr_rs1 == 0)
1413 pr_rs2 = 1;
1414
1415 break;
1447
1448 if (regstr == NULL)
1449 return (-1);
1450
1451 if (use_mask != 0 && ((1L << ridx) & mask) == 0)
1452 return (-1);
1453
1454 prt_name(dhp, name, 1);
1455
1456 if (rd != 0) {
1457 bprintf(dhp, "%s, %s", regstr, reg_names[f->f3.rd]);
1458 } else {
1459 if (pr_rs1 == 1)
1460 bprintf(dhp, "%s, ", reg_names[f->f3.rs1]);
1461
1462 if (pr_rs2 != 0) {
1463 if (f->f3.i == 1)
1464 prt_imm(dhp, sign_extend(f->f3a.simm13, 13),
1465 IMM_SIGNED);
1466 else
1467 (void) strlcat(dhp->dh_buf,
1468 reg_names[f->f3.rs2], dhp->dh_buflen);
1469 (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen);
1470 }
1471
1472 (void) strlcat(dhp->dh_buf, regstr, dhp->dh_buflen);
1473 }
1474
1475 return (0);
1476 }
1477
1478 /* ARGSUSED3 */
1479 int
1480 fmt_trap(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
1481 {
1482 ifmt_t *f = (ifmt_t *)&instr;
1483
1484 int v9 = ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) != 0);
1485 int p_rs1, p_t;
1486
1487 if (f->ftcc.undef != 0)
1488 return (-1);
1489
1490 if (icc_names[f->ftcc.cc] == NULL)
1491 return (-1);
1492
1493 if (f->ftcc.i == 1 && f->ftcc.undef2 != 0)
1494 return (-1);
1495
1496 if (f->ftcc2.i == 0 && f->ftcc2.undef2 != 0)
1497 return (-1);
1498
1499 p_rs1 = ((f->ftcc.rs1 != 0) ||
1500 ((dhp->dh_debug & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL)) == 0));
1501
1502 if (f->ftcc.i == 0) {
1503 p_t = (f->f3.rs2 != 0 || p_rs1 == 0);
1504
1505 bprintf(dhp, "%-9s %s%s%s%s%s", inp->in_data.in_def.in_name,
1506 (v9 != 0) ? icc_names[f->ftcc2.cc] : "",
1507 (v9 != 0) ? ", " : "",
1508 (p_rs1 != 0) ? reg_names[f->ftcc2.rs1] : "",
1509 (p_rs1 != 0) ? " + " : "",
1510 (p_t != 0) ? reg_names[f->f3.rs2] : "");
1511 } else {
1512 bprintf(dhp, "%-9s %s%s%s%s0x%x", inp->in_data.in_def.in_name,
1513 (v9 != 0) ? icc_names[f->ftcc2.cc] : "",
1514 (v9 != 0) ? ", " : "",
1515 (p_rs1 != 0) ? reg_names[f->ftcc2.rs1] : "",
1516 (p_rs1 != 0) ? " + " : "",
1517 f->ftcc.immtrap);
1518 }
1519 return (0);
1520 }
1538 cnt = f->f3b.shcnt;
1539 (void) strlcat(name, "x", sizeof (name));
1540 }
1541
1542 prt_name(dhp, name, 1);
1543
1544 if (f->f3b.i == 1)
1545 bprintf(dhp, (octal != 0) ? "%s, 0%lo, %s" : "%s, 0x%lx, %s",
1546 reg_names[f->f3.rs1], cnt, reg_names[f->f3.rd]);
1547 else
1548 bprintf(dhp, "%s, %s, %s", reg_names[f->f3.rs1],
1549 reg_names[f->f3.rs2], reg_names[f->f3.rd]);
1550
1551 return (0);
1552 }
1553
1554 /* ARGSUSED3 */
1555 static int
1556 prt_jmpl(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
1557 {
1558 const char *name = inp->in_data.in_def.in_name;
1559 ifmt_t *f = (ifmt_t *)&instr;
1560
1561 if (f->f3.rd == 15 && ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0))
1562 name = "call";
1563
1564 if (f->f3.rd == 0) {
1565 if (f->f3.i == 1 && f->f3a.simm13 == 8) {
1566 if (f->f3.rs1 == 15) {
1567 prt_name(dhp, "retl", 0);
1568 return (0);
1569 }
1570
1571 if (f->f3.rs1 == 31) {
1572 prt_name(dhp, "ret", 0);
1573 return (0);
1574 }
1575 }
1576
1577 name = "jmp";
1578 }
1579
1580 prt_name(dhp, name, 1);
1581 prt_address(dhp, instr, 1);
1582
1583 if (f->f3.rd == 0)
1584 return (0);
1585
1586 if (f->f3.rd == 15 && ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0))
1587 return (0);
1588
1589 bprintf(dhp, ", %s", reg_names[f->f3.rd]);
1590
1591 return (0);
1592 }
1593
1594 int
1595 fmt_alu(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
1596 {
1597 ifmt_t *f = (ifmt_t *)&instr;
1598
1599 const char *name = inp->in_data.in_def.in_name;
1600 int flags = inp->in_data.in_def.in_flags;
1601 int arg = 0;
1602
1603 if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
1604 prt_field("op", f->f3.op, 2);
1605 prt_field("op3", f->f3.op3, 6);
1606 prt_field("rs1", f->f3.rs1, 5);
1607
1608 switch (idx) {
1609 /* TODO: more formats */
1610
1611 default:
1612 if (f->f3.i == 0)
1613 prt_field("rs2", f->f3.rs2, 5);
1614 else
1615 prt_field("simm13", f->f3a.simm13, 13);
1616
1617 prt_field("rd", f->f3.rd, 5);
1618 }
1619
1620 }
1621
1622 switch (idx) {
1623 case 0x00:
1624 /* add */
1625
1626 if ((dhp->dh_debug & DIS_DEBUG_SYN_ALL) == 0)
1627 break;
1628
1629 if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
1630 f->f3a.simm13 == 1) {
1631 name = "inc";
1632 flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM;
1633 break;
1634 }
1635
1636 if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
1637 f->f3a.simm13 != 1) {
1638 name = "inc";
1639 flags = FLG_P1(REG_NONE);
1640 break;
1641 }
1642 break;
1643
1644 case 0x02:
1645 /* or */
1646
1647 if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT))
1648 == 0)
1649 break;
1650
1651 if ((dhp->dh_debug & DIS_DEBUG_SYN_ALL) != 0) {
1652 if (f->f3.rs1 == f->f3.rd) {
1653 name = "bset";
1654 flags = FLG_P1(REG_NONE);
1655 break;
1656 }
1657 }
1658
1659 if (((f->f3.i == 0 && f->f3.rs2 == 0) ||
1660 (f->f3.i == 1 && f->f3a.simm13 == 0)) &&
1661 (f->f3.rs1 == 0)) {
1662 name = "clr";
1663 flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM;
1664 break;
1665 }
1666
1667 if (f->f3.rs1 == 0) {
1668 name = "mov";
1669 flags = FLG_P1(REG_NONE);
1670 break;
1671 }
1672 break;
1673
1674 case 0x04:
1675 /* sub */
1676
1677 if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT))
1678 == 0)
1679 break;
1680
1681 if (f->f3.rs1 == 0 && f->f3.i == 0 && f->f3.rs2 == f->f3.rd) {
1682 name = "neg";
1683 flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE);
1684 break;
1685 }
1686
1687 if (f->f3.rs1 == 0 && f->f3.i == 0 && f->f3.rs2 != f->f3.rd) {
1688 name = "neg";
1689 flags = FLG_P1(REG_NONE);
1690 break;
1691 }
1692
1693 if ((dhp->dh_debug & DIS_DEBUG_SYN_ALL) == 0)
1694 break;
1695
1696 if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
1697 f->f3a.simm13 == 1) {
1698 name = "dec";
1699 flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM;
1700 break;
1701 }
1702
1703 if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
1704 f->f3a.simm13 != 1) {
1705 name = "dec";
1706 flags = FLG_P1(REG_NONE);
1707 break;
1708 }
1709 break;
1710
1711 case 0x07:
1712 /* xnor */
1713
1714 if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT))
1715 == 0)
1716 break;
1717
1718 /*
1719 * xnor -> not when you have:
1720 * xnor %rs1, 0x0 or %g0, %rd
1721 */
1722 if ((f->f3.i == 0 && f->f3.rs2 != 0) ||
1723 (f->f3.i == 1 && f->f3a.simm13 != 0))
1724 break;
1725
1726 name = "not";
1727
1728 if (f->f3.rs1 == f->f3.rd)
1729 flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM|
1730 FLG_P3(REG_INT);
1731 else
1732 flags = FLG_P1(REG_INT)|FLG_P2(REG_NONE)|FLG_NOIMM|
1733 FLG_P3(REG_INT);
1734
1735 break;
1736
1737 case 0x10:
1738 /* addcc */
1739
1740 if ((dhp->dh_debug & DIS_DEBUG_SYN_ALL) == 0)
1741 break;
1742
1743 if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
1744 f->f3a.simm13 == 1) {
1745 name = "inccc";
1746 flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM;
1747 break;
1748 }
1749
1750 if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
1751 f->f3a.simm13 != 1) {
1752 name = "inccc";
1753 flags = FLG_P1(REG_NONE);
1754 break;
1755 }
1756 break;
1757
1758 case 0x11:
1759 /* andcc */
1760
1761 if (f->f3.rd != 0)
1762 break;
1763
1764 if ((dhp->dh_debug & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL))
1765 == 0)
1766 break;
1767
1768 if (((dhp->dh_debug & DIS_DEBUG_COMPAT) != 0) &&
1769 ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) == 0))
1770 break;
1771
1772 name = "btst";
1773 flags = FLG_P1(REG_NONE);
1774 f->f3.rd = f->f3.rs1;
1775 break;
1776
1777 case 0x12:
1778 /* orcc */
1779
1780 if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT))
1781 == 0)
1782 break;
1783
1784 if (f->f3.rs1 == 0 && f->f3.rd == 0 && f->f3.i == 0) {
1785 name = "tst";
1786 flags = FLG_P1(REG_NONE)|FLG_P3(REG_NONE);
1787 break;
1788 }
1789
1790 if (f->f3.rs2 == 0 && f->f3.rd == 0 && f->f3.i == 0) {
1791 name = "tst";
1792 flags = FLG_P2(REG_NONE)|FLG_P3(REG_NONE);
1793 break;
1794 }
1795
1796 break;
1797
1798 case 0x14:
1799 /* subcc */
1800
1801 if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT))
1802 == 0)
1803 break;
1804
1805 if (f->f3.rd == 0) {
1806 name = "cmp";
1807 flags = FLG_P3(REG_NONE);
1808 break;
1809 }
1810
1811 if ((dhp->dh_debug & DIS_DEBUG_COMPAT) != 0)
1812 break;
1813
1814 if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
1815 f->f3a.simm13 == 1) {
1816 name = "deccc";
1817 flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM;
1818 break;
1819 }
1820
1821 if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
1822 f->f3a.simm13 != 1) {
1823 name = "deccc";
1824 flags = FLG_P1(REG_NONE);
1825 break;
1826 }
1827
1828 break;
1829
1830 case 0x25:
1831 case 0x26:
1851
1852 case 0x38:
1853 /* jmpl */
1854 return (prt_jmpl(dhp, instr, inp, idx));
1855
1856 case 0x39:
1857 /* rett / return */
1858 prt_name(dhp, name, 1);
1859 prt_address(dhp, instr, 1);
1860 return (0);
1861
1862 case 0x3b:
1863 /* flush */
1864 prt_name(dhp, name, 1);
1865 prt_address(dhp, instr, 0);
1866 return (0);
1867
1868 case 0x3c:
1869 case 0x3d:
1870 /* save / restore */
1871 if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT))
1872 == 0)
1873 break;
1874
1875 if (f->f3.rs1 != 0 || f->f3.rs2 != 0 || f->f3.rd != 0)
1876 break;
1877
1878 if (f->f3.i != 0 && ((dhp->dh_debug & DIS_DEBUG_COMPAT) != 0))
1879 break;
1880
1881 prt_name(dhp, name, 0);
1882 return (0);
1883 }
1884
1885 if (FLG_P1_VAL(flags) != REG_NONE || FLG_P2_VAL(flags) != REG_NONE ||
1886 FLG_P3_VAL(flags) != REG_NONE)
1887 arg = 1;
1888
1889 prt_name(dhp, name, (arg != 0));
1890 prt_aluargs(dhp, instr, flags);
1891
1892 return (0);
1893 }
1894
1895 /* ARGSUSED1 */
1896 int
1897 fmt_regwin(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
1898 {
1902
1903 /* ARGSUSED1 */
1904 int
1905 fmt_trap_ret(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
1906 {
1907 ifmt_t *f = (ifmt_t *)&instr;
1908 prt_name(dhp, inp->in_data.in_def.in_name, 1);
1909
1910 if (f->f3.rd == 0xf) {
1911 /* jpriv */
1912 prt_address(dhp, instr, 1);
1913 }
1914
1915 return (0);
1916 }
1917
1918 /* ARGSUSED3 */
1919 int
1920 fmt_movcc(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
1921 {
1922 ifmt_t *f = (ifmt_t *)&instr;
1923 const char **regs = NULL;
1924
1925 if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
1926 prt_field("op", f->f3c.op, 2);
1927 prt_field("op3", f->f3c.op3, 6);
1928 prt_field("cond", f->f3c.cond, 4);
1929 prt_field("cc2", f->f3c.cc2, 1);
1930 prt_field("cc", f->f3c.cc, 2);
1931 prt_field("i", f->f3c.i, 1);
1932
1933 if (f->f3c.i == 0)
1934 prt_field("rs2", f->f3.rs2, 5);
1935 else
1936 prt_field("simm11", f->f3c.simm11, 11);
1937
1938 prt_field("rd", f->f3.rd, 5);
1939 }
1940
1941 if (f->f3c.cc2 == 0) {
1942 regs = fcc_names;
1943 } else {
1944 regs = icc_names;
1945 if (regs[f->f3c.cc] == NULL)
1946 return (-1);
1947 }
1948
1949 prt_name(dhp, inp->in_data.in_def.in_name, 1);
1950
1951 bprintf(dhp, "%s, ", regs[f->f3c.cc]);
1952
1953 if (f->f3c.i == 1)
1954 prt_imm(dhp, sign_extend(f->f3c.simm11, 11), IMM_SIGNED);
1955 else
1956 (void) strlcat(dhp->dh_buf, reg_names[f->f3.rs2],
1957 dhp->dh_buflen);
1958
1959 bprintf(dhp, ", %s", reg_names[f->f3.rd]);
1960
1961 return (0);
1962 }
1963
1964 /* ARGSUSED3 */
1965 int
1966 fmt_movr(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
1967 {
1968 ifmt_t *f = (ifmt_t *)&instr;
1969
1970 prt_name(dhp, inp->in_data.in_def.in_name, 1);
1971
1972 bprintf(dhp, "%s, ", reg_names[f->f3d.rs1]);
1973
1974 if (f->f3d.i == 1)
1975 prt_imm(dhp, sign_extend(f->f3d.simm10, 10), IMM_SIGNED);
1976 else
1977 (void) strlcat(dhp->dh_buf, reg_names[f->f3.rs2],
1978 dhp->dh_buflen);
1979
1980 bprintf(dhp, ", %s", reg_names[f->f3.rd]);
1981
1982 return (0);
1983 }
1984
1985 /* ARGSUSED3 */
1986 int
1987 fmt_fpop1(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
1988 {
1989 ifmt_t *f = (ifmt_t *)&instr;
1990 int flags = inp->in_data.in_def.in_flags;
1991
1992 flags |= FLG_NOIMM;
1993
1994 if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
1995 prt_field("op", f->f3.op, 2);
1996 prt_field("op3", f->f3.op3, 6);
1997 prt_field("opf", f->fcmp.opf, 9);
1998 prt_field("rs1", f->f3.rs1, 5);
1999 prt_field("rs2", f->f3.rs2, 5);
2000 prt_field("rd", f->f3.rd, 5);
2001 }
2002
2003 prt_name(dhp, inp->in_data.in_def.in_name, 1);
2004 prt_aluargs(dhp, instr, flags);
2005
2006 return (0);
2007 }
2008
2009 int
2010 fmt_fpop2(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
2011 {
2012 static const char *condstr_icc[16] = {
2013 "n", "e", "le", "l", "leu", "lu", "neg", "vs",
2014 "a", "nz", "g", "ge", "gu", "geu", "pos", "vc"
2015 };
2016
2017 static const char *condstr_fcc[16] = {
2018 "n", "nz", "lg", "ul", "l", "ug", "g", "u",
2019 "a", "e", "ue", "ge", "uge", "le", "ule", "o"
2020 };
2021
2022 ifmt_t *f = (ifmt_t *)&instr;
2023 const char *ccstr = "";
2024 char name[15];
2025
2026 int flags = inp->in_data.in_def.in_flags;
2027 int is_cmp = (idx == 0x51 || idx == 0x52 || idx == 0x53 ||
2028 idx == 0x55 || idx == 0x56 || idx == 0x57);
2029 int is_fmov = (idx & 0x3f);
2030 int is_v9 = ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) != 0);
2031 int is_compat = ((dhp->dh_debug & DIS_DEBUG_COMPAT) != 0);
2032
2033 int p_cc = 0;
2034
2035 is_fmov = (is_fmov == 0x1 || is_fmov == 0x2 || is_fmov == 0x3);
2036
2037 if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
2038 prt_field("op", f->f3.op, 2);
2039 prt_field("op3", f->f3.op3, 6);
2040 prt_field("opf", f->fcmp.opf, 9);
2041
2042 switch (idx & 0x3f) {
2043 case 0x51:
2044 case 0x52:
2045 case 0x53:
2046 case 0x55:
2047 case 0x56:
2048 case 0x57:
2049 prt_field("cc", f->fcmp.cc, 2);
2050 prt_field("rs1", f->f3.rs1, 5);
2051 prt_field("rs2", f->f3.rs2, 5);
2052 break;
2053
2054 case 0x01:
2055 case 0x02:
2056 case 0x03:
2057 prt_field("opf_low", f->fmv.opf, 6);
2087 : icc_names[f->fmv.cc & 0x3];
2088
2089 if (ccstr == NULL)
2090 return (-1);
2091
2092 p_cc = (is_compat == 0 || is_v9 != 0 ||
2093 (is_cmp != 0 && f->fcmp.cc != 0) ||
2094 (is_fmov != 0 && f->fmv.cc != 0));
2095
2096 if (p_cc != 0)
2097 bprintf(dhp, "%s, ", ccstr);
2098
2099 prt_aluargs(dhp, instr, flags);
2100
2101 return (0);
2102 }
2103
2104 int
2105 fmt_vis(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
2106 {
2107 ifmt_t *f = (ifmt_t *)&instr;
2108 int flags = inp->in_data.in_def.in_flags;
2109
2110 if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
2111 prt_field("op", f->f3.op, 2);
2112 prt_field("op3", f->f3.op3, 6);
2113 prt_field("opf", f->fcmp.opf, 9);
2114
2115 if (idx == 0x081) {
2116 prt_field("mode", instr & 02L, 2);
2117 } else {
2118 prt_field("rs1", f->f3.rs1, 5);
2119 prt_field("rs2", f->f3.rs2, 5);
2120 prt_field("rd", f->f3.rd, 5);
2121 }
2122 }
2123
2124 prt_name(dhp, inp->in_data.in_def.in_name, 1);
2125
2126 if (idx == 0x081) {
2127 /* siam */
2128 bprintf(dhp, "%d", instr & 0x7L);
2129 return (0);
2130 }
2234 default:
2235 fmtstr = (octal != 0) ? "0%lo" : "0x%lx";
2236 }
2237
2238 bprintf(dhp, fmtstr, sv);
2239 }
2240
2241 /*
2242 * return the symbolic name of a register
2243 * regset is one of the REG_* values indicating which type of register it is
2244 * such as integer, floating point, etc.
2245 * idx is the numeric value of the register
2246 *
2247 * If regset is REG_NONE, an empty, but non-NULL string is returned
2248 * NULL may be returned if the index indicates an invalid register value
2249 * such as with the %icc/%xcc sets
2250 */
2251 static const char *
2252 get_regname(dis_handle_t *dhp, int regset, uint32_t idx)
2253 {
2254 const char *regname = NULL;
2255
2256 switch (regset) {
2257 case REG_INT:
2258 regname = reg_names[idx];
2259 break;
2260
2261 case REG_FP:
2262 regname = freg_names[idx];
2263 break;
2264
2265 case REG_FPD:
2266 if (((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0) ||
2267 ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) != 0))
2268 regname = fdreg_names[idx];
2269 else
2270 regname = compat_fdreg_names[idx];
2271
2272 break;
2273
2274 case REG_FPQ:
2275 if ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0)
2276 regname = fqreg_names[idx];
2277 else
2278 regname = freg_names[idx];
2279
2280 break;
2281
2282 case REG_CP:
2283 regname = cpreg_names[idx];
2284 break;
2285
2286 case REG_ICC:
2287 regname = icc_names[idx];
2288 break;
2289
2290 case REG_FCC:
2291 regname = fcc_names[idx];
2292 break;
2293
2294 case REG_FSR:
2295 regname = "%fsr";
2333 /*
2334 * put an address expression into the output buffer
2335 *
2336 * instr is the instruction to use
2337 * if nobrackets != 0, [] are not added around the instruction
2338 *
2339 * Currently this option is set when printing out the address portion
2340 * of a jmpl instruction, but otherwise 0 for load/stores
2341 *
2342 * If no debug flags are set, the full expression is output, even when
2343 * %g0 or 0x0 appears in the address
2344 *
2345 * If DIS_DEBUG_SYN_ALL or DIS_DEBUG_COMPAT are set, when %g0 or 0x0
2346 * appear in the address, they are not output. If the wierd (and probably
2347 * shouldn't happen) address of [%g0 + %g0] or [%g0 + 0x0] is encountered,
2348 * [%g0] is output
2349 */
2350 static void
2351 prt_address(dis_handle_t *dhp, uint32_t instr, int nobrackets)
2352 {
2353 ifmt_t *f = (ifmt_t *)&instr;
2354 int32_t simm13;
2355 int octal = ((dhp->dh_flags & DIS_OCTAL) != 0);
2356 int p1 = ((dhp->dh_debug & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL)) == 0);
2357 int p2 = ((dhp->dh_debug & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL)) == 0);
2358
2359 if (f->f3a.i == 0) {
2360 p1 |= ((f->f3a.rs1 != 0) || f->f3.rs2 == 0);
2361 p2 |= (f->f3.rs2 != 0);
2362
2363 bprintf(dhp, "%s%s%s%s%s",
2364 (nobrackets == 0) ? "[" : "",
2365 (p1 != 0) ? reg_names[f->f3a.rs1] : "",
2366 (p1 != 0 && p2 != 0) ? " + " : "",
2367 (p2 != 0) ? reg_names[f->f3.rs2] : "",
2368 (nobrackets == 0) ? "]" : "");
2369 } else {
2370 const char *sign;
2371
2372 simm13 = sign_extend(f->f3a.simm13, 13);
2373 sign = (simm13 < 0) ? "-" : "+";
2374
2375 p1 |= (f->f3a.rs1 != 0);
2376 p2 |= (p1 == 0 || simm13 != 0);
2377
2404 * print out the arguments to an alu operation (add, sub, etc.)
2405 * conatined in 'instr'
2406 *
2407 * alu instructions have the following format:
2408 * %rs1, %rs2, %rd (i == 0)
2409 * %rs1, 0xnnn, %rd (i == 1)
2410 * ^ ^ ^
2411 * | | |
2412 * p1 p2 p3
2413 *
2414 * flags indicates the register set to use for each position (p1, p2, p3)
2415 * as well as if immediate values (i == 1) are allowed
2416 *
2417 * if flags indicates a specific position has REG_NONE set as it's register
2418 * set, it is omitted from the output. This is primarly used for certain
2419 * floating point operations
2420 */
2421 static void
2422 prt_aluargs(dis_handle_t *dhp, uint32_t instr, uint32_t flags)
2423 {
2424 ifmt_t *f = (ifmt_t *)&instr;
2425 const char *r1, *r2, *r3;
2426 int p1, p2, p3;
2427 unsigned int opf = 0;
2428
2429 r1 = get_regname(dhp, FLG_P1_VAL(flags), f->f3.rs1);
2430 r2 = get_regname(dhp, FLG_P2_VAL(flags), f->f3.rs2);
2431 r3 = get_regname(dhp, FLG_P3_VAL(flags), f->f3.rd);
2432
2433 p1 = (FLG_P1_VAL(flags) != REG_NONE);
2434 p2 = (((flags & FLG_NOIMM) == 0) || (FLG_P2_VAL(flags) != REG_NONE));
2435 p3 = (FLG_RD_VAL(flags) != REG_NONE);
2436
2437 if (r1 == NULL || r1[0] == '\0')
2438 p1 = 0;
2439
2440 if (f->f3a.i == 0 && (r2 == NULL || r2[0] == '\0'))
2441 p2 = 0;
2442
2443 if (r3 == NULL || r3[0] == '\0')
2444 p3 = 0;
2445
2446 if ((f->fcmp.op == 2) && (f->fcmp.op3 == 0x36) && (f->fcmp.cc != 0))
2447 opf = f->fcmp.opf;
2448
2449 if ((opf == 0x151) || (opf == 0x152)) {
2450 (void) strlcat(dhp->dh_buf, r3, dhp->dh_buflen);
2451 (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen);
2452 p3 = 0;
2453 }
2454
2455 if (p1 != 0) {
2456 (void) strlcat(dhp->dh_buf, r1, dhp->dh_buflen);
2457 if (p2 != 0 || p3 != 0)
2458 (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen);
2459 }
2460
2461 if (p2 != 0) {
2462 if (f->f3.i == 0 || ((flags & FLG_NOIMM) != 0))
2463 (void) strlcat(dhp->dh_buf, r2, dhp->dh_buflen);
2464 else
2465 prt_imm(dhp, sign_extend(f->f3a.simm13, 13),
2466 IMM_SIGNED);
2467
2468 if (p3 != 0)
2469 (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen);
2470 }
2471
2472 if (p3 != 0)
2473 (void) strlcat(dhp->dh_buf, r3, dhp->dh_buflen);
2474 }
2475
2476 static const char *
2477 get_asi_name(uint8_t asi)
2478 {
2479 switch (asi) {
2480 case 0x04:
2481 return ("ASI_N");
2482
2483 case 0x0c:
2484 return ("ASI_NL");
2485
2486 case 0x10:
2487 return ("ASI_AIUP");
2488
2489 case 0x11:
2490 return ("ASI_AIUS");
2491
2492 case 0x14:
2493 return ("ASI_REAL");
2725
2726 case 0xf9:
2727 return ("ASI_BLK_SL");
2728
2729 default:
2730 return (NULL);
2731 }
2732 }
2733
2734 /*
2735 * just a handy function that takes care of managing the buffer length
2736 * w/ printf
2737 */
2738
2739 /*
2740 * PRINTF LIKE 1
2741 */
2742 static void
2743 bprintf(dis_handle_t *dhp, const char *fmt, ...)
2744 {
2745 size_t curlen;
2746 va_list ap;
2747
2748 curlen = strlen(dhp->dh_buf);
2749
2750 va_start(ap, fmt);
2751 (void) vsnprintf(dhp->dh_buf + curlen, dhp->dh_buflen - curlen, fmt,
2752 ap);
2753 va_end(ap);
2754 }
|
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Copyright 2009 Jason King. All rights reserved.
29 * Use is subject to license terms.
30 * Copyright 2012 Joshua M. Clulow <josh@sysmgr.org>
31 */
32
33
34 #include <sys/byteorder.h>
35 #include <stdarg.h>
36
37 #if !defined(DIS_STANDALONE)
38 #include <stdio.h>
39 #endif /* DIS_STANDALONE */
40
41 #include "libdisasm.h"
42 #include "libdisasm_impl.h"
43 #include "dis_sparc.h"
44 #include "dis_sparc_fmt.h"
45
46 extern char *strncpy(char *, const char *, size_t);
47 extern size_t strlen(const char *);
48 extern int strcmp(const char *, const char *);
49 extern int strncmp(const char *, const char *, size_t);
50 extern size_t strlcat(char *, const char *, size_t);
51 extern size_t strlcpy(char *, const char *, size_t);
52
53 /*
54 * This file has the functions that do all the dirty work of outputting the
55 * disassembled instruction
56 *
57 * All the non-static functions follow the format_fcn (in dis_sparc.h):
58 * Input:
59 * disassembler handle/context
60 * instruction to disassemble
61 * instruction definition pointer (inst_t *)
62 * index in the table of the instruction
63 * Return:
64 * 0 Success
65 * !0 Invalid instruction
66 *
67 * Generally, instructions found in the same table use the same output format
68 * or have a few minor differences (which are described in the 'flags' field
69 * of the instruction definition. In some cases, certain instructions differ
70 * radically enough from those in the same table, that their own format
71 * function is used.
680 int i;
681
682 for (i = bitlen - 1; i >= 0; --i) {
683 (void) fprintf(stderr, ((val & (1L << i)) != 0) ? "1" : "0");
684
685 if (i % 4 == 0 && i != 0)
686 (void) fprintf(stderr, " ");
687 }
688 }
689 #endif /* DIS_STANDALONE */
690
691
692 /*
693 * print out a call instruction
694 * format: call address <name>
695 */
696 /* ARGSUSED1 */
697 int
698 fmt_call(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
699 {
700 dis_handle_sparc_t *dhx = dhp->dh_arch_private;
701 ifmt_t *f = (ifmt_t *)&instr;
702
703 int32_t disp;
704 size_t curlen;
705
706 int octal = ((dhp->dh_flags & DIS_OCTAL) != 0);
707
708 if ((dhx->dhx_debug & DIS_DEBUG_PRTFMT) != 0) {
709 prt_field("op", f->f1.op, 2);
710 prt_field("disp30", f->f1.disp30, 30);
711 }
712
713 disp = sign_extend(f->f1.disp30, 30) * 4;
714
715 prt_name(dhp, inp->in_data.in_def.in_name, 1);
716
717 bprintf(dhp, (octal != 0) ? "%s0%-11lo" : "%s0x%-10lx",
718 (disp < 0) ? "-" : "+",
719 (disp < 0) ? (-disp) : disp);
720
721 (void) strlcat(dhx->dhx_buf, " <", dhx->dhx_buflen);
722
723 curlen = strlen(dhx->dhx_buf);
724 dhp->dh_lookup(dhp->dh_data, dhp->dh_addr + (int64_t)disp,
725 dhx->dhx_buf + curlen, dhx->dhx_buflen - curlen - 1, NULL,
726 NULL);
727 (void) strlcat(dhx->dhx_buf, ">", dhx->dhx_buflen);
728
729
730 return (0);
731 }
732
733 int
734 fmt_sethi(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
735 {
736 dis_handle_sparc_t *dhx = dhp->dh_arch_private;
737 ifmt_t *f = (ifmt_t *)&instr;
738
739 if ((dhx->dhx_debug & DIS_DEBUG_PRTFMT) != 0) {
740 prt_field("op", f->f2.op, 2);
741 prt_field("op2", f->f2.op2, 3);
742 prt_field("rd", f->f2.rd, 5);
743 prt_field("imm22", f->f2.imm22, 22);
744 }
745
746 if (idx == 0) {
747 /* unimp / illtrap */
748 prt_name(dhp, inp->in_data.in_def.in_name, 1);
749 prt_imm(dhp, f->f2.imm22, 0);
750 return (0);
751 }
752
753 if (f->f2.imm22 == 0 && f->f2.rd == 0) {
754 prt_name(dhp, "nop", 0);
755 return (0);
756 }
757
758 /* ?? Should we return -1 if rd == 0 && disp != 0 */
759
760 prt_name(dhp, inp->in_data.in_def.in_name, 1);
761
762 bprintf(dhp,
763 ((dhp->dh_flags & DIS_OCTAL) != 0) ?
764 "%%hi(0%lo), %s" : "%%hi(0x%lx), %s",
765 f->f2.imm22 << 10,
766 reg_names[f->f2.rd]);
767
768 return (0);
769 }
770
771 /* ARGSUSED3 */
772 int
773 fmt_branch(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
774 {
775 dis_handle_sparc_t *dhx = dhp->dh_arch_private;
776 const char *name = inp->in_data.in_def.in_name;
777 const char *r = NULL;
778 const char *annul = "";
779 const char *pred = "";
780
781 char buf[15];
782
783 ifmt_t *f = (ifmt_t *)&instr;
784
785 size_t curlen;
786 int32_t disp;
787 uint32_t flags = inp->in_data.in_def.in_flags;
788 int octal = ((dhp->dh_flags & DIS_OCTAL) != 0);
789
790 if ((dhx->dhx_debug & DIS_DEBUG_PRTFMT) != 0) {
791 prt_field("op", f->f2.op, 2);
792 prt_field("op2", f->f2.op2, 3);
793
794 switch (FLG_DISP_VAL(flags)) {
795 case DISP22:
796 prt_field("cond", f->f2a.cond, 4);
797 prt_field("a", f->f2a.a, 1);
798 prt_field("disp22", f->f2a.disp22, 22);
799 break;
800
801 case DISP19:
802 prt_field("cond", f->f2a.cond, 4);
803 prt_field("a", f->f2a.a, 1);
804 prt_field("p", f->f2b.p, 1);
805 prt_field("cc", f->f2b.cc, 2);
806 prt_field("disp19", f->f2b.disp19, 19);
807 break;
808
809 case DISP16:
810 prt_field("bit 28", ((instr & (1L << 28)) >> 28), 1);
811 prt_field("rcond", f->f2c.cond, 3);
812 prt_field("p", f->f2c.p, 1);
813 prt_field("rs1", f->f2c.rs1, 5);
814 prt_field("d16hi", f->f2c.d16hi, 2);
815 prt_field("d16lo", f->f2c.d16lo, 14);
816 break;
817 }
818 }
819
820 if (f->f2b.op2 == 0x01 && idx == 0x00 && f->f2b.p == 1 &&
821 f->f2b.cc == 0x02 && ((dhx->dhx_debug & DIS_DEBUG_SYN_ALL) != 0)) {
822 name = "iprefetch";
823 flags = FLG_RS1(REG_NONE)|FLG_DISP(DISP19);
824 }
825
826
827 switch (FLG_DISP_VAL(flags)) {
828 case DISP22:
829 disp = sign_extend(f->f2a.disp22, 22);
830 break;
831
832 case DISP19:
833 disp = sign_extend(f->f2b.disp19, 19);
834 break;
835
836 case DISP16:
837 disp = sign_extend((f->f2c.d16hi << 14)|f->f2c.d16lo, 16);
838 break;
839
840 }
841
842 disp *= 4;
843
844 if ((FLG_RS1_VAL(flags) == REG_ICC) || (FLG_RS1_VAL(flags) == REG_FCC))
845 r = get_regname(dhp, FLG_RS1_VAL(flags), f->f2b.cc);
846 else
847 r = get_regname(dhp, FLG_RS1_VAL(flags), f->f2c.rs1);
848
849 if (r == NULL)
850 return (-1);
851
852 if (f->f2a.a == 1)
853 annul = ",a";
854
855 if ((flags & FLG_PRED) != 0) {
856 if (f->f2b.p == 0) {
857 pred = ",pn";
858 } else {
859 if ((dhx->dhx_debug & DIS_DEBUG_COMPAT) != 0)
860 pred = ",pt";
861 }
862 }
863
864 (void) dis_snprintf(buf, sizeof (buf), "%s%s%s", name, annul, pred);
865 prt_name(dhp, buf, 1);
866
867
868 switch (FLG_DISP_VAL(flags)) {
869 case DISP22:
870 bprintf(dhp,
871 (octal != 0) ? "%s0%-11lo <" : "%s0x%-10lx <",
872 (disp < 0) ? "-" : "+",
873 (disp < 0) ? (-disp) : disp);
874 break;
875
876 case DISP19:
877 bprintf(dhp,
878 (octal != 0) ? "%s, %s0%-5lo <" :
879 "%s, %s0x%-04lx <", r,
880 (disp < 0) ? "-" : "+",
881 (disp < 0) ? (-disp) : disp);
882 break;
883
884 case DISP16:
885 bprintf(dhp,
886 (octal != 0) ? "%s, %s0%-6lo <" : "%s, %s0x%-5lx <",
887 r,
888 (disp < 0) ? "-" : "+",
889 (disp < 0) ? (-disp) : disp);
890 break;
891 }
892
893 curlen = strlen(dhx->dhx_buf);
894 dhp->dh_lookup(dhp->dh_data, dhp->dh_addr + (int64_t)disp,
895 dhx->dhx_buf + curlen, dhx->dhx_buflen - curlen - 1, NULL, NULL);
896
897 (void) strlcat(dhx->dhx_buf, ">", dhx->dhx_buflen);
898
899 return (0);
900 }
901
902
903
904 /*
905 * print out the compare and swap instructions (casa/casxa)
906 * format: casa/casxa [%rs1] imm_asi, %rs2, %rd
907 * casa/casxa [%rs1] %asi, %rs2, %rd
908 *
909 * If DIS_DEBUG_SYN_ALL is set, synthetic instructions are emitted
910 * when an immediate ASI value is given as follows:
911 *
912 * casa [%rs1]#ASI_P, %rs2, %rd -> cas [%rs1], %rs2, %rd
913 * casa [%rs1]#ASI_P_L, %rs2, %rd -> casl [%rs1], %rs2, %rd
914 * casxa [%rs1]#ASI_P, %rs2, %rd -> casx [%rs1], %rs2, %rd
915 * casxa [%rs1]#ASI_P_L, %rs2, %rd -> casxl [%rs1], %rs2, %rd
916 */
917 static int
918 fmt_cas(dis_handle_t *dhp, uint32_t instr, const char *name)
919 {
920 dis_handle_sparc_t *dhx = dhp->dh_arch_private;
921 ifmt_t *f = (ifmt_t *)&instr;
922 const char *asistr = NULL;
923 int noasi = 0;
924
925 asistr = get_asi_name(f->f3.asi);
926
927 if ((dhx->dhx_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT)) != 0) {
928 if (f->f3.op3 == 0x3c && f->f3.i == 0) {
929 if (f->f3.asi == 0x80) {
930 noasi = 1;
931 name = "cas";
932 }
933
934 if (f->f3.asi == 0x88) {
935 noasi = 1;
936 name = "casl";
937 }
938 }
939
940 if (f->f3.op3 == 0x3e && f->f3.i == 0) {
941 if (f->f3.asi == 0x80) {
942 noasi = 1;
943 name = "casx";
944 }
945
946 if (f->f3.asi == 0x88) {
947 noasi = 1;
948 name = "casxl";
949 }
950 }
951 }
952
953 prt_name(dhp, name, 1);
954
955 bprintf(dhp, "[%s]", reg_names[f->f3.rs1]);
956
957 if (noasi == 0) {
958 (void) strlcat(dhx->dhx_buf, " ", dhx->dhx_buflen);
959 prt_asi(dhp, instr);
960 }
961
962 bprintf(dhp, ", %s, %s", reg_names[f->f3.rs2], reg_names[f->f3.rd]);
963
964 if (noasi == 0 && asistr != NULL)
965 bprintf(dhp, "\t<%s>", asistr);
966
967 return (0);
968 }
969
970 /*
971 * format a load/store instruction
972 * format: ldXX [%rs1 + %rs2], %rd load, i==0
973 * ldXX [%rs1 +/- nn], %rd load, i==1
974 * ldXX [%rs1 + %rs2] #XX, %rd load w/ imm_asi, i==0
975 * ldXX [%rs1 +/- nn] %asi, %rd load from asi[%asi], i==1
976 *
977 * stXX %rd, [%rs1 + %rs2] store, i==0
978 * stXX %rd, [%rs1 +/- nn] store, i==1
985 * If DIS_DEBUG_SYNTH_ALL or DIS_DEBUG_COMPAT are set,
986 * When %rs1, %rs2 or nn are 0, they are not printed, i.e.
987 * [ %rs1 + 0x0 ], %rd -> [%rs1], %rd for example
988 *
989 * The following synthetic instructions are also implemented:
990 *
991 * stb %g0, [addr] -> clrb [addr] DIS_DEBUG_SYNTH_ALL
992 * sth %g0, [addr] -> crlh [addr] DIS_DEBUG_SYNTH_ALL
993 * stw %g0, [addr] -> clr [addr] DIS_DEBUG_SYNTH_ALL|DIS_DEBUG_COMPAT
994 * stx %g0, [addr] -> clrx [addr] DIS_DEBUG_SYNTH_ALL
995 *
996 * If DIS_DEBUG_COMPAT is set, the following substitutions also take place
997 * lduw -> ld
998 * ldtw -> ld
999 * stuw -> st
1000 * sttw -> st
1001 */
1002 int
1003 fmt_ls(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
1004 {
1005 dis_handle_sparc_t *dhx = dhp->dh_arch_private;
1006 ifmt_t *f = (ifmt_t *)&instr;
1007 const char *regstr = NULL;
1008 const char *asistr = NULL;
1009
1010 const char *iname = inp->in_data.in_def.in_name;
1011 uint32_t flags = inp->in_data.in_def.in_flags;
1012
1013 if ((dhx->dhx_debug & DIS_DEBUG_PRTFMT) != 0) {
1014 prt_field("op", f->f3.op, 2);
1015 prt_field("op3", f->f3.op3, 6);
1016 prt_field("rs1", f->f3.rs1, 5);
1017 prt_field("i", f->f3.i, 1);
1018 if (f->f3.i != 0) {
1019 prt_field("simm13", f->f3a.simm13, 13);
1020 } else {
1021 if ((flags & FLG_ASI) != 0)
1022 prt_field("imm_asi", f->f3.asi, 8);
1023 prt_field("rs2", f->f3.rs2, 5);
1024 }
1025 prt_field("rd", f->f3.rd, 5);
1026 }
1027
1028 if (idx == 0x2d || idx == 0x3d) {
1029 /* prefetch / prefetcha */
1030
1031 prt_name(dhp, iname, 1);
1032
1033 prt_address(dhp, instr, 0);
1034
1035 if (idx == 0x3d) {
1036 (void) strlcat(dhx->dhx_buf, " ", dhx->dhx_buflen);
1037 prt_asi(dhp, instr);
1038 }
1039
1040 (void) strlcat(dhx->dhx_buf, ", ", dhx->dhx_buflen);
1041
1042 /* fcn field is the same as rd */
1043 if (prefetch_str[f->f3.rd] != NULL)
1044 (void) strlcat(dhx->dhx_buf, prefetch_str[f->f3.rd],
1045 dhx->dhx_buflen);
1046 else
1047 prt_imm(dhp, f->f3.rd, 0);
1048
1049 if (idx == 0x3d && f->f3.i == 0) {
1050 asistr = get_asi_name(f->f3.asi);
1051 if (asistr != NULL)
1052 bprintf(dhp, "\t<%s>", asistr);
1053 }
1054
1055 return (0);
1056 }
1057
1058 /* casa / casxa */
1059 if (idx == 0x3c || idx == 0x3e)
1060 return (fmt_cas(dhp, instr, iname));
1061
1062 /* synthetic instructions & special cases */
1063 switch (idx) {
1064 case 0x00:
1065 /* ld */
1066 if ((dhx->dhx_debug & DIS_DEBUG_COMPAT) == 0)
1067 iname = "lduw";
1068 break;
1069
1070 case 0x03:
1071 if ((dhx->dhx_debug & DIS_DEBUG_COMPAT) == 0)
1072 iname = "ldtw";
1073 break;
1074
1075 case 0x04:
1076 /* stw */
1077 if ((dhx->dhx_debug & DIS_DEBUG_COMPAT) == 0)
1078 iname = "stuw";
1079
1080 if ((dhp->dh_flags & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL))
1081 == 0)
1082 break;
1083
1084 if (f->f3.rd == 0) {
1085 iname = "clr";
1086 flags = FLG_RD(REG_NONE);
1087 }
1088 break;
1089
1090 case 0x05:
1091 /* stb */
1092 if ((dhp->dh_flags & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL))
1093 == 0)
1094 break;
1095
1096 if (f->f3.rd == 0) {
1097 iname = "clrb";
1098 flags = FLG_RD(REG_NONE);
1099 }
1100 break;
1101
1102 case 0x06:
1103 /* sth */
1104 if ((dhp->dh_flags & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL))
1105 == 0)
1106 break;
1107
1108 if (f->f3.rd == 0) {
1109 iname = "clrh";
1110 flags = FLG_RD(REG_NONE);
1111 }
1112 break;
1113
1114 case 0x07:
1115 if ((dhx->dhx_debug & DIS_DEBUG_COMPAT) == 0)
1116 iname = "sttw";
1117 break;
1118
1119 case 0x0e:
1120 /* stx */
1121
1122 if ((dhp->dh_flags & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL))
1123 == 0)
1124 break;
1125
1126 if (f->f3.rd == 0) {
1127 iname = "clrx";
1128 flags = FLG_RD(REG_NONE);
1129 }
1130 break;
1131
1132 case 0x13:
1133 /* ldtwa */
1134 if (((dhx->dhx_debug & DIS_DEBUG_COMPAT) == 0) &&
1135 ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) != 0))
1136 iname = "ldtwa";
1137 break;
1138
1139 case 0x17:
1140 /* sttwa */
1141 if (((dhx->dhx_debug & DIS_DEBUG_COMPAT) == 0) &&
1142 ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) != 0))
1143 iname = "sttwa";
1144 break;
1145
1146 case 0x21:
1147 case 0x25:
1148 /*
1149 * on sparcv8 it merely says that rd != 1 should generate an
1150 * exception, on v9, it is illegal
1151 */
1152 if ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) == 0)
1153 break;
1154
1155 iname = (idx == 0x21) ? "ldx" : "stx";
1156
1157 if (f->f3.rd > 1)
1158 return (-1);
1159
1160 break;
1161
1199 if (asistr != NULL)
1200 bprintf(dhp, "\t<%s>", asistr);
1201
1202 return (0);
1203
1204 default:
1205 break;
1206 }
1207
1208 }
1209
1210 regstr = get_regname(dhp, FLG_RD_VAL(flags), f->f3.rd);
1211
1212 if (f->f3.i == 0)
1213 asistr = get_asi_name(f->f3.asi);
1214
1215 prt_name(dhp, iname, 1);
1216
1217 if ((flags & FLG_STORE) != 0) {
1218 if (regstr[0] != '\0') {
1219 (void) strlcat(dhx->dhx_buf, regstr, dhx->dhx_buflen);
1220 (void) strlcat(dhx->dhx_buf, ", ", dhx->dhx_buflen);
1221 }
1222
1223 prt_address(dhp, instr, 0);
1224 if ((flags & FLG_ASI) != 0) {
1225 (void) strlcat(dhx->dhx_buf, " ", dhx->dhx_buflen);
1226 prt_asi(dhp, instr);
1227 }
1228 } else {
1229 prt_address(dhp, instr, 0);
1230 if ((flags & FLG_ASI) != 0) {
1231 (void) strlcat(dhx->dhx_buf, " ", dhx->dhx_buflen);
1232 prt_asi(dhp, instr);
1233 }
1234
1235 if (regstr[0] != '\0') {
1236 (void) strlcat(dhx->dhx_buf, ", ", dhx->dhx_buflen);
1237 (void) strlcat(dhx->dhx_buf, regstr, dhx->dhx_buflen);
1238 }
1239 }
1240
1241 if ((flags & FLG_ASI) != 0 && asistr != NULL)
1242 bprintf(dhp, "\t<%s>", asistr);
1243
1244 return (0);
1245 }
1246
1247 static int
1248 fmt_cpop(dis_handle_t *dhp, uint32_t instr, const inst_t *inp)
1249 {
1250 dis_handle_sparc_t *dhx = dhp->dh_arch_private;
1251 ifmt_t *f = (ifmt_t *)&instr;
1252 int flags = FLG_P1(REG_CP)|FLG_P2(REG_CP)|FLG_NOIMM|FLG_P3(REG_CP);
1253
1254 if ((dhx->dhx_debug & DIS_DEBUG_PRTFMT) != 0) {
1255 prt_field("op", f->fcp.op, 2);
1256 prt_field("op3", f->fcp.op3, 6);
1257 prt_field("opc", f->fcp.opc, 9);
1258 prt_field("rs1", f->fcp.rs1, 5);
1259 prt_field("rs2", f->fcp.rs2, 5);
1260 prt_field("rd", f->fcp.rd, 5);
1261 }
1262
1263 prt_name(dhp, inp->in_data.in_def.in_name, 1);
1264 prt_imm(dhp, f->fcp.opc, 0);
1265
1266 (void) strlcat(dhx->dhx_buf, ", ", dhx->dhx_buflen);
1267 (void) prt_aluargs(dhp, instr, flags);
1268
1269 return (0);
1270 }
1271
1272 static int
1273 dis_fmt_rdwr(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
1274 {
1275 dis_handle_sparc_t *dhx = dhp->dh_arch_private;
1276 const char *psr_str = "%psr";
1277 const char *wim_str = "%wim";
1278 const char *tbr_str = "%tbr";
1279
1280 const char *name = inp->in_data.in_def.in_name;
1281 const char *regstr = NULL;
1282
1283 ifmt_t *f = (ifmt_t *)&instr;
1284
1285 int rd = (idx < 0x30);
1286 int v9 = (dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI));
1287 int ridx = f->f3.rs1;
1288 int i, first;
1289 int pr_rs1 = 1;
1290 int pr_rs2 = 1;
1291
1292 int use_mask = 1;
1293 uint32_t mask;
1294
1295 if (rd == 0)
1381 mask = v9_asr_wrmask;
1382 } else {
1383 regstr = asr_names[ridx];
1384 mask = asr_wrmask;
1385 }
1386
1387 /*
1388 * sir is shoehorned in here, per Ultrasparc 2007
1389 * hyperprivileged edition, section 7.88, all of
1390 * these must be true to distinguish from WRasr
1391 */
1392 if (v9 != 0 && f->f3.rd == 15 && f->f3.rs1 == 0 &&
1393 f->f3.i == 1) {
1394 prt_name(dhp, "sir", 1);
1395 prt_imm(dhp, sign_extend(f->f3a.simm13, 13),
1396 IMM_SIGNED);
1397 return (0);
1398 }
1399
1400 /* synth: mov */
1401 if ((dhx->dhx_debug & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL))
1402 == 0)
1403 break;
1404
1405 if (v9 == 0) {
1406 if (f->f3.rs1 == 0) {
1407 name = "mov";
1408 pr_rs1 = 0;
1409 }
1410
1411 if ((f->f3.i == 0 && f->f3.rs2 == 0) ||
1412 (f->f3.i == 1 && f->f3a.simm13 == 0)) {
1413 name = "mov";
1414 pr_rs2 = 0;
1415 }
1416 }
1417
1418 if (pr_rs1 == 0)
1419 pr_rs2 = 1;
1420
1421 break;
1453
1454 if (regstr == NULL)
1455 return (-1);
1456
1457 if (use_mask != 0 && ((1L << ridx) & mask) == 0)
1458 return (-1);
1459
1460 prt_name(dhp, name, 1);
1461
1462 if (rd != 0) {
1463 bprintf(dhp, "%s, %s", regstr, reg_names[f->f3.rd]);
1464 } else {
1465 if (pr_rs1 == 1)
1466 bprintf(dhp, "%s, ", reg_names[f->f3.rs1]);
1467
1468 if (pr_rs2 != 0) {
1469 if (f->f3.i == 1)
1470 prt_imm(dhp, sign_extend(f->f3a.simm13, 13),
1471 IMM_SIGNED);
1472 else
1473 (void) strlcat(dhx->dhx_buf,
1474 reg_names[f->f3.rs2], dhx->dhx_buflen);
1475 (void) strlcat(dhx->dhx_buf, ", ", dhx->dhx_buflen);
1476 }
1477
1478 (void) strlcat(dhx->dhx_buf, regstr, dhx->dhx_buflen);
1479 }
1480
1481 return (0);
1482 }
1483
1484 /* ARGSUSED3 */
1485 int
1486 fmt_trap(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
1487 {
1488 dis_handle_sparc_t *dhx = dhp->dh_arch_private;
1489 ifmt_t *f = (ifmt_t *)&instr;
1490
1491 int v9 = ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) != 0);
1492 int p_rs1, p_t;
1493
1494 if (f->ftcc.undef != 0)
1495 return (-1);
1496
1497 if (icc_names[f->ftcc.cc] == NULL)
1498 return (-1);
1499
1500 if (f->ftcc.i == 1 && f->ftcc.undef2 != 0)
1501 return (-1);
1502
1503 if (f->ftcc2.i == 0 && f->ftcc2.undef2 != 0)
1504 return (-1);
1505
1506 p_rs1 = ((f->ftcc.rs1 != 0) ||
1507 ((dhx->dhx_debug & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL)) == 0));
1508
1509 if (f->ftcc.i == 0) {
1510 p_t = (f->f3.rs2 != 0 || p_rs1 == 0);
1511
1512 bprintf(dhp, "%-9s %s%s%s%s%s", inp->in_data.in_def.in_name,
1513 (v9 != 0) ? icc_names[f->ftcc2.cc] : "",
1514 (v9 != 0) ? ", " : "",
1515 (p_rs1 != 0) ? reg_names[f->ftcc2.rs1] : "",
1516 (p_rs1 != 0) ? " + " : "",
1517 (p_t != 0) ? reg_names[f->f3.rs2] : "");
1518 } else {
1519 bprintf(dhp, "%-9s %s%s%s%s0x%x", inp->in_data.in_def.in_name,
1520 (v9 != 0) ? icc_names[f->ftcc2.cc] : "",
1521 (v9 != 0) ? ", " : "",
1522 (p_rs1 != 0) ? reg_names[f->ftcc2.rs1] : "",
1523 (p_rs1 != 0) ? " + " : "",
1524 f->ftcc.immtrap);
1525 }
1526 return (0);
1527 }
1545 cnt = f->f3b.shcnt;
1546 (void) strlcat(name, "x", sizeof (name));
1547 }
1548
1549 prt_name(dhp, name, 1);
1550
1551 if (f->f3b.i == 1)
1552 bprintf(dhp, (octal != 0) ? "%s, 0%lo, %s" : "%s, 0x%lx, %s",
1553 reg_names[f->f3.rs1], cnt, reg_names[f->f3.rd]);
1554 else
1555 bprintf(dhp, "%s, %s, %s", reg_names[f->f3.rs1],
1556 reg_names[f->f3.rs2], reg_names[f->f3.rd]);
1557
1558 return (0);
1559 }
1560
1561 /* ARGSUSED3 */
1562 static int
1563 prt_jmpl(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
1564 {
1565 dis_handle_sparc_t *dhx = dhp->dh_arch_private;
1566 const char *name = inp->in_data.in_def.in_name;
1567 ifmt_t *f = (ifmt_t *)&instr;
1568
1569 if (f->f3.rd == 15 && ((dhx->dhx_debug & DIS_DEBUG_COMPAT) == 0))
1570 name = "call";
1571
1572 if (f->f3.rd == 0) {
1573 if (f->f3.i == 1 && f->f3a.simm13 == 8) {
1574 if (f->f3.rs1 == 15) {
1575 prt_name(dhp, "retl", 0);
1576 return (0);
1577 }
1578
1579 if (f->f3.rs1 == 31) {
1580 prt_name(dhp, "ret", 0);
1581 return (0);
1582 }
1583 }
1584
1585 name = "jmp";
1586 }
1587
1588 prt_name(dhp, name, 1);
1589 prt_address(dhp, instr, 1);
1590
1591 if (f->f3.rd == 0)
1592 return (0);
1593
1594 if (f->f3.rd == 15 && ((dhx->dhx_debug & DIS_DEBUG_COMPAT) == 0))
1595 return (0);
1596
1597 bprintf(dhp, ", %s", reg_names[f->f3.rd]);
1598
1599 return (0);
1600 }
1601
1602 int
1603 fmt_alu(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
1604 {
1605 dis_handle_sparc_t *dhx = dhp->dh_arch_private;
1606 ifmt_t *f = (ifmt_t *)&instr;
1607
1608 const char *name = inp->in_data.in_def.in_name;
1609 int flags = inp->in_data.in_def.in_flags;
1610 int arg = 0;
1611
1612 if ((dhx->dhx_debug & DIS_DEBUG_PRTFMT) != 0) {
1613 prt_field("op", f->f3.op, 2);
1614 prt_field("op3", f->f3.op3, 6);
1615 prt_field("rs1", f->f3.rs1, 5);
1616
1617 switch (idx) {
1618 /* TODO: more formats */
1619
1620 default:
1621 if (f->f3.i == 0)
1622 prt_field("rs2", f->f3.rs2, 5);
1623 else
1624 prt_field("simm13", f->f3a.simm13, 13);
1625
1626 prt_field("rd", f->f3.rd, 5);
1627 }
1628
1629 }
1630
1631 switch (idx) {
1632 case 0x00:
1633 /* add */
1634
1635 if ((dhx->dhx_debug & DIS_DEBUG_SYN_ALL) == 0)
1636 break;
1637
1638 if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
1639 f->f3a.simm13 == 1) {
1640 name = "inc";
1641 flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM;
1642 break;
1643 }
1644
1645 if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
1646 f->f3a.simm13 != 1) {
1647 name = "inc";
1648 flags = FLG_P1(REG_NONE);
1649 break;
1650 }
1651 break;
1652
1653 case 0x02:
1654 /* or */
1655
1656 if ((dhx->dhx_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT))
1657 == 0)
1658 break;
1659
1660 if ((dhx->dhx_debug & DIS_DEBUG_SYN_ALL) != 0) {
1661 if (f->f3.rs1 == f->f3.rd) {
1662 name = "bset";
1663 flags = FLG_P1(REG_NONE);
1664 break;
1665 }
1666 }
1667
1668 if (((f->f3.i == 0 && f->f3.rs2 == 0) ||
1669 (f->f3.i == 1 && f->f3a.simm13 == 0)) &&
1670 (f->f3.rs1 == 0)) {
1671 name = "clr";
1672 flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM;
1673 break;
1674 }
1675
1676 if (f->f3.rs1 == 0) {
1677 name = "mov";
1678 flags = FLG_P1(REG_NONE);
1679 break;
1680 }
1681 break;
1682
1683 case 0x04:
1684 /* sub */
1685
1686 if ((dhx->dhx_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT))
1687 == 0)
1688 break;
1689
1690 if (f->f3.rs1 == 0 && f->f3.i == 0 && f->f3.rs2 == f->f3.rd) {
1691 name = "neg";
1692 flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE);
1693 break;
1694 }
1695
1696 if (f->f3.rs1 == 0 && f->f3.i == 0 && f->f3.rs2 != f->f3.rd) {
1697 name = "neg";
1698 flags = FLG_P1(REG_NONE);
1699 break;
1700 }
1701
1702 if ((dhx->dhx_debug & DIS_DEBUG_SYN_ALL) == 0)
1703 break;
1704
1705 if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
1706 f->f3a.simm13 == 1) {
1707 name = "dec";
1708 flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM;
1709 break;
1710 }
1711
1712 if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
1713 f->f3a.simm13 != 1) {
1714 name = "dec";
1715 flags = FLG_P1(REG_NONE);
1716 break;
1717 }
1718 break;
1719
1720 case 0x07:
1721 /* xnor */
1722
1723 if ((dhx->dhx_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT))
1724 == 0)
1725 break;
1726
1727 /*
1728 * xnor -> not when you have:
1729 * xnor %rs1, 0x0 or %g0, %rd
1730 */
1731 if ((f->f3.i == 0 && f->f3.rs2 != 0) ||
1732 (f->f3.i == 1 && f->f3a.simm13 != 0))
1733 break;
1734
1735 name = "not";
1736
1737 if (f->f3.rs1 == f->f3.rd)
1738 flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM|
1739 FLG_P3(REG_INT);
1740 else
1741 flags = FLG_P1(REG_INT)|FLG_P2(REG_NONE)|FLG_NOIMM|
1742 FLG_P3(REG_INT);
1743
1744 break;
1745
1746 case 0x10:
1747 /* addcc */
1748
1749 if ((dhx->dhx_debug & DIS_DEBUG_SYN_ALL) == 0)
1750 break;
1751
1752 if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
1753 f->f3a.simm13 == 1) {
1754 name = "inccc";
1755 flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM;
1756 break;
1757 }
1758
1759 if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
1760 f->f3a.simm13 != 1) {
1761 name = "inccc";
1762 flags = FLG_P1(REG_NONE);
1763 break;
1764 }
1765 break;
1766
1767 case 0x11:
1768 /* andcc */
1769
1770 if (f->f3.rd != 0)
1771 break;
1772
1773 if ((dhx->dhx_debug & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL))
1774 == 0)
1775 break;
1776
1777 if (((dhx->dhx_debug & DIS_DEBUG_COMPAT) != 0) &&
1778 ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) == 0))
1779 break;
1780
1781 name = "btst";
1782 flags = FLG_P1(REG_NONE);
1783 f->f3.rd = f->f3.rs1;
1784 break;
1785
1786 case 0x12:
1787 /* orcc */
1788
1789 if ((dhx->dhx_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT))
1790 == 0)
1791 break;
1792
1793 if (f->f3.rs1 == 0 && f->f3.rd == 0 && f->f3.i == 0) {
1794 name = "tst";
1795 flags = FLG_P1(REG_NONE)|FLG_P3(REG_NONE);
1796 break;
1797 }
1798
1799 if (f->f3.rs2 == 0 && f->f3.rd == 0 && f->f3.i == 0) {
1800 name = "tst";
1801 flags = FLG_P2(REG_NONE)|FLG_P3(REG_NONE);
1802 break;
1803 }
1804
1805 break;
1806
1807 case 0x14:
1808 /* subcc */
1809
1810 if ((dhx->dhx_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT))
1811 == 0)
1812 break;
1813
1814 if (f->f3.rd == 0) {
1815 name = "cmp";
1816 flags = FLG_P3(REG_NONE);
1817 break;
1818 }
1819
1820 if ((dhx->dhx_debug & DIS_DEBUG_COMPAT) != 0)
1821 break;
1822
1823 if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
1824 f->f3a.simm13 == 1) {
1825 name = "deccc";
1826 flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM;
1827 break;
1828 }
1829
1830 if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
1831 f->f3a.simm13 != 1) {
1832 name = "deccc";
1833 flags = FLG_P1(REG_NONE);
1834 break;
1835 }
1836
1837 break;
1838
1839 case 0x25:
1840 case 0x26:
1860
1861 case 0x38:
1862 /* jmpl */
1863 return (prt_jmpl(dhp, instr, inp, idx));
1864
1865 case 0x39:
1866 /* rett / return */
1867 prt_name(dhp, name, 1);
1868 prt_address(dhp, instr, 1);
1869 return (0);
1870
1871 case 0x3b:
1872 /* flush */
1873 prt_name(dhp, name, 1);
1874 prt_address(dhp, instr, 0);
1875 return (0);
1876
1877 case 0x3c:
1878 case 0x3d:
1879 /* save / restore */
1880 if ((dhx->dhx_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT))
1881 == 0)
1882 break;
1883
1884 if (f->f3.rs1 != 0 || f->f3.rs2 != 0 || f->f3.rd != 0)
1885 break;
1886
1887 if (f->f3.i != 0 && ((dhx->dhx_debug & DIS_DEBUG_COMPAT) != 0))
1888 break;
1889
1890 prt_name(dhp, name, 0);
1891 return (0);
1892 }
1893
1894 if (FLG_P1_VAL(flags) != REG_NONE || FLG_P2_VAL(flags) != REG_NONE ||
1895 FLG_P3_VAL(flags) != REG_NONE)
1896 arg = 1;
1897
1898 prt_name(dhp, name, (arg != 0));
1899 prt_aluargs(dhp, instr, flags);
1900
1901 return (0);
1902 }
1903
1904 /* ARGSUSED1 */
1905 int
1906 fmt_regwin(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
1907 {
1911
1912 /* ARGSUSED1 */
1913 int
1914 fmt_trap_ret(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
1915 {
1916 ifmt_t *f = (ifmt_t *)&instr;
1917 prt_name(dhp, inp->in_data.in_def.in_name, 1);
1918
1919 if (f->f3.rd == 0xf) {
1920 /* jpriv */
1921 prt_address(dhp, instr, 1);
1922 }
1923
1924 return (0);
1925 }
1926
1927 /* ARGSUSED3 */
1928 int
1929 fmt_movcc(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
1930 {
1931 dis_handle_sparc_t *dhx = dhp->dh_arch_private;
1932 ifmt_t *f = (ifmt_t *)&instr;
1933 const char **regs = NULL;
1934
1935 if ((dhx->dhx_debug & DIS_DEBUG_PRTFMT) != 0) {
1936 prt_field("op", f->f3c.op, 2);
1937 prt_field("op3", f->f3c.op3, 6);
1938 prt_field("cond", f->f3c.cond, 4);
1939 prt_field("cc2", f->f3c.cc2, 1);
1940 prt_field("cc", f->f3c.cc, 2);
1941 prt_field("i", f->f3c.i, 1);
1942
1943 if (f->f3c.i == 0)
1944 prt_field("rs2", f->f3.rs2, 5);
1945 else
1946 prt_field("simm11", f->f3c.simm11, 11);
1947
1948 prt_field("rd", f->f3.rd, 5);
1949 }
1950
1951 if (f->f3c.cc2 == 0) {
1952 regs = fcc_names;
1953 } else {
1954 regs = icc_names;
1955 if (regs[f->f3c.cc] == NULL)
1956 return (-1);
1957 }
1958
1959 prt_name(dhp, inp->in_data.in_def.in_name, 1);
1960
1961 bprintf(dhp, "%s, ", regs[f->f3c.cc]);
1962
1963 if (f->f3c.i == 1)
1964 prt_imm(dhp, sign_extend(f->f3c.simm11, 11), IMM_SIGNED);
1965 else
1966 (void) strlcat(dhx->dhx_buf, reg_names[f->f3.rs2],
1967 dhx->dhx_buflen);
1968
1969 bprintf(dhp, ", %s", reg_names[f->f3.rd]);
1970
1971 return (0);
1972 }
1973
1974 /* ARGSUSED3 */
1975 int
1976 fmt_movr(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
1977 {
1978 dis_handle_sparc_t *dhx = dhp->dh_arch_private;
1979 ifmt_t *f = (ifmt_t *)&instr;
1980
1981 prt_name(dhp, inp->in_data.in_def.in_name, 1);
1982
1983 bprintf(dhp, "%s, ", reg_names[f->f3d.rs1]);
1984
1985 if (f->f3d.i == 1)
1986 prt_imm(dhp, sign_extend(f->f3d.simm10, 10), IMM_SIGNED);
1987 else
1988 (void) strlcat(dhx->dhx_buf, reg_names[f->f3.rs2],
1989 dhx->dhx_buflen);
1990
1991 bprintf(dhp, ", %s", reg_names[f->f3.rd]);
1992
1993 return (0);
1994 }
1995
1996 /* ARGSUSED3 */
1997 int
1998 fmt_fpop1(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
1999 {
2000 dis_handle_sparc_t *dhx = dhp->dh_arch_private;
2001 ifmt_t *f = (ifmt_t *)&instr;
2002 int flags = inp->in_data.in_def.in_flags;
2003
2004 flags |= FLG_NOIMM;
2005
2006 if ((dhx->dhx_debug & DIS_DEBUG_PRTFMT) != 0) {
2007 prt_field("op", f->f3.op, 2);
2008 prt_field("op3", f->f3.op3, 6);
2009 prt_field("opf", f->fcmp.opf, 9);
2010 prt_field("rs1", f->f3.rs1, 5);
2011 prt_field("rs2", f->f3.rs2, 5);
2012 prt_field("rd", f->f3.rd, 5);
2013 }
2014
2015 prt_name(dhp, inp->in_data.in_def.in_name, 1);
2016 prt_aluargs(dhp, instr, flags);
2017
2018 return (0);
2019 }
2020
2021 int
2022 fmt_fpop2(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
2023 {
2024 static const char *condstr_icc[16] = {
2025 "n", "e", "le", "l", "leu", "lu", "neg", "vs",
2026 "a", "nz", "g", "ge", "gu", "geu", "pos", "vc"
2027 };
2028
2029 static const char *condstr_fcc[16] = {
2030 "n", "nz", "lg", "ul", "l", "ug", "g", "u",
2031 "a", "e", "ue", "ge", "uge", "le", "ule", "o"
2032 };
2033
2034 dis_handle_sparc_t *dhx = dhp->dh_arch_private;
2035 ifmt_t *f = (ifmt_t *)&instr;
2036 const char *ccstr = "";
2037 char name[15];
2038
2039 int flags = inp->in_data.in_def.in_flags;
2040 int is_cmp = (idx == 0x51 || idx == 0x52 || idx == 0x53 ||
2041 idx == 0x55 || idx == 0x56 || idx == 0x57);
2042 int is_fmov = (idx & 0x3f);
2043 int is_v9 = ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) != 0);
2044 int is_compat = ((dhx->dhx_debug & DIS_DEBUG_COMPAT) != 0);
2045
2046 int p_cc = 0;
2047
2048 is_fmov = (is_fmov == 0x1 || is_fmov == 0x2 || is_fmov == 0x3);
2049
2050 if ((dhx->dhx_debug & DIS_DEBUG_PRTFMT) != 0) {
2051 prt_field("op", f->f3.op, 2);
2052 prt_field("op3", f->f3.op3, 6);
2053 prt_field("opf", f->fcmp.opf, 9);
2054
2055 switch (idx & 0x3f) {
2056 case 0x51:
2057 case 0x52:
2058 case 0x53:
2059 case 0x55:
2060 case 0x56:
2061 case 0x57:
2062 prt_field("cc", f->fcmp.cc, 2);
2063 prt_field("rs1", f->f3.rs1, 5);
2064 prt_field("rs2", f->f3.rs2, 5);
2065 break;
2066
2067 case 0x01:
2068 case 0x02:
2069 case 0x03:
2070 prt_field("opf_low", f->fmv.opf, 6);
2100 : icc_names[f->fmv.cc & 0x3];
2101
2102 if (ccstr == NULL)
2103 return (-1);
2104
2105 p_cc = (is_compat == 0 || is_v9 != 0 ||
2106 (is_cmp != 0 && f->fcmp.cc != 0) ||
2107 (is_fmov != 0 && f->fmv.cc != 0));
2108
2109 if (p_cc != 0)
2110 bprintf(dhp, "%s, ", ccstr);
2111
2112 prt_aluargs(dhp, instr, flags);
2113
2114 return (0);
2115 }
2116
2117 int
2118 fmt_vis(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
2119 {
2120 dis_handle_sparc_t *dhx = dhp->dh_arch_private;
2121 ifmt_t *f = (ifmt_t *)&instr;
2122 int flags = inp->in_data.in_def.in_flags;
2123
2124 if ((dhx->dhx_debug & DIS_DEBUG_PRTFMT) != 0) {
2125 prt_field("op", f->f3.op, 2);
2126 prt_field("op3", f->f3.op3, 6);
2127 prt_field("opf", f->fcmp.opf, 9);
2128
2129 if (idx == 0x081) {
2130 prt_field("mode", instr & 02L, 2);
2131 } else {
2132 prt_field("rs1", f->f3.rs1, 5);
2133 prt_field("rs2", f->f3.rs2, 5);
2134 prt_field("rd", f->f3.rd, 5);
2135 }
2136 }
2137
2138 prt_name(dhp, inp->in_data.in_def.in_name, 1);
2139
2140 if (idx == 0x081) {
2141 /* siam */
2142 bprintf(dhp, "%d", instr & 0x7L);
2143 return (0);
2144 }
2248 default:
2249 fmtstr = (octal != 0) ? "0%lo" : "0x%lx";
2250 }
2251
2252 bprintf(dhp, fmtstr, sv);
2253 }
2254
2255 /*
2256 * return the symbolic name of a register
2257 * regset is one of the REG_* values indicating which type of register it is
2258 * such as integer, floating point, etc.
2259 * idx is the numeric value of the register
2260 *
2261 * If regset is REG_NONE, an empty, but non-NULL string is returned
2262 * NULL may be returned if the index indicates an invalid register value
2263 * such as with the %icc/%xcc sets
2264 */
2265 static const char *
2266 get_regname(dis_handle_t *dhp, int regset, uint32_t idx)
2267 {
2268 dis_handle_sparc_t *dhx = dhp->dh_arch_private;
2269 const char *regname = NULL;
2270
2271 switch (regset) {
2272 case REG_INT:
2273 regname = reg_names[idx];
2274 break;
2275
2276 case REG_FP:
2277 regname = freg_names[idx];
2278 break;
2279
2280 case REG_FPD:
2281 if (((dhx->dhx_debug & DIS_DEBUG_COMPAT) == 0) ||
2282 ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) != 0))
2283 regname = fdreg_names[idx];
2284 else
2285 regname = compat_fdreg_names[idx];
2286
2287 break;
2288
2289 case REG_FPQ:
2290 if ((dhx->dhx_debug & DIS_DEBUG_COMPAT) == 0)
2291 regname = fqreg_names[idx];
2292 else
2293 regname = freg_names[idx];
2294
2295 break;
2296
2297 case REG_CP:
2298 regname = cpreg_names[idx];
2299 break;
2300
2301 case REG_ICC:
2302 regname = icc_names[idx];
2303 break;
2304
2305 case REG_FCC:
2306 regname = fcc_names[idx];
2307 break;
2308
2309 case REG_FSR:
2310 regname = "%fsr";
2348 /*
2349 * put an address expression into the output buffer
2350 *
2351 * instr is the instruction to use
2352 * if nobrackets != 0, [] are not added around the instruction
2353 *
2354 * Currently this option is set when printing out the address portion
2355 * of a jmpl instruction, but otherwise 0 for load/stores
2356 *
2357 * If no debug flags are set, the full expression is output, even when
2358 * %g0 or 0x0 appears in the address
2359 *
2360 * If DIS_DEBUG_SYN_ALL or DIS_DEBUG_COMPAT are set, when %g0 or 0x0
2361 * appear in the address, they are not output. If the wierd (and probably
2362 * shouldn't happen) address of [%g0 + %g0] or [%g0 + 0x0] is encountered,
2363 * [%g0] is output
2364 */
2365 static void
2366 prt_address(dis_handle_t *dhp, uint32_t instr, int nobrackets)
2367 {
2368 dis_handle_sparc_t *dhx = dhp->dh_arch_private;
2369 ifmt_t *f = (ifmt_t *)&instr;
2370 int32_t simm13;
2371 int octal = ((dhp->dh_flags & DIS_OCTAL) != 0);
2372 int p1 = ((dhx->dhx_debug & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL)) == 0);
2373 int p2 = ((dhx->dhx_debug & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL)) == 0);
2374
2375 if (f->f3a.i == 0) {
2376 p1 |= ((f->f3a.rs1 != 0) || f->f3.rs2 == 0);
2377 p2 |= (f->f3.rs2 != 0);
2378
2379 bprintf(dhp, "%s%s%s%s%s",
2380 (nobrackets == 0) ? "[" : "",
2381 (p1 != 0) ? reg_names[f->f3a.rs1] : "",
2382 (p1 != 0 && p2 != 0) ? " + " : "",
2383 (p2 != 0) ? reg_names[f->f3.rs2] : "",
2384 (nobrackets == 0) ? "]" : "");
2385 } else {
2386 const char *sign;
2387
2388 simm13 = sign_extend(f->f3a.simm13, 13);
2389 sign = (simm13 < 0) ? "-" : "+";
2390
2391 p1 |= (f->f3a.rs1 != 0);
2392 p2 |= (p1 == 0 || simm13 != 0);
2393
2420 * print out the arguments to an alu operation (add, sub, etc.)
2421 * conatined in 'instr'
2422 *
2423 * alu instructions have the following format:
2424 * %rs1, %rs2, %rd (i == 0)
2425 * %rs1, 0xnnn, %rd (i == 1)
2426 * ^ ^ ^
2427 * | | |
2428 * p1 p2 p3
2429 *
2430 * flags indicates the register set to use for each position (p1, p2, p3)
2431 * as well as if immediate values (i == 1) are allowed
2432 *
2433 * if flags indicates a specific position has REG_NONE set as it's register
2434 * set, it is omitted from the output. This is primarly used for certain
2435 * floating point operations
2436 */
2437 static void
2438 prt_aluargs(dis_handle_t *dhp, uint32_t instr, uint32_t flags)
2439 {
2440 dis_handle_sparc_t *dhx = dhp->dh_arch_private;
2441 ifmt_t *f = (ifmt_t *)&instr;
2442 const char *r1, *r2, *r3;
2443 int p1, p2, p3;
2444 unsigned int opf = 0;
2445
2446 r1 = get_regname(dhp, FLG_P1_VAL(flags), f->f3.rs1);
2447 r2 = get_regname(dhp, FLG_P2_VAL(flags), f->f3.rs2);
2448 r3 = get_regname(dhp, FLG_P3_VAL(flags), f->f3.rd);
2449
2450 p1 = (FLG_P1_VAL(flags) != REG_NONE);
2451 p2 = (((flags & FLG_NOIMM) == 0) || (FLG_P2_VAL(flags) != REG_NONE));
2452 p3 = (FLG_RD_VAL(flags) != REG_NONE);
2453
2454 if (r1 == NULL || r1[0] == '\0')
2455 p1 = 0;
2456
2457 if (f->f3a.i == 0 && (r2 == NULL || r2[0] == '\0'))
2458 p2 = 0;
2459
2460 if (r3 == NULL || r3[0] == '\0')
2461 p3 = 0;
2462
2463 if ((f->fcmp.op == 2) && (f->fcmp.op3 == 0x36) && (f->fcmp.cc != 0))
2464 opf = f->fcmp.opf;
2465
2466 if ((opf == 0x151) || (opf == 0x152)) {
2467 (void) strlcat(dhx->dhx_buf, r3, dhx->dhx_buflen);
2468 (void) strlcat(dhx->dhx_buf, ", ", dhx->dhx_buflen);
2469 p3 = 0;
2470 }
2471
2472 if (p1 != 0) {
2473 (void) strlcat(dhx->dhx_buf, r1, dhx->dhx_buflen);
2474 if (p2 != 0 || p3 != 0)
2475 (void) strlcat(dhx->dhx_buf, ", ", dhx->dhx_buflen);
2476 }
2477
2478 if (p2 != 0) {
2479 if (f->f3.i == 0 || ((flags & FLG_NOIMM) != 0))
2480 (void) strlcat(dhx->dhx_buf, r2, dhx->dhx_buflen);
2481 else
2482 prt_imm(dhp, sign_extend(f->f3a.simm13, 13),
2483 IMM_SIGNED);
2484
2485 if (p3 != 0)
2486 (void) strlcat(dhx->dhx_buf, ", ", dhx->dhx_buflen);
2487 }
2488
2489 if (p3 != 0)
2490 (void) strlcat(dhx->dhx_buf, r3, dhx->dhx_buflen);
2491 }
2492
2493 static const char *
2494 get_asi_name(uint8_t asi)
2495 {
2496 switch (asi) {
2497 case 0x04:
2498 return ("ASI_N");
2499
2500 case 0x0c:
2501 return ("ASI_NL");
2502
2503 case 0x10:
2504 return ("ASI_AIUP");
2505
2506 case 0x11:
2507 return ("ASI_AIUS");
2508
2509 case 0x14:
2510 return ("ASI_REAL");
2742
2743 case 0xf9:
2744 return ("ASI_BLK_SL");
2745
2746 default:
2747 return (NULL);
2748 }
2749 }
2750
2751 /*
2752 * just a handy function that takes care of managing the buffer length
2753 * w/ printf
2754 */
2755
2756 /*
2757 * PRINTF LIKE 1
2758 */
2759 static void
2760 bprintf(dis_handle_t *dhp, const char *fmt, ...)
2761 {
2762 dis_handle_sparc_t *dhx = dhp->dh_arch_private;
2763 size_t curlen;
2764 va_list ap;
2765
2766 curlen = strlen(dhx->dhx_buf);
2767
2768 va_start(ap, fmt);
2769 (void) dis_vsnprintf(dhx->dhx_buf + curlen, dhx->dhx_buflen -
2770 curlen, fmt, ap);
2771 va_end(ap);
2772 }
|