aboutsummaryrefslogtreecommitdiff
path: root/cddl/contrib/opensolaris/lib/libdtrace
diff options
context:
space:
mode:
Diffstat (limited to 'cddl/contrib/opensolaris/lib/libdtrace')
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c43
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_cg.c45
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c324
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_errtags.h2
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h1
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c4
6 files changed, 10 insertions, 409 deletions
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c
index ef10e0bc7e94..1216a389e239 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c
@@ -1058,46 +1058,6 @@ dt_action_printm(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
}
static void
-dt_action_printt(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
-{
- dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
-
- dt_node_t *size = dnp->dn_args;
- dt_node_t *addr = dnp->dn_args->dn_list;
-
- char n[DT_TYPE_NAMELEN];
-
- if (dt_node_is_posconst(size) == 0) {
- dnerror(size, D_PRINTT_SIZE, "printt( ) argument #1 must "
- "be a non-zero positive integral constant expression\n");
- }
-
- if (addr == NULL || addr->dn_kind != DT_NODE_FUNC ||
- addr->dn_ident != dt_idhash_lookup(dtp->dt_globals, "typeref")) {
- dnerror(addr, D_PRINTT_ADDR,
- "printt( ) argument #2 is incompatible with "
- "prototype:\n\tprototype: typeref()\n"
- "\t argument: %s\n",
- dt_node_type_name(addr, n, sizeof (n)));
- }
-
- dt_cg(yypcb, addr);
- ap->dtad_difo = dt_as(yypcb);
- ap->dtad_kind = DTRACEACT_PRINTT;
-
- ap->dtad_difo->dtdo_rtype.dtdt_flags |= DIF_TF_BYREF;
-
- /*
- * Allow additional buffer space for the data size, type size,
- * type string length and a stab in the dark (32 bytes) for the
- * type string. The type string is part of the typeref() that
- * this action references.
- */
- ap->dtad_difo->dtdo_rtype.dtdt_size = size->dn_value + 3 * sizeof(uintptr_t) + 32;
-
-}
-
-static void
dt_action_commit(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
{
dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
@@ -1169,9 +1129,6 @@ dt_compile_fun(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
case DT_ACT_PRINTM:
dt_action_printm(dtp, dnp->dn_expr, sdp);
break;
- case DT_ACT_PRINTT:
- dt_action_printt(dtp, dnp->dn_expr, sdp);
- break;
case DT_ACT_RAISE:
dt_action_raise(dtp, dnp->dn_expr, sdp);
break;
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cg.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cg.c
index e748ff2b3ade..e4580a8ab340 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cg.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cg.c
@@ -1353,40 +1353,6 @@ dt_cg_inline(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
}
}
-static void
-dt_cg_func_typeref(dtrace_hdl_t *dtp, dt_node_t *dnp)
-{
- dtrace_typeinfo_t dtt;
- dt_node_t *addr = dnp->dn_args;
- dt_node_t *nelm = addr->dn_list;
- dt_node_t *strp = nelm->dn_list;
- dt_node_t *typs = strp->dn_list;
- char buf[DT_TYPE_NAMELEN];
- char *p;
-
- ctf_type_name(addr->dn_ctfp, addr->dn_type, buf, sizeof (buf));
-
- /*
- * XXX Hack alert! XXX
- * The prototype has two dummy args that we munge to represent
- * the type string and the type size.
- *
- * Yes, I hear your grumble, but it works for now. We'll come
- * up with a more elegant implementation later. :-)
- */
- free(strp->dn_string);
-
- if ((p = strchr(buf, '*')) != NULL)
- *p = '\0';
-
- strp->dn_string = strdup(buf);
-
- if (dtrace_lookup_by_type(dtp, DTRACE_OBJ_EVERY, buf, &dtt) < 0)
- return;
-
- typs->dn_value = ctf_type_size(dtt.dtt_ctfp, dtt.dtt_type);
-}
-
typedef struct dt_xlmemb {
dt_ident_t *dtxl_idp; /* translated ident */
dt_irlist_t *dtxl_dlp; /* instruction list */
@@ -2002,8 +1968,6 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
switch (dnp->dn_kind) {
case DT_NODE_FUNC: {
- dtrace_hdl_t *dtp = yypcb->pcb_hdl;
-
if ((idp = dnp->dn_ident)->di_kind != DT_IDENT_FUNC) {
dnerror(dnp, D_CG_EXPR, "%s %s( ) may not be "
"called from a D expression (D program "
@@ -2011,15 +1975,6 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
dt_idkind_name(idp->di_kind), idp->di_name);
}
- switch (idp->di_id) {
- case DIF_SUBR_TYPEREF:
- dt_cg_func_typeref(dtp, dnp);
- break;
-
- default:
- break;
- }
-
dt_cg_arglist(dnp->dn_ident, dnp->dn_args, dlp, drp);
dnp->dn_reg = dt_regset_alloc(drp);
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c
index 04c022b7ad00..de574a330268 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c
@@ -1537,314 +1537,6 @@ dt_print_umod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr)
return (err);
}
-int
-dt_print_memory(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr)
-{
- int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET);
- size_t nbytes = *((uintptr_t *) addr);
-
- return (dt_print_bytes(dtp, fp, addr + sizeof(uintptr_t),
- nbytes, 50, quiet, 1));
-}
-
-typedef struct dt_type_cbdata {
- dtrace_hdl_t *dtp;
- dtrace_typeinfo_t dtt;
- caddr_t addr;
- caddr_t addrend;
- const char *name;
- int f_type;
- int indent;
- int type_width;
- int name_width;
- FILE *fp;
-} dt_type_cbdata_t;
-
-static int dt_print_type_data(dt_type_cbdata_t *, ctf_id_t);
-
-static int
-dt_print_type_member(const char *name, ctf_id_t type, ulong_t off, void *arg)
-{
- dt_type_cbdata_t cbdata;
- dt_type_cbdata_t *cbdatap = arg;
- ssize_t ssz;
-
- if ((ssz = ctf_type_size(cbdatap->dtt.dtt_ctfp, type)) <= 0)
- return (0);
-
- off /= 8;
-
- cbdata = *cbdatap;
- cbdata.name = name;
- cbdata.addr += off;
- cbdata.addrend = cbdata.addr + ssz;
-
- return (dt_print_type_data(&cbdata, type));
-}
-
-static int
-dt_print_type_width(const char *name, ctf_id_t type, ulong_t off, void *arg)
-{
- char buf[DT_TYPE_NAMELEN];
- char *p;
- dt_type_cbdata_t *cbdatap = arg;
- size_t sz = strlen(name);
-
- ctf_type_name(cbdatap->dtt.dtt_ctfp, type, buf, sizeof (buf));
-
- if ((p = strchr(buf, '[')) != NULL)
- p[-1] = '\0';
- else
- p = "";
-
- sz += strlen(p);
-
- if (sz > cbdatap->name_width)
- cbdatap->name_width = sz;
-
- sz = strlen(buf);
-
- if (sz > cbdatap->type_width)
- cbdatap->type_width = sz;
-
- return (0);
-}
-
-static int
-dt_print_type_data(dt_type_cbdata_t *cbdatap, ctf_id_t type)
-{
- caddr_t addr = cbdatap->addr;
- caddr_t addrend = cbdatap->addrend;
- char buf[DT_TYPE_NAMELEN];
- char *p;
- int cnt = 0;
- uint_t kind = ctf_type_kind(cbdatap->dtt.dtt_ctfp, type);
- ssize_t ssz = ctf_type_size(cbdatap->dtt.dtt_ctfp, type);
-
- ctf_type_name(cbdatap->dtt.dtt_ctfp, type, buf, sizeof (buf));
-
- if ((p = strchr(buf, '[')) != NULL)
- p[-1] = '\0';
- else
- p = "";
-
- if (cbdatap->f_type) {
- int type_width = roundup(cbdatap->type_width + 1, 4);
- int name_width = roundup(cbdatap->name_width + 1, 4);
-
- name_width -= strlen(cbdatap->name);
-
- dt_printf(cbdatap->dtp, cbdatap->fp, "%*s%-*s%s%-*s = ",cbdatap->indent * 4,"",type_width,buf,cbdatap->name,name_width,p);
- }
-
- while (addr < addrend) {
- dt_type_cbdata_t cbdata;
- ctf_arinfo_t arinfo;
- ctf_encoding_t cte;
- uintptr_t *up;
- void *vp = addr;
- cbdata = *cbdatap;
- cbdata.name = "";
- cbdata.addr = addr;
- cbdata.addrend = addr + ssz;
- cbdata.f_type = 0;
- cbdata.indent++;
- cbdata.type_width = 0;
- cbdata.name_width = 0;
-
- if (cnt > 0)
- dt_printf(cbdatap->dtp, cbdatap->fp, "%*s", cbdatap->indent * 4,"");
-
- switch (kind) {
- case CTF_K_INTEGER:
- if (ctf_type_encoding(cbdatap->dtt.dtt_ctfp, type, &cte) != 0)
- return (-1);
- if ((cte.cte_format & CTF_INT_SIGNED) != 0)
- switch (cte.cte_bits) {
- case 8:
- if (isprint(*((char *) vp)))
- dt_printf(cbdatap->dtp, cbdatap->fp, "'%c', ", *((char *) vp));
- dt_printf(cbdatap->dtp, cbdatap->fp, "%d (0x%x);\n", *((char *) vp), *((char *) vp));
- break;
- case 16:
- dt_printf(cbdatap->dtp, cbdatap->fp, "%hd (0x%hx);\n", *((short *) vp), *((u_short *) vp));
- break;
- case 32:
- dt_printf(cbdatap->dtp, cbdatap->fp, "%d (0x%x);\n", *((int *) vp), *((u_int *) vp));
- break;
- case 64:
- dt_printf(cbdatap->dtp, cbdatap->fp, "%jd (0x%jx);\n", *((long long *) vp), *((unsigned long long *) vp));
- break;
- default:
- dt_printf(cbdatap->dtp, cbdatap->fp, "CTF_K_INTEGER: format %x offset %u bits %u\n",cte.cte_format,cte.cte_offset,cte.cte_bits);
- break;
- }
- else
- switch (cte.cte_bits) {
- case 8:
- dt_printf(cbdatap->dtp, cbdatap->fp, "%u (0x%x);\n", *((uint8_t *) vp) & 0xff, *((uint8_t *) vp) & 0xff);
- break;
- case 16:
- dt_printf(cbdatap->dtp, cbdatap->fp, "%hu (0x%hx);\n", *((u_short *) vp), *((u_short *) vp));
- break;
- case 32:
- dt_printf(cbdatap->dtp, cbdatap->fp, "%u (0x%x);\n", *((u_int *) vp), *((u_int *) vp));
- break;
- case 64:
- dt_printf(cbdatap->dtp, cbdatap->fp, "%ju (0x%jx);\n", *((unsigned long long *) vp), *((unsigned long long *) vp));
- break;
- default:
- dt_printf(cbdatap->dtp, cbdatap->fp, "CTF_K_INTEGER: format %x offset %u bits %u\n",cte.cte_format,cte.cte_offset,cte.cte_bits);
- break;
- }
- break;
- case CTF_K_FLOAT:
- dt_printf(cbdatap->dtp, cbdatap->fp, "CTF_K_FLOAT: format %x offset %u bits %u\n",cte.cte_format,cte.cte_offset,cte.cte_bits);
- break;
- case CTF_K_POINTER:
- dt_printf(cbdatap->dtp, cbdatap->fp, "%p;\n", *((void **) addr));
- break;
- case CTF_K_ARRAY:
- if (ctf_array_info(cbdatap->dtt.dtt_ctfp, type, &arinfo) != 0)
- return (-1);
- dt_printf(cbdatap->dtp, cbdatap->fp, "{\n%*s",cbdata.indent * 4,"");
- dt_print_type_data(&cbdata, arinfo.ctr_contents);
- dt_printf(cbdatap->dtp, cbdatap->fp, "%*s};\n",cbdatap->indent * 4,"");
- break;
- case CTF_K_FUNCTION:
- dt_printf(cbdatap->dtp, cbdatap->fp, "CTF_K_FUNCTION:\n");
- break;
- case CTF_K_STRUCT:
- cbdata.f_type = 1;
- if (ctf_member_iter(cbdatap->dtt.dtt_ctfp, type,
- dt_print_type_width, &cbdata) != 0)
- return (-1);
- dt_printf(cbdatap->dtp, cbdatap->fp, "{\n");
- if (ctf_member_iter(cbdatap->dtt.dtt_ctfp, type,
- dt_print_type_member, &cbdata) != 0)
- return (-1);
- dt_printf(cbdatap->dtp, cbdatap->fp, "%*s};\n",cbdatap->indent * 4,"");
- break;
- case CTF_K_UNION:
- cbdata.f_type = 1;
- if (ctf_member_iter(cbdatap->dtt.dtt_ctfp, type,
- dt_print_type_width, &cbdata) != 0)
- return (-1);
- dt_printf(cbdatap->dtp, cbdatap->fp, "{\n");
- if (ctf_member_iter(cbdatap->dtt.dtt_ctfp, type,
- dt_print_type_member, &cbdata) != 0)
- return (-1);
- dt_printf(cbdatap->dtp, cbdatap->fp, "%*s};\n",cbdatap->indent * 4,"");
- break;
- case CTF_K_ENUM:
- dt_printf(cbdatap->dtp, cbdatap->fp, "%s;\n", ctf_enum_name(cbdatap->dtt.dtt_ctfp, type, *((int *) vp)));
- break;
- case CTF_K_TYPEDEF:
- dt_print_type_data(&cbdata, ctf_type_reference(cbdatap->dtt.dtt_ctfp,type));
- break;
- case CTF_K_VOLATILE:
- if (cbdatap->f_type)
- dt_printf(cbdatap->dtp, cbdatap->fp, "volatile ");
- dt_print_type_data(&cbdata, ctf_type_reference(cbdatap->dtt.dtt_ctfp,type));
- break;
- case CTF_K_CONST:
- if (cbdatap->f_type)
- dt_printf(cbdatap->dtp, cbdatap->fp, "const ");
- dt_print_type_data(&cbdata, ctf_type_reference(cbdatap->dtt.dtt_ctfp,type));
- break;
- case CTF_K_RESTRICT:
- if (cbdatap->f_type)
- dt_printf(cbdatap->dtp, cbdatap->fp, "restrict ");
- dt_print_type_data(&cbdata, ctf_type_reference(cbdatap->dtt.dtt_ctfp,type));
- break;
- default:
- break;
- }
-
- addr += ssz;
- cnt++;
- }
-
- return (0);
-}
-
-static int
-dt_print_type(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr)
-{
- caddr_t addrend;
- char *p;
- dtrace_typeinfo_t dtt;
- dt_type_cbdata_t cbdata;
- int num = 0;
- int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET);
- ssize_t ssz;
-
- if (!quiet)
- dt_printf(dtp, fp, "\n");
-
- /* Get the total number of bytes of data buffered. */
- size_t nbytes = *((uintptr_t *) addr);
- addr += sizeof(uintptr_t);
-
- /*
- * Get the size of the type so that we can check that it matches
- * the CTF data we look up and so that we can figure out how many
- * type elements are buffered.
- */
- size_t typs = *((uintptr_t *) addr);
- addr += sizeof(uintptr_t);
-
- /*
- * Point to the type string in the buffer. Get it's string
- * length and round it up to become the offset to the start
- * of the buffered type data which we would like to be aligned
- * for easy access.
- */
- char *strp = (char *) addr;
- int offset = roundup(strlen(strp) + 1, sizeof(uintptr_t));
-
- /*
- * The type string might have a format such as 'int [20]'.
- * Check if there is an array dimension present.
- */
- if ((p = strchr(strp, '[')) != NULL) {
- /* Strip off the array dimension. */
- *p++ = '\0';
-
- for (; *p != '\0' && *p != ']'; p++)
- num = num * 10 + *p - '0';
- } else
- /* No array dimension, so default. */
- num = 1;
-
- /* Lookup the CTF type from the type string. */
- if (dtrace_lookup_by_type(dtp, DTRACE_OBJ_EVERY, strp, &dtt) < 0)
- return (-1);
-
- /* Offset the buffer address to the start of the data... */
- addr += offset;
-
- ssz = ctf_type_size(dtt.dtt_ctfp, dtt.dtt_type);
-
- if (typs != ssz) {
- printf("Expected type size from buffer (%lu) to match type size looked up now (%ld)\n", (u_long) typs, (long) ssz);
- return (-1);
- }
-
- cbdata.dtp = dtp;
- cbdata.dtt = dtt;
- cbdata.name = "";
- cbdata.addr = addr;
- cbdata.addrend = addr + nbytes;
- cbdata.indent = 1;
- cbdata.f_type = 1;
- cbdata.type_width = 0;
- cbdata.name_width = 0;
- cbdata.fp = fp;
-
- return (dt_print_type_data(&cbdata, dtt.dtt_type));
-}
-
static int
dt_print_sym(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr)
{
@@ -1904,6 +1596,16 @@ dt_print_mod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr)
return (0);
}
+static int
+dt_print_memory(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr)
+{
+ int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET);
+ size_t nbytes = *((uintptr_t *) addr);
+
+ return (dt_print_bytes(dtp, fp, addr + sizeof(uintptr_t),
+ nbytes, 50, quiet, 1));
+}
+
typedef struct dt_normal {
dtrace_aggvarid_t dtnd_id;
uint64_t dtnd_normal;
@@ -2644,12 +2346,6 @@ dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, int cpu,
goto nextrec;
}
- if (act == DTRACEACT_PRINTT) {
- if (dt_print_type(dtp, fp, addr) < 0)
- return (-1);
- goto nextrec;
- }
-
if (DTRACEACT_ISPRINTFLIKE(act)) {
void *fmtdata;
int (*func)(dtrace_hdl_t *, FILE *, void *,
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_errtags.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_errtags.h
index 6bc392ff65fa..d95de2dfa992 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_errtags.h
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_errtags.h
@@ -265,8 +265,6 @@ typedef enum {
D_NOREG, /* no available internal registers */
D_PRINTM_ADDR, /* printm() memref bad type */
D_PRINTM_SIZE, /* printm() size bad type */
- D_PRINTT_ADDR, /* printt() typeref bad type */
- D_PRINTT_SIZE /* printt() size bad type */
} dt_errtag_t;
extern const char *dt_errtag(dt_errtag_t);
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h
index e71e9d71aeff..f2c60a2b07d4 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h
@@ -488,7 +488,6 @@ struct dtrace_hdl {
#define DT_ACT_SETOPT DT_ACT(28) /* setopt() action */
#define DT_ACT_PRINT DT_ACT(29) /* print() action */
#define DT_ACT_PRINTM DT_ACT(30) /* printm() action */
-#define DT_ACT_PRINTT DT_ACT(31) /* printt() action */
/*
* Sentinel to tell freopen() to restore the saved stdout. This must not
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c
index a56b98681d3b..77d8386bc80f 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c
@@ -392,8 +392,6 @@ static const dt_ident_t _dtrace_globals[] = {
&dt_idops_func, "void(@, ...)" },
{ "printm", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINTM, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "void(size_t, uintptr_t *)" },
-{ "printt", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINTT, DT_ATTR_STABCMN, DT_VERS_1_0,
- &dt_idops_func, "void(size_t, uintptr_t *)" },
{ "probefunc", DT_IDENT_SCALAR, 0, DIF_VAR_PROBEFUNC,
DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" },
{ "probemod", DT_IDENT_SCALAR, 0, DIF_VAR_PROBEMOD,
@@ -505,8 +503,6 @@ static const dt_ident_t _dtrace_globals[] = {
&dt_idops_func, "void(@, size_t, ...)" },
{ "trunc", DT_IDENT_ACTFUNC, 0, DT_ACT_TRUNC, DT_ATTR_STABCMN,
DT_VERS_1_0, &dt_idops_func, "void(...)" },
-{ "typeref", DT_IDENT_FUNC, 0, DIF_SUBR_TYPEREF, DT_ATTR_STABCMN, DT_VERS_1_1,
- &dt_idops_func, "uintptr_t *(void *, size_t, string, size_t)" },
{ "uaddr", DT_IDENT_ACTFUNC, 0, DT_ACT_UADDR, DT_ATTR_STABCMN,
DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
{ "ucaller", DT_IDENT_SCALAR, 0, DIF_VAR_UCALLER, DT_ATTR_STABCMN,