4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Copyright 2009 Jason King. All rights reserved.
29 * Use is subject to license terms.
30 * Copyright 2012 Joshua M. Clulow <josh@sysmgr.org>
34 #include <sys/byteorder.h>
35 #include <sys/debug.h>
38 #if !defined(DIS_STANDALONE)
40 #endif /* DIS_STANDALONE */
42 #include "libdisasm.h"
43 #include "libdisasm_impl.h"
44 #include "dis_sparc.h"
45 #include "dis_sparc_fmt.h"
47 extern char *strncpy(char *, const char *, size_t);
48 extern size_t strlen(const char *);
49 extern int strcmp(const char *, const char *);
50 extern int strncmp(const char *, const char *, size_t);
51 extern size_t strlcat(char *, const char *, size_t);
52 extern size_t strlcpy(char *, const char *, size_t);
55 * This file has the functions that do all the dirty work of outputting the
56 * disassembled instruction
58 * All the non-static functions follow the format_fcn (in dis_sparc.h):
60 * disassembler handle/context
61 * instruction to disassemble
62 * instruction definition pointer (inst_t *)
63 * index in the table of the instruction
66 * !0 Invalid instruction
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
74 * Typically each table has a unique format function defined in this file. In
75 * some cases (such as branches) a common one for all the tables is used.
77 * When adding support for new instructions, it is largely a judgement call
78 * as to when a new format function is defined.
81 /* The various instruction formats of a sparc instruction */
83 #if defined(_BIT_FIELDS_HTOL)
84 typedef struct format1
{
88 #elif defined(_BIT_FIELDS_LTOH)
89 typedef struct format1
{
94 #error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
97 #if defined(_BIT_FIELDS_HTOL)
98 typedef struct format2
{
104 #elif defined(_BIT_FIELDS_LTOH)
105 typedef struct format2
{
112 #error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
115 #if defined(_BIT_FIELDS_HTOL)
116 typedef struct format2a
{
123 #elif defined(_BIT_FIELDS_LTOH)
124 typedef struct format2a
{
132 #error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
135 #if defined(_BIT_FIELDS_HTOL)
136 typedef struct format2b
{
145 #elif defined(_BIT_FIELDS_LTOH)
146 typedef struct format2b
{
156 #error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
159 #if defined(_BIT_FIELDS_HTOL)
160 typedef struct format2c
{
170 #elif defined(_BIT_FIELDS_LTOH)
171 typedef struct format2c
{
182 #error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
185 #if defined(_BIT_FIELDS_HTOL)
186 typedef struct format3
{
195 #elif defined(_BIT_FIELDS_LTOH)
196 typedef struct format3
{
206 #error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
209 #if defined(_BIT_FIELDS_HTOL)
210 typedef struct format3a
{
218 #elif defined(_BIT_FIELDS_LTOH)
219 typedef struct format3a
{
228 #error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
231 #if defined(_BIT_FIELDS_HTOL)
232 typedef struct format3b
{
242 #elif defined(_BIT_FIELDS_LTOH)
243 typedef struct format3b
{
254 #error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
257 #if defined(_BIT_FIELDS_HTOL)
258 typedef struct format3c
{
268 #elif defined(_BIT_FIELDS_LTOH)
269 typedef struct format3c
{
280 #error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
283 #if defined(_BIT_FIELDS_HTOL)
284 typedef struct format3d
{
293 #elif defined(_BIT_FIELDS_LTOH)
294 typedef struct format3d
{
304 #error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
307 #if defined(_BIT_FIELDS_HTOL)
308 typedef struct formatcp
{
316 #elif defined(_BIT_FIELDS_LTOH)
317 typedef struct formatcp
{
326 #error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
329 #if defined(_BIT_FIELDS_HTOL)
330 typedef struct formattcc
{
341 #elif defined(_BIT_FIELDS_LTOH)
342 typedef struct formattcc
{
354 #error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
357 #if defined(_BIT_FIELDS_HTOL)
358 typedef struct formattcc2
{
369 #elif defined(_BIT_FIELDS_LTOH)
370 typedef struct formattcc2
{
382 #error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
385 #if defined(_BIT_FIELDS_HTOL)
386 typedef struct formatmbr
{
396 #elif defined(_BIT_FIELDS_LTOH)
397 typedef struct formatmbr
{
408 #error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
411 #if defined(_BIT_FIELDS_HTOL)
412 typedef struct formatfcmp
{
421 #elif defined(_BIT_FIELDS_LTOH)
422 typedef struct formatfcmp
{
432 #error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
435 #if defined(_BIT_FIELDS_HTOL)
436 typedef struct formatfmov
{
446 #elif defined(_BIT_FIELDS_LTOH)
447 typedef struct formatfmov
{
458 #error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
461 #if defined(_BIT_FIELDS_HTOL)
462 typedef struct formatfused
{
471 #elif defined(_BIT_FIELDS_LTOH)
472 typedef struct formatfused
{
482 #error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
506 /* integer register names */
507 static const char *reg_names
[32] = {
508 "%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7",
509 "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%sp", "%o7",
510 "%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7",
511 "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%fp", "%i7"
514 /* floating point register names */
515 static const char *freg_names
[32] = {
516 "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7",
517 "%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15",
518 "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23",
519 "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31"
522 /* double precision register names */
523 static const char *fdreg_names
[32] = {
524 "%d0", "%d32", "%d2", "%d34", "%d4", "%d36", "%d6", "%d38",
525 "%d8", "%d40", "%d10", "%d42", "%d12", "%d44", "%d14", "%d46",
526 "%d16", "%d48", "%d18", "%d50", "%d20", "%d52", "%d22", "%d54",
527 "%d24", "%d56", "%d26", "%d58", "%d28", "%d60", "%d30", "%d62"
530 static const char *compat_fdreg_names
[32] = {
531 "%f0", "%f32", "%f2", "%f34", "%f4", "%f36", "%f6", "%f38",
532 "%f8", "%f40", "%f10", "%f42", "%f12", "%f44", "%f14", "%f46",
533 "%f16", "%f48", "%f18", "%f50", "%f20", "%f52", "%f22", "%f54",
534 "%f24", "%f56", "%f26", "%f58", "%f28", "%f60", "%f30", "%f62"
538 static const char *fqreg_names
[32] = {
539 "%q0", "%q32", "%f2", "%f3", "%f4", "%q4", "%q36", "%f6",
540 "%f7", "%q8", "%q40", "%f10", "%f11", "%q12", "%q44", "%f14",
541 "%f15", "%q16", "%q48", "%f18", "%f19", "%q20", "%q52", "%f22",
542 "%f23", "%q24", "%q56", "%f26", "%f27", "%q28", "%q60", "%f30",
546 /* coprocessor register names -- sparcv8 only */
547 static const char *cpreg_names
[32] = {
548 "%c0", "%c1", "%c2", "%c3", "%c4", "%c5", "%c6", "%c7",
549 "%c8", "%c9", "%c10", "%c11", "%c12", "%c13", "%c14", "%c15",
550 "%c16", "%c17", "%c18", "%c19", "%c20", "%c21", "%c22", "%c23",
551 "%c24", "%c25", "%c26", "%c27", "%c28", "%c29", "%c30", "%c31",
554 /* floating point condition code names */
555 static const char *fcc_names
[4] = {
556 "%fcc0", "%fcc1", "%fcc2", "%fcc3"
559 /* condition code names */
560 static const char *icc_names
[4] = {
561 "%icc", NULL
, "%xcc", NULL
564 /* bitmask values for membar */
565 static const char *membar_mmask
[4] = {
566 "#LoadLoad", "#StoreLoad", "#LoadStore", "#StoreStore"
569 static const char *membar_cmask
[3] = {
570 "#Lookaside", "#MemIssue", "#Sync"
573 /* v8 ancillary state register names */
574 static const char *asr_names
[32] = {
575 "%y", "%asr1", "%asr2", "%asr3",
576 "%asr4", "%asr5", "%asr6", "%asr7",
577 "%asr8", "%asr9", "%asr10", "%asr11",
578 "%asr12", "%asr13", "%asr14", "%asr15",
579 NULL
, NULL
, NULL
, NULL
,
580 NULL
, NULL
, NULL
, NULL
,
581 NULL
, NULL
, NULL
, NULL
,
582 NULL
, NULL
, NULL
, NULL
584 static const uint32_t asr_rdmask
= 0x0000ffffL
;
585 static const uint32_t asr_wrmask
= 0x0000ffffL
;
587 static const char *v9_asr_names
[32] = {
588 "%y", NULL
, "%ccr", "%asi",
589 "%tick", "%pc", "%fprs", NULL
,
590 NULL
, NULL
, NULL
, NULL
,
591 NULL
, NULL
, NULL
, NULL
,
592 "%pcr", "%pic", "%dcr", "%gsr",
593 "%softint_set", "%softint_clr", "%softint", "%tick_cmpr",
594 "%stick", "%stick_cmpr", NULL
, NULL
,
595 NULL
, NULL
, NULL
, NULL
598 * on v9, only certain registers are valid for read or writing
599 * these are bitmasks corresponding to which registers are valid in which
600 * case. Any access to %dcr is illegal.
602 static const uint32_t v9_asr_rdmask
= 0x03cb007d;
603 static const uint32_t v9_asr_wrmask
= 0x03fb004d;
605 /* privledged register names on v9 */
606 /* TODO: compat - NULL to %priv_nn */
607 static const char *v9_privreg_names
[32] = {
608 "%tpc", "%tnpc", "%tstate", "%tt",
609 "%tick", "%tba", "%pstate", "%tl",
610 "%pil", "%cwp", "%cansave", "%canrestore",
611 "%cleanwin", "%otherwin", "%wstate", "%fq",
612 "%gl", NULL
, NULL
, NULL
,
613 NULL
, NULL
, NULL
, NULL
,
614 NULL
, NULL
, NULL
, NULL
,
615 NULL
, NULL
, NULL
, "%ver"
618 /* hyper privileged register names on v9 */
619 static const char *v9_hprivreg_names
[32] = {
620 "%hpstate", "%htstate", NULL
, "%hintp",
621 NULL
, "%htba", "%hver", NULL
,
622 NULL
, NULL
, NULL
, NULL
,
623 NULL
, NULL
, NULL
, NULL
,
624 NULL
, NULL
, NULL
, NULL
,
625 NULL
, NULL
, NULL
, NULL
,
626 NULL
, NULL
, NULL
, NULL
,
627 NULL
, NULL
, NULL
, "%hstick_cmpr"
630 static const uint32_t v9_pr_rdmask
= 0x80017fff;
631 static const uint32_t v9_pr_wrmask
= 0x00017fff;
632 static const uint32_t v9_hpr_rdmask
= 0x8000006b;
633 static const uint32_t v9_hpr_wrmask
= 0x8000006b;
635 static const char *prefetch_str
[32] = {
636 "#n_reads", "#one_read",
637 "#n_writes", "#one_write",
638 "#page", NULL
, NULL
, NULL
,
639 NULL
, NULL
, NULL
, NULL
,
640 NULL
, NULL
, NULL
, NULL
,
641 NULL
, "#unified", NULL
, NULL
,
642 "#n_reads_strong", "#one_read_strong",
643 "#n_writes_strong", "#one_write_strong",
644 NULL
, NULL
, NULL
, NULL
,
645 NULL
, NULL
, NULL
, NULL
648 static void prt_field(const char *, uint32_t, int);
650 static const char *get_regname(dis_handle_t
*, int, uint32_t);
651 static int32_t sign_extend(int32_t, uint32_t);
653 static void prt_name(dis_handle_t
*, const char *, int);
655 #define IMM_SIGNED 0x01 /* Is immediate value signed */
656 #define IMM_ADDR 0x02 /* Is immediate value part of an address */
657 static void prt_imm(dis_handle_t
*, uint32_t, int);
659 static void prt_asi(dis_handle_t
*, uint32_t);
660 static const char *get_asi_name(uint8_t);
661 static void prt_address(dis_handle_t
*, uint32_t, int);
662 static void prt_aluargs(dis_handle_t
*, uint32_t, uint32_t);
663 static void bprintf(dis_handle_t
*, const char *, ...);
666 * print out val (which is 'bitlen' bits long) in binary
668 #if defined(DIS_STANDALONE)
671 prt_binary(uint32_t val
, int bitlen
)
679 prt_binary(uint32_t val
, int bitlen
)
683 for (i
= bitlen
- 1; i
>= 0; --i
) {
684 (void) fprintf(stderr
, ((val
& (1L << i
)) != 0) ? "1" : "0");
686 if (i
% 4 == 0 && i
!= 0)
687 (void) fprintf(stderr
, " ");
690 #endif /* DIS_STANDALONE */
694 * print out a call instruction
695 * format: call address <name>
699 fmt_call(dis_handle_t
*dhp
, uint32_t instr
, const inst_t
*inp
, int idx
)
701 dis_handle_sparc_t
*dhx
= dhp
->dh_arch_private
;
702 ifmt_t
*f
= (ifmt_t
*)&instr
;
707 int octal
= ((dhp
->dh_flags
& DIS_OCTAL
) != 0);
709 if ((dhx
->dhx_debug
& DIS_DEBUG_PRTFMT
) != 0) {
710 prt_field("op", f
->f1
.op
, 2);
711 prt_field("disp30", f
->f1
.disp30
, 30);
714 disp
= sign_extend(f
->f1
.disp30
, 30) * 4;
716 prt_name(dhp
, inp
->in_data
.in_def
.in_name
, 1);
718 bprintf(dhp
, (octal
!= 0) ? "%s0%-11lo" : "%s0x%-10lx",
719 (disp
< 0) ? "-" : "+",
720 (disp
< 0) ? (-disp
) : disp
);
722 (void) strlcat(dhx
->dhx_buf
, " <", dhx
->dhx_buflen
);
724 curlen
= strlen(dhx
->dhx_buf
);
725 dhp
->dh_lookup(dhp
->dh_data
, dhp
->dh_addr
+ (int64_t)disp
,
726 dhx
->dhx_buf
+ curlen
, dhx
->dhx_buflen
- curlen
- 1, NULL
,
728 (void) strlcat(dhx
->dhx_buf
, ">", dhx
->dhx_buflen
);
735 fmt_sethi(dis_handle_t
*dhp
, uint32_t instr
, const inst_t
*inp
, int idx
)
737 dis_handle_sparc_t
*dhx
= dhp
->dh_arch_private
;
738 ifmt_t
*f
= (ifmt_t
*)&instr
;
740 if ((dhx
->dhx_debug
& DIS_DEBUG_PRTFMT
) != 0) {
741 prt_field("op", f
->f2
.op
, 2);
742 prt_field("op2", f
->f2
.op2
, 3);
743 prt_field("rd", f
->f2
.rd
, 5);
744 prt_field("imm22", f
->f2
.imm22
, 22);
748 /* unimp / illtrap */
749 prt_name(dhp
, inp
->in_data
.in_def
.in_name
, 1);
750 prt_imm(dhp
, f
->f2
.imm22
, 0);
754 if (f
->f2
.imm22
== 0 && f
->f2
.rd
== 0) {
755 prt_name(dhp
, "nop", 0);
759 /* ?? Should we return -1 if rd == 0 && disp != 0 */
761 prt_name(dhp
, inp
->in_data
.in_def
.in_name
, 1);
764 ((dhp
->dh_flags
& DIS_OCTAL
) != 0) ?
765 "%%hi(0%lo), %s" : "%%hi(0x%lx), %s",
767 reg_names
[f
->f2
.rd
]);
774 fmt_branch(dis_handle_t
*dhp
, uint32_t instr
, const inst_t
*inp
, int idx
)
776 dis_handle_sparc_t
*dhx
= dhp
->dh_arch_private
;
777 const char *name
= inp
->in_data
.in_def
.in_name
;
778 const char *r
= NULL
;
779 const char *annul
= "";
780 const char *pred
= "";
784 ifmt_t
*f
= (ifmt_t
*)&instr
;
788 uint32_t flags
= inp
->in_data
.in_def
.in_flags
;
789 int octal
= ((dhp
->dh_flags
& DIS_OCTAL
) != 0);
791 if ((dhx
->dhx_debug
& DIS_DEBUG_PRTFMT
) != 0) {
792 prt_field("op", f
->f2
.op
, 2);
793 prt_field("op2", f
->f2
.op2
, 3);
795 switch (FLG_DISP_VAL(flags
)) {
797 prt_field("cond", f
->f2a
.cond
, 4);
798 prt_field("a", f
->f2a
.a
, 1);
799 prt_field("disp22", f
->f2a
.disp22
, 22);
803 prt_field("cond", f
->f2a
.cond
, 4);
804 prt_field("a", f
->f2a
.a
, 1);
805 prt_field("p", f
->f2b
.p
, 1);
806 prt_field("cc", f
->f2b
.cc
, 2);
807 prt_field("disp19", f
->f2b
.disp19
, 19);
811 prt_field("bit 28", ((instr
& (1L << 28)) >> 28), 1);
812 prt_field("rcond", f
->f2c
.cond
, 3);
813 prt_field("p", f
->f2c
.p
, 1);
814 prt_field("rs1", f
->f2c
.rs1
, 5);
815 prt_field("d16hi", f
->f2c
.d16hi
, 2);
816 prt_field("d16lo", f
->f2c
.d16lo
, 14);
821 if (f
->f2b
.op2
== 0x01 && idx
== 0x00 && f
->f2b
.p
== 1 &&
822 f
->f2b
.cc
== 0x02 && ((dhx
->dhx_debug
& DIS_DEBUG_SYN_ALL
) != 0)) {
824 flags
= FLG_RS1(REG_NONE
)|FLG_DISP(DISP19
);
828 switch (FLG_DISP_VAL(flags
)) {
830 disp
= sign_extend(f
->f2a
.disp22
, 22);
834 disp
= sign_extend(f
->f2b
.disp19
, 19);
838 disp
= sign_extend((f
->f2c
.d16hi
<< 14)|f
->f2c
.d16lo
, 16);
845 if ((FLG_RS1_VAL(flags
) == REG_ICC
) || (FLG_RS1_VAL(flags
) == REG_FCC
))
846 r
= get_regname(dhp
, FLG_RS1_VAL(flags
), f
->f2b
.cc
);
848 r
= get_regname(dhp
, FLG_RS1_VAL(flags
), f
->f2c
.rs1
);
856 if ((flags
& FLG_PRED
) != 0) {
860 if ((dhx
->dhx_debug
& DIS_DEBUG_COMPAT
) != 0)
865 (void) dis_snprintf(buf
, sizeof (buf
), "%s%s%s", name
, annul
, pred
);
866 prt_name(dhp
, buf
, 1);
869 switch (FLG_DISP_VAL(flags
)) {
872 (octal
!= 0) ? "%s0%-11lo <" : "%s0x%-10lx <",
873 (disp
< 0) ? "-" : "+",
874 (disp
< 0) ? (-disp
) : disp
);
879 (octal
!= 0) ? "%s, %s0%-5lo <" :
880 "%s, %s0x%-04lx <", r
,
881 (disp
< 0) ? "-" : "+",
882 (disp
< 0) ? (-disp
) : disp
);
887 (octal
!= 0) ? "%s, %s0%-6lo <" : "%s, %s0x%-5lx <",
889 (disp
< 0) ? "-" : "+",
890 (disp
< 0) ? (-disp
) : disp
);
894 curlen
= strlen(dhx
->dhx_buf
);
895 dhp
->dh_lookup(dhp
->dh_data
, dhp
->dh_addr
+ (int64_t)disp
,
896 dhx
->dhx_buf
+ curlen
, dhx
->dhx_buflen
- curlen
- 1, NULL
, NULL
);
898 (void) strlcat(dhx
->dhx_buf
, ">", dhx
->dhx_buflen
);
906 * print out the compare and swap instructions (casa/casxa)
907 * format: casa/casxa [%rs1] imm_asi, %rs2, %rd
908 * casa/casxa [%rs1] %asi, %rs2, %rd
910 * If DIS_DEBUG_SYN_ALL is set, synthetic instructions are emitted
911 * when an immediate ASI value is given as follows:
913 * casa [%rs1]#ASI_P, %rs2, %rd -> cas [%rs1], %rs2, %rd
914 * casa [%rs1]#ASI_P_L, %rs2, %rd -> casl [%rs1], %rs2, %rd
915 * casxa [%rs1]#ASI_P, %rs2, %rd -> casx [%rs1], %rs2, %rd
916 * casxa [%rs1]#ASI_P_L, %rs2, %rd -> casxl [%rs1], %rs2, %rd
919 fmt_cas(dis_handle_t
*dhp
, uint32_t instr
, const char *name
)
921 dis_handle_sparc_t
*dhx
= dhp
->dh_arch_private
;
922 ifmt_t
*f
= (ifmt_t
*)&instr
;
923 const char *asistr
= NULL
;
926 asistr
= get_asi_name(f
->f3
.asi
);
928 if ((dhx
->dhx_debug
& (DIS_DEBUG_SYN_ALL
|DIS_DEBUG_COMPAT
)) != 0) {
929 if (f
->f3
.op3
== 0x3c && f
->f3
.i
== 0) {
930 if (f
->f3
.asi
== 0x80) {
935 if (f
->f3
.asi
== 0x88) {
941 if (f
->f3
.op3
== 0x3e && f
->f3
.i
== 0) {
942 if (f
->f3
.asi
== 0x80) {
947 if (f
->f3
.asi
== 0x88) {
954 prt_name(dhp
, name
, 1);
956 bprintf(dhp
, "[%s]", reg_names
[f
->f3
.rs1
]);
959 (void) strlcat(dhx
->dhx_buf
, " ", dhx
->dhx_buflen
);
963 bprintf(dhp
, ", %s, %s", reg_names
[f
->f3
.rs2
], reg_names
[f
->f3
.rd
]);
965 if (noasi
== 0 && asistr
!= NULL
)
966 bprintf(dhp
, "\t<%s>", asistr
);
972 * format a load/store instruction
973 * format: ldXX [%rs1 + %rs2], %rd load, i==0
974 * ldXX [%rs1 +/- nn], %rd load, i==1
975 * ldXX [%rs1 + %rs2] #XX, %rd load w/ imm_asi, i==0
976 * ldXX [%rs1 +/- nn] %asi, %rd load from asi[%asi], i==1
978 * stXX %rd, [%rs1 + %rs2] store, i==0
979 * stXX %rd, [%rs1 +/- nn] store, i==1
980 * stXX %rd, [%rs1 + %rs1] #XX store to imm_asi, i==0
981 * stXX %rd, [%rs1 +/-nn] %asi store to asi[%asi], i==1
983 * The register sets used for %rd are set in the instructions flags field
984 * The asi variants are used if FLG_ASI is set in the instructions flags field
986 * If DIS_DEBUG_SYNTH_ALL or DIS_DEBUG_COMPAT are set,
987 * When %rs1, %rs2 or nn are 0, they are not printed, i.e.
988 * [ %rs1 + 0x0 ], %rd -> [%rs1], %rd for example
990 * The following synthetic instructions are also implemented:
992 * stb %g0, [addr] -> clrb [addr] DIS_DEBUG_SYNTH_ALL
993 * sth %g0, [addr] -> crlh [addr] DIS_DEBUG_SYNTH_ALL
994 * stw %g0, [addr] -> clr [addr] DIS_DEBUG_SYNTH_ALL|DIS_DEBUG_COMPAT
995 * stx %g0, [addr] -> clrx [addr] DIS_DEBUG_SYNTH_ALL
997 * If DIS_DEBUG_COMPAT is set, the following substitutions also take place
1004 fmt_ls(dis_handle_t
*dhp
, uint32_t instr
, const inst_t
*inp
, int idx
)
1006 dis_handle_sparc_t
*dhx
= dhp
->dh_arch_private
;
1007 ifmt_t
*f
= (ifmt_t
*)&instr
;
1008 const char *regstr
= NULL
;
1009 const char *asistr
= NULL
;
1011 const char *iname
= inp
->in_data
.in_def
.in_name
;
1012 uint32_t flags
= inp
->in_data
.in_def
.in_flags
;
1014 if ((dhx
->dhx_debug
& DIS_DEBUG_PRTFMT
) != 0) {
1015 prt_field("op", f
->f3
.op
, 2);
1016 prt_field("op3", f
->f3
.op3
, 6);
1017 prt_field("rs1", f
->f3
.rs1
, 5);
1018 prt_field("i", f
->f3
.i
, 1);
1020 prt_field("simm13", f
->f3a
.simm13
, 13);
1022 if ((flags
& FLG_ASI
) != 0)
1023 prt_field("imm_asi", f
->f3
.asi
, 8);
1024 prt_field("rs2", f
->f3
.rs2
, 5);
1026 prt_field("rd", f
->f3
.rd
, 5);
1029 if (idx
== 0x2d || idx
== 0x3d) {
1030 /* prefetch / prefetcha */
1032 prt_name(dhp
, iname
, 1);
1034 prt_address(dhp
, instr
, 0);
1037 (void) strlcat(dhx
->dhx_buf
, " ", dhx
->dhx_buflen
);
1038 prt_asi(dhp
, instr
);
1041 (void) strlcat(dhx
->dhx_buf
, ", ", dhx
->dhx_buflen
);
1043 /* fcn field is the same as rd */
1044 if (prefetch_str
[f
->f3
.rd
] != NULL
)
1045 (void) strlcat(dhx
->dhx_buf
, prefetch_str
[f
->f3
.rd
],
1048 prt_imm(dhp
, f
->f3
.rd
, 0);
1050 if (idx
== 0x3d && f
->f3
.i
== 0) {
1051 asistr
= get_asi_name(f
->f3
.asi
);
1053 bprintf(dhp
, "\t<%s>", asistr
);
1060 if (idx
== 0x3c || idx
== 0x3e)
1061 return (fmt_cas(dhp
, instr
, iname
));
1063 /* synthetic instructions & special cases */
1067 if ((dhx
->dhx_debug
& DIS_DEBUG_COMPAT
) == 0)
1072 if ((dhx
->dhx_debug
& DIS_DEBUG_COMPAT
) == 0)
1078 if ((dhx
->dhx_debug
& DIS_DEBUG_COMPAT
) == 0)
1081 if ((dhp
->dh_flags
& (DIS_DEBUG_COMPAT
|DIS_DEBUG_SYN_ALL
))
1085 if (f
->f3
.rd
== 0) {
1087 flags
= FLG_RD(REG_NONE
);
1093 if ((dhp
->dh_flags
& (DIS_DEBUG_COMPAT
|DIS_DEBUG_SYN_ALL
))
1097 if (f
->f3
.rd
== 0) {
1099 flags
= FLG_RD(REG_NONE
);
1105 if ((dhp
->dh_flags
& (DIS_DEBUG_COMPAT
|DIS_DEBUG_SYN_ALL
))
1109 if (f
->f3
.rd
== 0) {
1111 flags
= FLG_RD(REG_NONE
);
1116 if ((dhx
->dhx_debug
& DIS_DEBUG_COMPAT
) == 0)
1123 if ((dhp
->dh_flags
& (DIS_DEBUG_COMPAT
|DIS_DEBUG_SYN_ALL
))
1127 if (f
->f3
.rd
== 0) {
1129 flags
= FLG_RD(REG_NONE
);
1135 if (((dhx
->dhx_debug
& DIS_DEBUG_COMPAT
) == 0) &&
1136 ((dhp
->dh_flags
& (DIS_SPARC_V9
|DIS_SPARC_V9_SGI
)) != 0))
1142 if (((dhx
->dhx_debug
& DIS_DEBUG_COMPAT
) == 0) &&
1143 ((dhp
->dh_flags
& (DIS_SPARC_V9
|DIS_SPARC_V9_SGI
)) != 0))
1150 * on sparcv8 it merely says that rd != 1 should generate an
1151 * exception, on v9, it is illegal
1153 if ((dhp
->dh_flags
& (DIS_SPARC_V9
|DIS_SPARC_V9_SGI
)) == 0)
1156 iname
= (idx
== 0x21) ? "ldx" : "stx";
1165 switch (f
->f3
.asi
) {
1179 * store partial floating point, only valid w/
1182 * Somewhat confusingly, it uses the same op
1183 * code as 'stda' -- store double to alternate
1184 * space. It is distinguised by specific
1185 * imm_asi values (as seen above), and
1186 * has a slightly different output syntax
1189 if ((dhp
->dh_flags
& DIS_SPARC_V9_SGI
) == 0)
1193 prt_name(dhp
, iname
, 1);
1194 bprintf(dhp
, "%s, %s, [%s] ",
1195 get_regname(dhp
, REG_FPD
, f
->f3
.rd
),
1196 get_regname(dhp
, REG_FPD
, f
->f3
.rs2
),
1197 get_regname(dhp
, REG_FPD
, f
->f3
.rs1
));
1198 prt_asi(dhp
, instr
);
1199 asistr
= get_asi_name(f
->f3
.asi
);
1201 bprintf(dhp
, "\t<%s>", asistr
);
1211 regstr
= get_regname(dhp
, FLG_RD_VAL(flags
), f
->f3
.rd
);
1214 asistr
= get_asi_name(f
->f3
.asi
);
1216 prt_name(dhp
, iname
, 1);
1218 if ((flags
& FLG_STORE
) != 0) {
1219 if (regstr
[0] != '\0') {
1220 (void) strlcat(dhx
->dhx_buf
, regstr
, dhx
->dhx_buflen
);
1221 (void) strlcat(dhx
->dhx_buf
, ", ", dhx
->dhx_buflen
);
1224 prt_address(dhp
, instr
, 0);
1225 if ((flags
& FLG_ASI
) != 0) {
1226 (void) strlcat(dhx
->dhx_buf
, " ", dhx
->dhx_buflen
);
1227 prt_asi(dhp
, instr
);
1230 prt_address(dhp
, instr
, 0);
1231 if ((flags
& FLG_ASI
) != 0) {
1232 (void) strlcat(dhx
->dhx_buf
, " ", dhx
->dhx_buflen
);
1233 prt_asi(dhp
, instr
);
1236 if (regstr
[0] != '\0') {
1237 (void) strlcat(dhx
->dhx_buf
, ", ", dhx
->dhx_buflen
);
1238 (void) strlcat(dhx
->dhx_buf
, regstr
, dhx
->dhx_buflen
);
1242 if ((flags
& FLG_ASI
) != 0 && asistr
!= NULL
)
1243 bprintf(dhp
, "\t<%s>", asistr
);
1249 fmt_cpop(dis_handle_t
*dhp
, uint32_t instr
, const inst_t
*inp
)
1251 dis_handle_sparc_t
*dhx
= dhp
->dh_arch_private
;
1252 ifmt_t
*f
= (ifmt_t
*)&instr
;
1253 int flags
= FLG_P1(REG_CP
)|FLG_P2(REG_CP
)|FLG_NOIMM
|FLG_P3(REG_CP
);
1255 if ((dhx
->dhx_debug
& DIS_DEBUG_PRTFMT
) != 0) {
1256 prt_field("op", f
->fcp
.op
, 2);
1257 prt_field("op3", f
->fcp
.op3
, 6);
1258 prt_field("opc", f
->fcp
.opc
, 9);
1259 prt_field("rs1", f
->fcp
.rs1
, 5);
1260 prt_field("rs2", f
->fcp
.rs2
, 5);
1261 prt_field("rd", f
->fcp
.rd
, 5);
1264 prt_name(dhp
, inp
->in_data
.in_def
.in_name
, 1);
1265 prt_imm(dhp
, f
->fcp
.opc
, 0);
1267 (void) strlcat(dhx
->dhx_buf
, ", ", dhx
->dhx_buflen
);
1268 (void) prt_aluargs(dhp
, instr
, flags
);
1274 dis_fmt_rdwr(dis_handle_t
*dhp
, uint32_t instr
, const inst_t
*inp
, int idx
)
1276 dis_handle_sparc_t
*dhx
= dhp
->dh_arch_private
;
1277 const char *psr_str
= "%psr";
1278 const char *wim_str
= "%wim";
1279 const char *tbr_str
= "%tbr";
1281 const char *name
= inp
->in_data
.in_def
.in_name
;
1282 const char *regstr
= NULL
;
1284 ifmt_t
*f
= (ifmt_t
*)&instr
;
1286 int rd
= (idx
< 0x30);
1287 int v9
= (dhp
->dh_flags
& (DIS_SPARC_V9
|DIS_SPARC_V9_SGI
));
1288 int ridx
= f
->f3
.rs1
;
1304 if ((f
->f3
.rd
== 0) && (f
->f3
.rs1
== 15) && (f
->f3
.i
== 0)) {
1305 prt_name(dhp
, "stbar", 0);
1310 if ((v9
!= 0) && (f
->f3
.rd
== 0) && (f
->f3
.rs1
== 15) &&
1311 (f
->f3
.i
== 1) && ((f
->i
& (1L << 12)) == 0)) {
1313 prt_name(dhp
, "membar",
1314 ((f
->fmb
.cmask
!= 0) || (f
->fmb
.mmask
!= 0)));
1318 for (i
= 0; i
< 4; ++i
) {
1319 if ((f
->fmb
.cmask
& (1L << i
)) != 0) {
1320 bprintf(dhp
, "%s%s",
1321 (first
!= 0) ? "|" : "",
1327 for (i
= 0; i
< 5; ++i
) {
1328 if ((f
->fmb
.mmask
& (1L << i
)) != 0) {
1329 bprintf(dhp
, "%s%s",
1330 (first
!= 0) ? "|" : "",
1340 regstr
= v9_asr_names
[ridx
];
1341 mask
= v9_asr_rdmask
;
1343 regstr
= asr_names
[ridx
];
1350 regstr
= v9_hprivreg_names
[ridx
];
1351 mask
= v9_hpr_rdmask
;
1360 regstr
= v9_privreg_names
[ridx
];
1361 mask
= v9_pr_rdmask
;
1371 prt_name(dhp
, name
, 0);
1381 regstr
= v9_asr_names
[ridx
];
1382 mask
= v9_asr_wrmask
;
1384 regstr
= asr_names
[ridx
];
1389 * sir is shoehorned in here, per Ultrasparc 2007
1390 * hyperprivileged edition, section 7.88, all of
1391 * these must be true to distinguish from WRasr
1393 if (v9
!= 0 && f
->f3
.rd
== 15 && f
->f3
.rs1
== 0 &&
1395 prt_name(dhp
, "sir", 1);
1396 prt_imm(dhp
, sign_extend(f
->f3a
.simm13
, 13),
1402 if ((dhx
->dhx_debug
& (DIS_DEBUG_COMPAT
|DIS_DEBUG_SYN_ALL
))
1407 if (f
->f3
.rs1
== 0) {
1412 if ((f
->f3
.i
== 0 && f
->f3
.rs2
== 0) ||
1413 (f
->f3
.i
== 1 && f
->f3a
.simm13
== 0)) {
1426 * NOTE: due to the presence of an overlay entry for another
1427 * table, this case only happens when doing v8 instructions
1436 regstr
= v9_privreg_names
[ridx
];
1437 mask
= v9_pr_wrmask
;
1446 regstr
= v9_hprivreg_names
[ridx
];
1447 mask
= v9_hpr_wrmask
;
1458 if (use_mask
!= 0 && ((1L << ridx
) & mask
) == 0)
1461 prt_name(dhp
, name
, 1);
1464 bprintf(dhp
, "%s, %s", regstr
, reg_names
[f
->f3
.rd
]);
1467 bprintf(dhp
, "%s, ", reg_names
[f
->f3
.rs1
]);
1471 prt_imm(dhp
, sign_extend(f
->f3a
.simm13
, 13),
1474 (void) strlcat(dhx
->dhx_buf
,
1475 reg_names
[f
->f3
.rs2
], dhx
->dhx_buflen
);
1476 (void) strlcat(dhx
->dhx_buf
, ", ", dhx
->dhx_buflen
);
1479 (void) strlcat(dhx
->dhx_buf
, regstr
, dhx
->dhx_buflen
);
1487 fmt_trap(dis_handle_t
*dhp
, uint32_t instr
, const inst_t
*inp
, int idx
)
1489 dis_handle_sparc_t
*dhx
= dhp
->dh_arch_private
;
1490 ifmt_t
*f
= (ifmt_t
*)&instr
;
1492 int v9
= ((dhp
->dh_flags
& (DIS_SPARC_V9
|DIS_SPARC_V9_SGI
)) != 0);
1495 if (f
->ftcc
.undef
!= 0)
1498 if (icc_names
[f
->ftcc
.cc
] == NULL
)
1501 if (f
->ftcc
.i
== 1 && f
->ftcc
.undef2
!= 0)
1504 if (f
->ftcc2
.i
== 0 && f
->ftcc2
.undef2
!= 0)
1507 p_rs1
= ((f
->ftcc
.rs1
!= 0) ||
1508 ((dhx
->dhx_debug
& (DIS_DEBUG_COMPAT
|DIS_DEBUG_SYN_ALL
)) == 0));
1510 if (f
->ftcc
.i
== 0) {
1511 p_t
= (f
->f3
.rs2
!= 0 || p_rs1
== 0);
1513 bprintf(dhp
, "%-9s %s%s%s%s%s", inp
->in_data
.in_def
.in_name
,
1514 (v9
!= 0) ? icc_names
[f
->ftcc2
.cc
] : "",
1515 (v9
!= 0) ? ", " : "",
1516 (p_rs1
!= 0) ? reg_names
[f
->ftcc2
.rs1
] : "",
1517 (p_rs1
!= 0) ? " + " : "",
1518 (p_t
!= 0) ? reg_names
[f
->f3
.rs2
] : "");
1520 bprintf(dhp
, "%-9s %s%s%s%s0x%x", inp
->in_data
.in_def
.in_name
,
1521 (v9
!= 0) ? icc_names
[f
->ftcc2
.cc
] : "",
1522 (v9
!= 0) ? ", " : "",
1523 (p_rs1
!= 0) ? reg_names
[f
->ftcc2
.rs1
] : "",
1524 (p_rs1
!= 0) ? " + " : "",
1531 prt_shift(dis_handle_t
*dhp
, uint32_t instr
, const inst_t
*inp
)
1536 ifmt_t
*f
= (ifmt_t
*)&instr
;
1537 int octal
= ((dhp
->dh_flags
& DIS_OCTAL
) != 0);
1540 (void) strlcat(name
, inp
->in_data
.in_def
.in_name
, sizeof (name
));
1545 if (f
->f3b
.x
== 1 && ((dhp
->dh_flags
& DIS_SPARC_V8
) == 0)) {
1547 (void) strlcat(name
, "x", sizeof (name
));
1550 prt_name(dhp
, name
, 1);
1553 bprintf(dhp
, (octal
!= 0) ? "%s, 0%lo, %s" : "%s, 0x%lx, %s",
1554 reg_names
[f
->f3
.rs1
], cnt
, reg_names
[f
->f3
.rd
]);
1556 bprintf(dhp
, "%s, %s, %s", reg_names
[f
->f3
.rs1
],
1557 reg_names
[f
->f3
.rs2
], reg_names
[f
->f3
.rd
]);
1564 prt_jmpl(dis_handle_t
*dhp
, uint32_t instr
, const inst_t
*inp
, int idx
)
1566 dis_handle_sparc_t
*dhx
= dhp
->dh_arch_private
;
1567 const char *name
= inp
->in_data
.in_def
.in_name
;
1568 ifmt_t
*f
= (ifmt_t
*)&instr
;
1570 if (f
->f3
.rd
== 15 && ((dhx
->dhx_debug
& DIS_DEBUG_COMPAT
) == 0))
1573 if (f
->f3
.rd
== 0) {
1574 if (f
->f3
.i
== 1 && f
->f3a
.simm13
== 8) {
1575 if (f
->f3
.rs1
== 15) {
1576 prt_name(dhp
, "retl", 0);
1580 if (f
->f3
.rs1
== 31) {
1581 prt_name(dhp
, "ret", 0);
1589 prt_name(dhp
, name
, 1);
1590 prt_address(dhp
, instr
, 1);
1595 if (f
->f3
.rd
== 15 && ((dhx
->dhx_debug
& DIS_DEBUG_COMPAT
) == 0))
1598 bprintf(dhp
, ", %s", reg_names
[f
->f3
.rd
]);
1604 fmt_alu(dis_handle_t
*dhp
, uint32_t instr
, const inst_t
*inp
, int idx
)
1606 dis_handle_sparc_t
*dhx
= dhp
->dh_arch_private
;
1607 ifmt_t
*f
= (ifmt_t
*)&instr
;
1609 const char *name
= inp
->in_data
.in_def
.in_name
;
1610 int flags
= inp
->in_data
.in_def
.in_flags
;
1613 if ((dhx
->dhx_debug
& DIS_DEBUG_PRTFMT
) != 0) {
1614 prt_field("op", f
->f3
.op
, 2);
1615 prt_field("op3", f
->f3
.op3
, 6);
1616 prt_field("rs1", f
->f3
.rs1
, 5);
1619 /* TODO: more formats */
1623 prt_field("rs2", f
->f3
.rs2
, 5);
1625 prt_field("simm13", f
->f3a
.simm13
, 13);
1627 prt_field("rd", f
->f3
.rd
, 5);
1636 if ((dhx
->dhx_debug
& DIS_DEBUG_SYN_ALL
) == 0)
1639 if (f
->f3
.rs1
== f
->f3
.rd
&& f
->f3
.i
== 1 &&
1640 f
->f3a
.simm13
== 1) {
1642 flags
= FLG_P1(REG_NONE
)|FLG_P2(REG_NONE
)|FLG_NOIMM
;
1646 if (f
->f3
.rs1
== f
->f3
.rd
&& f
->f3
.i
== 1 &&
1647 f
->f3a
.simm13
!= 1) {
1649 flags
= FLG_P1(REG_NONE
);
1657 if ((dhx
->dhx_debug
& (DIS_DEBUG_SYN_ALL
|DIS_DEBUG_COMPAT
))
1661 if ((dhx
->dhx_debug
& DIS_DEBUG_SYN_ALL
) != 0) {
1662 if (f
->f3
.rs1
== f
->f3
.rd
) {
1664 flags
= FLG_P1(REG_NONE
);
1669 if (((f
->f3
.i
== 0 && f
->f3
.rs2
== 0) ||
1670 (f
->f3
.i
== 1 && f
->f3a
.simm13
== 0)) &&
1673 flags
= FLG_P1(REG_NONE
)|FLG_P2(REG_NONE
)|FLG_NOIMM
;
1677 if (f
->f3
.rs1
== 0) {
1679 flags
= FLG_P1(REG_NONE
);
1687 if ((dhx
->dhx_debug
& (DIS_DEBUG_SYN_ALL
|DIS_DEBUG_COMPAT
))
1691 if (f
->f3
.rs1
== 0 && f
->f3
.i
== 0 && f
->f3
.rs2
== f
->f3
.rd
) {
1693 flags
= FLG_P1(REG_NONE
)|FLG_P2(REG_NONE
);
1697 if (f
->f3
.rs1
== 0 && f
->f3
.i
== 0 && f
->f3
.rs2
!= f
->f3
.rd
) {
1699 flags
= FLG_P1(REG_NONE
);
1703 if ((dhx
->dhx_debug
& DIS_DEBUG_SYN_ALL
) == 0)
1706 if (f
->f3
.rs1
== f
->f3
.rd
&& f
->f3
.i
== 1 &&
1707 f
->f3a
.simm13
== 1) {
1709 flags
= FLG_P1(REG_NONE
)|FLG_P2(REG_NONE
)|FLG_NOIMM
;
1713 if (f
->f3
.rs1
== f
->f3
.rd
&& f
->f3
.i
== 1 &&
1714 f
->f3a
.simm13
!= 1) {
1716 flags
= FLG_P1(REG_NONE
);
1724 if ((dhx
->dhx_debug
& (DIS_DEBUG_SYN_ALL
|DIS_DEBUG_COMPAT
))
1729 * xnor -> not when you have:
1730 * xnor %rs1, 0x0 or %g0, %rd
1732 if ((f
->f3
.i
== 0 && f
->f3
.rs2
!= 0) ||
1733 (f
->f3
.i
== 1 && f
->f3a
.simm13
!= 0))
1738 if (f
->f3
.rs1
== f
->f3
.rd
)
1739 flags
= FLG_P1(REG_NONE
)|FLG_P2(REG_NONE
)|FLG_NOIMM
|
1742 flags
= FLG_P1(REG_INT
)|FLG_P2(REG_NONE
)|FLG_NOIMM
|
1750 if ((dhx
->dhx_debug
& DIS_DEBUG_SYN_ALL
) == 0)
1753 if (f
->f3
.rs1
== f
->f3
.rd
&& f
->f3
.i
== 1 &&
1754 f
->f3a
.simm13
== 1) {
1756 flags
= FLG_P1(REG_NONE
)|FLG_P2(REG_NONE
)|FLG_NOIMM
;
1760 if (f
->f3
.rs1
== f
->f3
.rd
&& f
->f3
.i
== 1 &&
1761 f
->f3a
.simm13
!= 1) {
1763 flags
= FLG_P1(REG_NONE
);
1774 if ((dhx
->dhx_debug
& (DIS_DEBUG_COMPAT
|DIS_DEBUG_SYN_ALL
))
1778 if (((dhx
->dhx_debug
& DIS_DEBUG_COMPAT
) != 0) &&
1779 ((dhp
->dh_flags
& (DIS_SPARC_V9
|DIS_SPARC_V9_SGI
)) == 0))
1783 flags
= FLG_P1(REG_NONE
);
1784 f
->f3
.rd
= f
->f3
.rs1
;
1790 if ((dhx
->dhx_debug
& (DIS_DEBUG_SYN_ALL
|DIS_DEBUG_COMPAT
))
1794 if (f
->f3
.rs1
== 0 && f
->f3
.rd
== 0 && f
->f3
.i
== 0) {
1796 flags
= FLG_P1(REG_NONE
)|FLG_P3(REG_NONE
);
1800 if (f
->f3
.rs2
== 0 && f
->f3
.rd
== 0 && f
->f3
.i
== 0) {
1802 flags
= FLG_P2(REG_NONE
)|FLG_P3(REG_NONE
);
1811 if ((dhx
->dhx_debug
& (DIS_DEBUG_SYN_ALL
|DIS_DEBUG_COMPAT
))
1815 if (f
->f3
.rd
== 0) {
1817 flags
= FLG_P3(REG_NONE
);
1821 if ((dhx
->dhx_debug
& DIS_DEBUG_COMPAT
) != 0)
1824 if (f
->f3
.rs1
== f
->f3
.rd
&& f
->f3
.i
== 1 &&
1825 f
->f3a
.simm13
== 1) {
1827 flags
= FLG_P1(REG_NONE
)|FLG_P2(REG_NONE
)|FLG_NOIMM
;
1831 if (f
->f3
.rs1
== f
->f3
.rd
&& f
->f3
.i
== 1 &&
1832 f
->f3a
.simm13
!= 1) {
1834 flags
= FLG_P1(REG_NONE
);
1843 return (prt_shift(dhp
, instr
, inp
));
1853 return (dis_fmt_rdwr(dhp
, instr
, inp
, idx
));
1857 /* NOTE: overlayed on v9 */
1858 if ((dhp
->dh_flags
& DIS_SPARC_V8
) != 0)
1859 return (fmt_cpop(dhp
, instr
, inp
));
1864 return (prt_jmpl(dhp
, instr
, inp
, idx
));
1868 prt_name(dhp
, name
, 1);
1869 prt_address(dhp
, instr
, 1);
1874 prt_name(dhp
, name
, 1);
1875 prt_address(dhp
, instr
, 0);
1880 /* save / restore */
1881 if ((dhx
->dhx_debug
& (DIS_DEBUG_SYN_ALL
|DIS_DEBUG_COMPAT
))
1885 if (f
->f3
.rs1
!= 0 || f
->f3
.rs2
!= 0 || f
->f3
.rd
!= 0)
1888 if (f
->f3
.i
!= 0 && ((dhx
->dhx_debug
& DIS_DEBUG_COMPAT
) != 0))
1891 prt_name(dhp
, name
, 0);
1895 if (FLG_P1_VAL(flags
) != REG_NONE
|| FLG_P2_VAL(flags
) != REG_NONE
||
1896 FLG_P3_VAL(flags
) != REG_NONE
)
1899 prt_name(dhp
, name
, (arg
!= 0));
1900 prt_aluargs(dhp
, instr
, flags
);
1907 fmt_regwin(dis_handle_t
*dhp
, uint32_t instr
, const inst_t
*inp
, int idx
)
1909 prt_name(dhp
, inp
->in_data
.in_def
.in_name
, 0);
1915 fmt_trap_ret(dis_handle_t
*dhp
, uint32_t instr
, const inst_t
*inp
, int idx
)
1917 ifmt_t
*f
= (ifmt_t
*)&instr
;
1918 prt_name(dhp
, inp
->in_data
.in_def
.in_name
, 1);
1920 if (f
->f3
.rd
== 0xf) {
1922 prt_address(dhp
, instr
, 1);
1930 fmt_movcc(dis_handle_t
*dhp
, uint32_t instr
, const inst_t
*inp
, int idx
)
1932 dis_handle_sparc_t
*dhx
= dhp
->dh_arch_private
;
1933 ifmt_t
*f
= (ifmt_t
*)&instr
;
1934 const char **regs
= NULL
;
1936 if ((dhx
->dhx_debug
& DIS_DEBUG_PRTFMT
) != 0) {
1937 prt_field("op", f
->f3c
.op
, 2);
1938 prt_field("op3", f
->f3c
.op3
, 6);
1939 prt_field("cond", f
->f3c
.cond
, 4);
1940 prt_field("cc2", f
->f3c
.cc2
, 1);
1941 prt_field("cc", f
->f3c
.cc
, 2);
1942 prt_field("i", f
->f3c
.i
, 1);
1945 prt_field("rs2", f
->f3
.rs2
, 5);
1947 prt_field("simm11", f
->f3c
.simm11
, 11);
1949 prt_field("rd", f
->f3
.rd
, 5);
1952 if (f
->f3c
.cc2
== 0) {
1956 if (regs
[f
->f3c
.cc
] == NULL
)
1960 prt_name(dhp
, inp
->in_data
.in_def
.in_name
, 1);
1962 bprintf(dhp
, "%s, ", regs
[f
->f3c
.cc
]);
1965 prt_imm(dhp
, sign_extend(f
->f3c
.simm11
, 11), IMM_SIGNED
);
1967 (void) strlcat(dhx
->dhx_buf
, reg_names
[f
->f3
.rs2
],
1970 bprintf(dhp
, ", %s", reg_names
[f
->f3
.rd
]);
1977 fmt_movr(dis_handle_t
*dhp
, uint32_t instr
, const inst_t
*inp
, int idx
)
1979 dis_handle_sparc_t
*dhx
= dhp
->dh_arch_private
;
1980 ifmt_t
*f
= (ifmt_t
*)&instr
;
1982 prt_name(dhp
, inp
->in_data
.in_def
.in_name
, 1);
1984 bprintf(dhp
, "%s, ", reg_names
[f
->f3d
.rs1
]);
1987 prt_imm(dhp
, sign_extend(f
->f3d
.simm10
, 10), IMM_SIGNED
);
1989 (void) strlcat(dhx
->dhx_buf
, reg_names
[f
->f3
.rs2
],
1992 bprintf(dhp
, ", %s", reg_names
[f
->f3
.rd
]);
1999 fmt_fpop1(dis_handle_t
*dhp
, uint32_t instr
, const inst_t
*inp
, int idx
)
2001 dis_handle_sparc_t
*dhx
= dhp
->dh_arch_private
;
2002 ifmt_t
*f
= (ifmt_t
*)&instr
;
2003 int flags
= inp
->in_data
.in_def
.in_flags
;
2007 if ((dhx
->dhx_debug
& DIS_DEBUG_PRTFMT
) != 0) {
2008 prt_field("op", f
->f3
.op
, 2);
2009 prt_field("op3", f
->f3
.op3
, 6);
2010 prt_field("opf", f
->fcmp
.opf
, 9);
2011 prt_field("rs1", f
->f3
.rs1
, 5);
2012 prt_field("rs2", f
->f3
.rs2
, 5);
2013 prt_field("rd", f
->f3
.rd
, 5);
2016 prt_name(dhp
, inp
->in_data
.in_def
.in_name
, 1);
2017 prt_aluargs(dhp
, instr
, flags
);
2023 fmt_fpop2(dis_handle_t
*dhp
, uint32_t instr
, const inst_t
*inp
, int idx
)
2025 static const char *condstr_icc
[16] = {
2026 "n", "e", "le", "l", "leu", "lu", "neg", "vs",
2027 "a", "nz", "g", "ge", "gu", "geu", "pos", "vc"
2030 static const char *condstr_fcc
[16] = {
2031 "n", "nz", "lg", "ul", "l", "ug", "g", "u",
2032 "a", "e", "ue", "ge", "uge", "le", "ule", "o"
2035 dis_handle_sparc_t
*dhx
= dhp
->dh_arch_private
;
2036 ifmt_t
*f
= (ifmt_t
*)&instr
;
2037 const char *ccstr
= "";
2040 int flags
= inp
->in_data
.in_def
.in_flags
;
2041 int is_cmp
= (idx
== 0x51 || idx
== 0x52 || idx
== 0x53 ||
2042 idx
== 0x55 || idx
== 0x56 || idx
== 0x57);
2043 int is_fmov
= (idx
& 0x3f);
2044 int is_v9
= ((dhp
->dh_flags
& (DIS_SPARC_V9
|DIS_SPARC_V9_SGI
)) != 0);
2045 int is_compat
= ((dhx
->dhx_debug
& DIS_DEBUG_COMPAT
) != 0);
2049 is_fmov
= (is_fmov
== 0x1 || is_fmov
== 0x2 || is_fmov
== 0x3);
2051 if ((dhx
->dhx_debug
& DIS_DEBUG_PRTFMT
) != 0) {
2052 prt_field("op", f
->f3
.op
, 2);
2053 prt_field("op3", f
->f3
.op3
, 6);
2054 prt_field("opf", f
->fcmp
.opf
, 9);
2056 switch (idx
& 0x3f) {
2063 prt_field("cc", f
->fcmp
.cc
, 2);
2064 prt_field("rs1", f
->f3
.rs1
, 5);
2065 prt_field("rs2", f
->f3
.rs2
, 5);
2071 prt_field("opf_low", f
->fmv
.opf
, 6);
2072 prt_field("cond", f
->fmv
.cond
, 4);
2073 prt_field("opf_cc", f
->fmv
.cc
, 3);
2074 prt_field("rs2", f
->fmv
.rs2
, 5);
2078 prt_field("rs1", f
->f3
.rs1
, 5);
2079 prt_field("rs2", f
->f3
.rs2
, 5);
2080 prt_field("rd", f
->f3
.rd
, 5);
2085 (void) strlcat(name
, inp
->in_data
.in_def
.in_name
, sizeof (name
));
2088 (void) strlcat(name
,
2089 (f
->fmv
.cc
< 4) ? condstr_fcc
[f
->fmv
.cond
]
2090 : condstr_icc
[f
->fmv
.cond
],
2094 prt_name(dhp
, name
, 1);
2097 ccstr
= fcc_names
[f
->fcmp
.cc
];
2100 ccstr
= (f
->fmv
.cc
< 4) ? fcc_names
[f
->fmv
.cc
& 0x3]
2101 : icc_names
[f
->fmv
.cc
& 0x3];
2106 p_cc
= (is_compat
== 0 || is_v9
!= 0 ||
2107 (is_cmp
!= 0 && f
->fcmp
.cc
!= 0) ||
2108 (is_fmov
!= 0 && f
->fmv
.cc
!= 0));
2111 bprintf(dhp
, "%s, ", ccstr
);
2113 prt_aluargs(dhp
, instr
, flags
);
2119 fmt_vis(dis_handle_t
*dhp
, uint32_t instr
, const inst_t
*inp
, int idx
)
2121 dis_handle_sparc_t
*dhx
= dhp
->dh_arch_private
;
2122 ifmt_t
*f
= (ifmt_t
*)&instr
;
2123 int flags
= inp
->in_data
.in_def
.in_flags
;
2125 if ((dhx
->dhx_debug
& DIS_DEBUG_PRTFMT
) != 0) {
2126 prt_field("op", f
->f3
.op
, 2);
2127 prt_field("op3", f
->f3
.op3
, 6);
2128 prt_field("opf", f
->fcmp
.opf
, 9);
2131 prt_field("mode", instr
& 02L, 2);
2133 prt_field("rs1", f
->f3
.rs1
, 5);
2134 prt_field("rs2", f
->f3
.rs2
, 5);
2135 prt_field("rd", f
->f3
.rd
, 5);
2139 prt_name(dhp
, inp
->in_data
.in_def
.in_name
, 1);
2143 bprintf(dhp
, "%d", instr
& 0x7L
);
2147 prt_aluargs(dhp
, instr
, flags
);
2154 fmt_fused(dis_handle_t
*dhp
, uint32_t instr
, const inst_t
*inp
, int idx
)
2156 ifmt_t
*f
= (ifmt_t
*)&instr
;
2157 int flags
= inp
->in_data
.in_def
.in_flags
;
2159 prt_name(dhp
, inp
->in_data
.in_def
.in_name
, 1);
2160 bprintf(dhp
, "%s, %s, %s, %s",
2161 get_regname(dhp
, FLG_P1_VAL(flags
), f
->fused
.rs1
),
2162 get_regname(dhp
, FLG_P1_VAL(flags
), f
->fused
.rs2
),
2163 get_regname(dhp
, FLG_P1_VAL(flags
), f
->fused
.rs3
),
2164 get_regname(dhp
, FLG_P1_VAL(flags
), f
->fused
.rd
));
2169 * put name into the output buffer
2170 * if add_space !=0, append a space after it
2173 prt_name(dis_handle_t
*dhp
, const char *name
, int add_space
)
2175 bprintf(dhp
, (add_space
== 0) ? "%s" : "%-9s ", name
);
2179 * For debugging, print out a field of the instruction
2180 * field is the name of the field
2181 * val is the value of the field
2182 * len is the length of the field (in bits)
2184 #if defined(DIS_STANDALONE)
2187 prt_field(const char *field
, uint32_t val
, int len
)
2194 prt_field(const char *field
, uint32_t val
, int len
)
2196 (void) fprintf(stderr
, "DISASM: %8s = 0x%-8x (", field
, val
);
2197 prt_binary(val
, len
);
2198 (void) fprintf(stderr
, ")\n");
2200 #endif /* DIS_STANDALONE */
2203 * sign extend a val (that is 'bits' bits in length) to a 32-bit signed
2207 sign_extend(int32_t val
, uint32_t bits
)
2212 mask
= 1L << (bits
- 1); /* 2**(bits - 1) */
2213 return (-(val
& mask
) + (val
& ~mask
));
2217 * print out an immediate (i.e. constant) value
2219 * format indicates if it is:
2221 * IMM_SIGNED A signed value (prepend +/- to the value)
2222 * IMM_ADDR Part of an address expression (prepend +/- but with a space
2223 * between the sign and the value for things like [%i1 + 0x55]
2226 prt_imm(dis_handle_t
*dhp
, uint32_t val
, int format
)
2228 const char *fmtstr
= NULL
;
2229 int32_t sv
= (int32_t)val
;
2230 int octal
= dhp
->dh_flags
& DIS_OCTAL
;
2236 fmtstr
= (octal
!= 0) ? "- 0%lo" : "- 0x%lx";
2238 fmtstr
= (octal
!= 0) ? "+ 0%lo" : "+ 0x%lx";
2245 fmtstr
= (octal
!= 0) ? "-0%lo" : "-0x%lx";
2251 fmtstr
= (octal
!= 0) ? "0%lo" : "0x%lx";
2254 bprintf(dhp
, fmtstr
, sv
);
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
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
2268 get_regname(dis_handle_t
*dhp
, int regset
, uint32_t idx
)
2270 dis_handle_sparc_t
*dhx
= dhp
->dh_arch_private
;
2271 const char *regname
= NULL
;
2275 regname
= reg_names
[idx
];
2279 regname
= freg_names
[idx
];
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
];
2287 regname
= compat_fdreg_names
[idx
];
2292 if ((dhx
->dhx_debug
& DIS_DEBUG_COMPAT
) == 0)
2293 regname
= fqreg_names
[idx
];
2295 regname
= freg_names
[idx
];
2300 regname
= cpreg_names
[idx
];
2304 regname
= icc_names
[idx
];
2308 regname
= fcc_names
[idx
];
2332 * output the asi value from the instruction
2334 * TODO: investigate if this should perhaps have a mask -- are undefined ASI
2335 * values for an instruction still disassembled??
2338 prt_asi(dis_handle_t
*dhp
, uint32_t instr
)
2340 ifmt_t
*f
= (ifmt_t
*)&instr
;
2341 int octal
= ((dhp
->dh_flags
& DIS_OCTAL
) != 0);
2344 bprintf(dhp
, "%%asi");
2346 bprintf(dhp
, (octal
!= 0) ? "0%03o" : "0x%02x", f
->f3
.asi
);
2351 * put an address expression into the output buffer
2353 * instr is the instruction to use
2354 * if nobrackets != 0, [] are not added around the instruction
2356 * Currently this option is set when printing out the address portion
2357 * of a jmpl instruction, but otherwise 0 for load/stores
2359 * If no debug flags are set, the full expression is output, even when
2360 * %g0 or 0x0 appears in the address
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,
2368 prt_address(dis_handle_t
*dhp
, uint32_t instr
, int nobrackets
)
2370 dis_handle_sparc_t
*dhx
= dhp
->dh_arch_private
;
2371 ifmt_t
*f
= (ifmt_t
*)&instr
;
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);
2377 if (f
->f3a
.i
== 0) {
2378 p1
|= ((f
->f3a
.rs1
!= 0) || f
->f3
.rs2
== 0);
2379 p2
|= (f
->f3
.rs2
!= 0);
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) ? "]" : "");
2390 simm13
= sign_extend(f
->f3a
.simm13
, 13);
2391 sign
= (simm13
< 0) ? "-" : "+";
2393 p1
|= (f
->f3a
.rs1
!= 0);
2394 p2
|= (p1
== 0 || simm13
!= 0);
2396 if (p1
== 0 && simm13
== 0)
2399 if (p1
== 0 && simm13
>= 0)
2404 (octal
!= 0) ? "%s%s%s%s%s0%lo%s" :
2405 "%s%s%s%s%s0x%lx%s",
2406 (nobrackets
== 0) ? "[" : "",
2407 (p1
!= 0) ? reg_names
[f
->f3a
.rs1
] : "",
2408 (p1
!= 0) ? " " : "",
2410 (p1
!= 0) ? " " : "",
2411 (simm13
< 0) ? -(simm13
) : simm13
,
2412 (nobrackets
== 0) ? "]" : "");
2414 bprintf(dhp
, "%s%s%s",
2415 (nobrackets
== 0) ? "[" : "",
2416 reg_names
[f
->f3a
.rs1
],
2417 (nobrackets
== 0) ? "]" : "");
2422 * print out the arguments to an alu operation (add, sub, etc.)
2423 * conatined in 'instr'
2425 * alu instructions have the following format:
2426 * %rs1, %rs2, %rd (i == 0)
2427 * %rs1, 0xnnn, %rd (i == 1)
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
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
2440 prt_aluargs(dis_handle_t
*dhp
, uint32_t instr
, uint32_t flags
)
2442 dis_handle_sparc_t
*dhx
= dhp
->dh_arch_private
;
2443 ifmt_t
*f
= (ifmt_t
*)&instr
;
2444 const char *r1
, *r2
, *r3
;
2446 unsigned int opf
= 0;
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
);
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
);
2456 if (r1
== NULL
|| r1
[0] == '\0')
2459 if (f
->f3a
.i
== 0 && (r2
== NULL
|| r2
[0] == '\0'))
2462 if (r3
== NULL
|| r3
[0] == '\0')
2465 if ((f
->fcmp
.op
== 2) && (f
->fcmp
.op3
== 0x36) && (f
->fcmp
.cc
!= 0))
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
);
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
);
2481 if (f
->f3
.i
== 0 || ((flags
& FLG_NOIMM
) != 0))
2482 (void) strlcat(dhx
->dhx_buf
, r2
, dhx
->dhx_buflen
);
2484 prt_imm(dhp
, sign_extend(f
->f3a
.simm13
, 13),
2488 (void) strlcat(dhx
->dhx_buf
, ", ", dhx
->dhx_buflen
);
2492 (void) strlcat(dhx
->dhx_buf
, r3
, dhx
->dhx_buflen
);
2496 get_asi_name(uint8_t asi
)
2506 return ("ASI_AIUP");
2509 return ("ASI_AIUS");
2512 return ("ASI_REAL");
2515 return ("ASI_REAL_IO");
2518 return ("ASI_BLK_AIUP");
2521 return ("ASI_BLK_AIUS");
2524 return ("ASI_AIUPL");
2527 return ("ASI_AIUSL");
2530 return ("ASI_REAL_L");
2533 return ("ASI_REAL_IO_L");
2536 return ("ASI_BLK_AIUPL");
2539 return ("ASI_BLK_AIUS_L");
2542 return ("ASI_SCRATCHPAD");
2545 return ("ASI_MMU_CONTEXTID");
2548 return ("ASI_TWINX_AIUP");
2551 return ("ASI_TWINX_AIUS");
2554 return ("ASI_QUEUE");
2557 return ("ASI_TWINX_R");
2560 return ("ASI_TWINX_N");
2563 return ("ASI_LDTX_AIUPL");
2566 return ("ASI_TWINX_AIUS_L");
2569 return ("ASI_TWINX_REAL_L");
2572 return ("ASI_TWINX_NL");
2575 return ("ASI_AIPP");
2578 return ("ASI_AIPS");
2581 return ("ASI_AIPN");
2584 return ("ASI_AIPP_L");
2587 return ("ASI_AIPS_L");
2590 return ("ASI_AIPN_L");
2593 return ("ASI_CMT_SHARED");
2596 return ("ASI_HYP_SCRATCHPAD");
2599 return ("ASI_IMMU");
2602 return ("ASI_MMU_REAL");
2608 return ("ASI_ITLB_DATA_ACCESS_REG");
2611 return ("ASI_ITLB_TAG_READ_REG");
2614 return ("ASI_IMMU_DEMAP");
2617 return ("ASI_DMMU / ASI_UMMU");
2620 return ("ASI_DTLB_DATA_IN_REG");
2623 return ("ASI_DTLB_DATA_ACCESS_REG");
2626 return ("ASI_DTLB_TAG_READ_REG");
2629 return ("ASI_DMMU_DEMAP");
2632 return ("ASI_CMT_PER_STRAND / ASI_CMT_PER_CORE");
2653 return ("ASI_PNFL");
2656 return ("ASI_SNFL");
2659 return ("ASI_PST8_P");
2662 return ("ASI_PST8_S");
2665 return ("ASI_PST16_P");
2668 return ("ASI_PST16_S");
2671 return ("ASI_PST32_P");
2674 return ("ASI_PST32_S");
2677 return ("ASI_PST8_PL");
2680 return ("ASI_PST8_SL");
2683 return ("ASI_PST16_PL");
2686 return ("ASI_PST16_SL");
2689 return ("ASI_PST32_PL");
2692 return ("ASI_PST32_SL");
2695 return ("ASI_FL8_P");
2698 return ("ASI_FL8_S");
2701 return ("ASI_FL16_P");
2704 return ("ASI_FL16_S");
2707 return ("ASI_FL8_PL");
2710 return ("ASI_FL8_SL");
2713 return ("ASI_FL16_PL");
2716 return ("ASI_FL16_SL");
2719 return ("ASI_BLK_COMMIT_P");
2722 return ("ASI_BLK_SOMMIT_S");
2725 return ("ASI_TWINX_P");
2728 return ("ASI_TWINX_S");
2731 return ("ASI_TWINX_PL");
2734 return ("ASI_TWINX_SL");
2737 return ("ASI_BLK_P");
2740 return ("ASI_BLK_S");
2743 return ("ASI_BLK_PL");
2746 return ("ASI_BLK_SL");
2754 * just a handy function that takes care of managing the buffer length
2762 bprintf(dis_handle_t
*dhp
, const char *fmt
, ...)
2764 dis_handle_sparc_t
*dhx
= dhp
->dh_arch_private
;
2768 curlen
= strlen(dhx
->dhx_buf
);
2771 (void) dis_vsnprintf(dhx
->dhx_buf
+ curlen
, dhx
->dhx_buflen
-