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