aboutsummaryrefslogtreecommitdiffstats
path: root/lib/erl_interface/src/misc/show_msg.c
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/erl_interface/src/misc/show_msg.c
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/erl_interface/src/misc/show_msg.c')
-rw-r--r--lib/erl_interface/src/misc/show_msg.c584
1 files changed, 584 insertions, 0 deletions
diff --git a/lib/erl_interface/src/misc/show_msg.c b/lib/erl_interface/src/misc/show_msg.c
new file mode 100644
index 0000000000..25865d6f8e
--- /dev/null
+++ b/lib/erl_interface/src/misc/show_msg.c
@@ -0,0 +1,584 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ *
+
+ */
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <sys/types.h>
+
+#include "eidef.h"
+
+#ifndef __WIN32__
+# ifdef TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+# else
+# ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+# endif
+#endif
+
+#include "eiext.h"
+#include "putget.h"
+#include "ei_printterm.h"
+#include "ei_internal.h"
+#include "show_msg.h"
+
+#ifndef EISHOWBUF
+#define EISHOWBUF 512
+#endif
+
+static void show_term(const char *termbuf, int *index, FILE *stream);
+static void show_pid(FILE *stream, const erlang_pid *pid);
+static void show_trace(FILE *stream, const erlang_trace *t);
+static void show_msg(FILE *stream, int direction, const erlang_msg *msg,
+ const char *buf);
+static void ei_efprint(FILE *stream, const char *termbuf);
+static int ei_decode_skip_bignum(const char *buf, int *index, void *p);
+static int printable_list_p(const uint8 *buf, int buflen);
+
+
+/***************************************************************************
+ *
+ * Write trace information to stderr
+ *
+ ***************************************************************************/
+
+void ei_trace_printf(const char *name, int level, const char *format,...)
+{
+ time_t now;
+ char *timestr;
+ char buf[2048];
+ int len;
+ va_list args;
+
+ va_start(args, format);
+
+ time(&now);
+ timestr = (char *)ctime(&now);
+ sprintf(buf, "%s: %.*s: ", name, (int) strlen(timestr)-1, timestr);
+ len = strlen(buf);
+ vsprintf(buf + len, format, args);
+ fprintf(stderr,"%s\r\n",buf);
+ va_end(args);
+}
+
+
+/***************************************************************************
+ *
+ * Debug printing of incoming and outgoing messages
+ *
+ ***************************************************************************/
+
+/*
+ * FIXME maybe this function should be rewritten to use ei_printterm instead
+ * (or the other way around)
+ */
+
+/*
+ * the new TT stuff has been added, but when these messages are shown
+ * they will look just like the non-tt ones for now.
+ */
+
+/*
+ * this should be long enough for longest atoms (256) but short enough for
+ * fprintf to handle all at once (a few kb probably).
+ */
+
+
+void ei_show_recmsg(FILE *stream, erlang_msg *msg, char *buf)
+{
+ show_msg(stream, 0, msg, buf);
+}
+
+
+/* decode the buffer again before showing it */
+int ei_show_sendmsg(FILE *stream, const char *header, const char *msgbuf)
+{
+ erlang_msg msg;
+ const char *mbuf = NULL;
+ int index = 0;
+ int arity = 0;
+ int version = 0;
+
+ /* skip five bytes */
+ index = 5;
+ ei_decode_version(header,&index,&version);
+ ei_decode_tuple_header(header,&index,&arity);
+ ei_decode_long(header,&index,&msg.msgtype);
+
+ switch (msg.msgtype) {
+ case ERL_SEND:
+ if (ei_decode_atom(header,&index,msg.cookie)
+ || ei_decode_pid(header,&index,&msg.to)) return -1;
+ mbuf = msgbuf;
+ break;
+
+ case ERL_SEND_TT:
+ if (ei_decode_atom(header,&index,msg.cookie)
+ || ei_decode_pid(header,&index,&msg.to)
+ || ei_decode_trace(header,&index,&msg.token)) return -1;
+ mbuf = msgbuf;
+ break;
+
+ case ERL_REG_SEND:
+ if (ei_decode_pid(header,&index,&msg.from)
+ || ei_decode_atom(header,&index,msg.cookie)
+ || ei_decode_atom(header,&index,msg.toname)) return -1;
+ mbuf = msgbuf;
+ break;
+
+ case ERL_REG_SEND_TT:
+ if (ei_decode_pid(header,&index,&msg.from)
+ || ei_decode_atom(header,&index,msg.cookie)
+ || ei_decode_atom(header,&index,msg.toname)
+ || ei_decode_trace(header,&index,&msg.token)) return -1;
+ mbuf = msgbuf;
+ break;
+
+ case ERL_EXIT:
+ case ERL_EXIT2:
+ if (ei_decode_pid(header,&index,&msg.from)
+ || ei_decode_pid(header,&index,&msg.to)) return -1;
+ mbuf = header+index;
+
+ case ERL_EXIT_TT:
+ case ERL_EXIT2_TT:
+ if (ei_decode_pid(header,&index,&msg.from)
+ || ei_decode_pid(header,&index,&msg.to)
+ || ei_decode_trace(header,&index,&msg.token)) return -1;
+ mbuf = header+index;
+ break;
+
+ case ERL_LINK:
+ case ERL_UNLINK:
+ case ERL_GROUP_LEADER:
+ if (ei_decode_pid(header,&index,&msg.from)
+ || ei_decode_pid(header,&index,&msg.to)) return -1;
+ mbuf = header;
+ break;
+
+ case ERL_NODE_LINK:
+ /* nothing to do */
+ mbuf = header;
+ break;
+
+ default:
+ break;
+ }
+
+ show_msg(stream, 1, &msg, mbuf);
+
+ return 0;
+}
+
+
+/***************************************************************************
+ *
+ * Common function for ei_show_recmsg() and ei_show_sendmsg()
+ *
+ ***************************************************************************/
+
+static void show_msg(FILE *stream, int direction, const erlang_msg *msg,
+ const char *buf)
+{
+ if (direction) fprintf(stream,"-> ");
+ else fprintf(stream,"<- ");
+
+ switch (msg->msgtype) {
+ case ERL_LINK:
+ fprintf(stream,"LINK From: ");
+ show_pid(stream,&msg->from);
+ fprintf(stream," To: ");
+ show_pid(stream,&msg->to);
+ break;
+
+ case ERL_SEND:
+ fprintf(stream,"SEND To: ");
+ show_pid(stream,&msg->to);
+ fprintf(stream,"\n ");
+ /* show the message */
+ ei_efprint(stream,buf);
+ break;
+
+ case ERL_EXIT:
+ fprintf(stream,"EXIT From: ");
+ show_pid(stream,&msg->from);
+ fprintf(stream," To: ");
+ show_pid(stream,&msg->to);
+ /* show the reason */
+ fprintf(stream,"\n Reason: ");
+ ei_efprint(stream,buf);
+ break;
+
+ case ERL_UNLINK:
+ fprintf(stream,"UNLINK From: ");
+ show_pid(stream,&msg->from);
+ fprintf(stream," To: ");
+ show_pid(stream,&msg->to);
+ break;
+
+ case ERL_NODE_LINK:
+ fprintf(stream,"NODE_LINK");
+ break;
+
+ case ERL_REG_SEND:
+ fprintf(stream,"REG_SEND From: ");
+ show_pid(stream,&msg->from);
+ fprintf(stream," To: %s\n ",msg->toname);
+ /* show the message */
+ ei_efprint(stream,buf);
+ break;
+
+ case ERL_GROUP_LEADER:
+ fprintf(stream,"GROUP_LEADER From: ");
+ show_pid(stream,&msg->from);
+ fprintf(stream," To: ");
+ show_pid(stream,&msg->to);
+ break;
+
+ case ERL_EXIT2:
+ fprintf(stream,"EXIT2 From: ");
+ show_pid(stream,&msg->from);
+ fprintf(stream," To: ");
+ show_pid(stream,&msg->to);
+ /* show the reason */
+ fprintf(stream,"\n Reason: ");
+ ei_efprint(stream,buf);
+ break;
+
+ /* the new TT stuff below */
+
+ case ERL_EXIT_TT:
+ fprintf(stream,"EXIT_TT From: ");
+ show_pid(stream,&msg->from);
+ fprintf(stream," To: ");
+ show_pid(stream,&msg->to);
+ fprintf(stream,"\n ");
+ show_trace(stream,&msg->token);
+ /* show the reason */
+ fprintf(stream,"\n Reason: ");
+ ei_efprint(stream,buf);
+ break;
+
+ case ERL_EXIT2_TT:
+ fprintf(stream,"EXIT2_TT From: ");
+ show_pid(stream,&msg->from);
+ fprintf(stream," To: ");
+ show_pid(stream,&msg->to);
+ fprintf(stream,"\n ");
+ show_trace(stream,&msg->token);
+ /* show the reason */
+ fprintf(stream,"\n Reason: ");
+ ei_efprint(stream,buf);
+ break;
+
+ case ERL_SEND_TT:
+ fprintf(stream,"SEND_TT To: ");
+ show_pid(stream,&msg->to);
+ fprintf(stream,"\n ");
+ show_trace(stream,&msg->token);
+ fprintf(stream,"\n ");
+ /* show the message */
+ ei_efprint(stream,buf);
+ break;
+
+ case ERL_REG_SEND_TT:
+ fprintf(stream,"REG_SEND_TT From: ");
+ show_pid(stream,&msg->from);
+ fprintf(stream," To: %s\n ",msg->toname);
+ show_trace(stream,&msg->token);
+ fprintf(stream,"\n ");
+ /* show the message */
+ ei_efprint(stream,buf);
+ break;
+
+ default:
+ fprintf(stream,"Unknown message type: %ld",msg->msgtype);
+ }
+ fprintf(stream,"\n");
+}
+
+/***************************************************************************
+ *
+ * Print term to stream with fprintf
+ *
+ ***************************************************************************/
+
+
+static void ei_efprint(FILE *stream, const char *termbuf)
+{
+ int index = 0;
+ show_term(termbuf,&index,stream);
+}
+
+static void show_term(const char *termbuf, int *index, FILE *stream)
+{
+ int type;
+ char smallbuf[EISHOWBUF];
+ int version;
+ long num;
+ double fnum;
+ erlang_pid pid;
+ erlang_port port;
+ erlang_ref ref;
+ int i, len;
+ char *s;
+
+ ei_get_type_internal(termbuf,index,&type,&len);
+
+ switch (type) {
+ case ERL_VERSION_MAGIC:
+ /* just skip past this */
+ ei_decode_version(termbuf,index,&version);
+ show_term(termbuf,index,stream);
+ break;
+
+ case ERL_ATOM_EXT:
+ ei_decode_atom(termbuf,index,smallbuf);
+ fprintf(stream,"%s",smallbuf);
+ break;
+
+ case ERL_STRING_EXT:
+ /* strings can be much longer than EISHOWBUF */
+ if (len < EISHOWBUF) s = smallbuf;
+ else if (!(s = malloc(len+1))) break; /* FIXME just break if can't? */
+
+ ei_decode_string(termbuf,index,s);
+
+ if (printable_list_p((uint8 *)s,len)) {
+ /* just show it as it is */
+ fprintf(stream,"\"%s\"",s);
+ } else {
+ /* show it as a list instead */
+ fprintf(stream,"[");
+ for (i=0; i<len; i++) {
+ if (i > 0) fprintf(stream,", ");
+ fprintf(stream,"%d",s[i]);
+ }
+ fprintf(stream,"]");
+ }
+
+ /* did we allocate anything? */
+ if (s && (s != smallbuf)) free(s);
+
+ break;
+
+ /* FIXME add case using ei_decode_longlong */
+ case ERL_SMALL_BIG_EXT:
+ case ERL_SMALL_INTEGER_EXT:
+ case ERL_INTEGER_EXT:
+ if (ei_decode_long(termbuf,index,&num) == 0) {
+ fprintf(stream,"%ld",num);
+ } else {
+ ei_decode_skip_bignum(termbuf,index,NULL);
+ fprintf(stream,"#Bignum");
+ }
+ break;
+
+ case ERL_FLOAT_EXT:
+ ei_decode_double(termbuf,index,&fnum);
+ fprintf(stream,"%f",fnum);
+ break;
+
+ case ERL_PID_EXT:
+ ei_decode_pid(termbuf,index,&pid);
+ show_pid(stream,&pid);
+ break;
+
+ case ERL_SMALL_TUPLE_EXT:
+ case ERL_LARGE_TUPLE_EXT:
+ ei_decode_tuple_header(termbuf,index,&len);
+ fprintf(stream,"{");
+ for (i=0; i<len; i++) {
+ if (i > 0) fprintf(stream,", ");
+ show_term(termbuf,index,stream);
+ }
+ fprintf(stream,"}");
+ break;
+
+ case ERL_LIST_EXT:
+ ei_decode_list_header(termbuf,index,&len);
+ fprintf(stream,"[");
+ for (i=0; i<len; i++) {
+ if (i > 0) fprintf(stream,", ");
+ show_term(termbuf,index,stream);
+ }
+ /* get the empty list at the end */
+ ei_decode_list_header(termbuf,index,&len);
+ fprintf(stream,"]");
+ break;
+
+ case ERL_NIL_EXT:
+ ei_decode_list_header(termbuf,index,&len);
+ fprintf(stream,"[]");
+ break;
+
+ case ERL_REFERENCE_EXT:
+ case ERL_NEW_REFERENCE_EXT:
+ ei_decode_ref(termbuf,index,&ref);
+ fprintf(stream,"#Ref<%s",ref.node);
+ for (i = 0; i < ref.len; i++) {
+ fprintf(stream,".%u",ref.n[i]);
+ }
+ fprintf(stream,".%u>",ref.creation);
+ break;
+
+ case ERL_PORT_EXT:
+ ei_decode_port(termbuf,index,&port);
+ fprintf(stream,"#Port<%s.%u.%u>",port.node,port.id,port.creation);
+ break;
+
+ case ERL_BINARY_EXT:
+ ei_decode_binary(termbuf,index,NULL,&num);
+ fprintf(stream,"#Bin<%ld>",num);
+ break;
+
+ case ERL_LARGE_BIG_EXT:
+ /* doesn't actually decode - just skip over it */
+ /* FIXME if GMP, what to do here?? */
+ ei_decode_skip_bignum(termbuf,index,NULL);
+ fprintf(stream,"#Bignum");
+ break;
+
+ case ERL_FUN_EXT: {
+ char atom[MAXATOMLEN+1];
+ long idx;
+ long uniq;
+ const char* s = termbuf + *index, * s0 = s;
+ int n_free;
+
+ ++s;
+ n_free = get32be(s);
+ *index += s - s0;
+ ei_decode_pid(termbuf, index, NULL); /* skip pid */
+ ei_decode_atom(termbuf, index, atom); /* get module, index, uniq */
+ ei_decode_long(termbuf, index, &idx);
+ ei_decode_long(termbuf, index, &uniq);
+ fprintf(stream,"#Fun<%s.%ld.%ld>", atom, idx, uniq);
+ for (i = 0; i < n_free; ++i) {
+ /* FIXME how to report error ?! */
+ if (ei_skip_term(termbuf, index) != 0)
+ fprintf(stderr,"<ERROR> show_msg: unknown type of term !");
+ }
+ break;
+ }
+ default:
+ fprintf(stream,"#Unknown<%d.%d>",type,len);
+ /* unfortunately we don't know how to skip over this type in
+ * the buffer if we don't even know what it is, so we return.
+ */
+ return;
+ break;
+ }
+}
+
+/***************************************************************************
+ *
+ * this help function does the actual decoding of the
+ * terms and is used by both ei_efprint and ei_sprintt.
+ *
+ * termbuf contains the undecoded term.
+ * idx is the current position in termbuf.
+ * stream is print destination, e.g. a FILE*
+ *
+ ***************************************************************************/
+
+static void show_pid(FILE *stream, const erlang_pid *pid)
+{
+ fprintf(stream,"#Pid<%s.%u.%u.%u>",
+ pid->node,pid->num,pid->serial,pid->creation);
+}
+
+static void show_trace(FILE *stream, const erlang_trace *t)
+{
+ fprintf(stream,
+ "Trace: Label: %ld, Flags: 0x%lx serial: %ld, prev: %ld From: ",
+ t->label,t->flags,t->serial,t->prev);
+ show_pid(stream,&t->from);
+}
+
+/***************************************************************************
+ *
+ * Try do decide if a buffer only contains printable characters
+ *
+ ***************************************************************************/
+
+/* we only need to initialize some of these (after 32 everything printable) */
+/* FIXME they are not!!!! We use isprint() for now but we could create a */
+/* custom print function that escape some non printable like \t and \n */
+#if 0
+static int non_printable[256] = {
+ /* 1 2 3 */
+ /* 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 */
+ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
+ /* \b\t\n\v\f\r */
+};
+#endif
+
+static int printable_list_p(const uint8 *buf, int buflen)
+{
+ int i;
+
+ for (i=0; i<buflen; i++) if (!isprint(buf[i])) return 0;
+
+ /* is printable */
+ return 1;
+}
+
+/***************************************************************************
+ *
+ * Skip over bignums, we can't print them
+ *
+ ***************************************************************************/
+
+/* FIXME we can if bignum small enough or if we use Per's functions or
+ if we have compiled in gmp support */
+
+/* this function doesn't do anything but skip over the number in the buffer */
+/* it doesn't really belong here either... */
+
+static int ei_decode_skip_bignum(const char *buf, int *index, void *p)
+{
+ const char *s = buf + *index;
+ const char *s0 = s;
+ long n;
+
+ switch (get8(s)) {
+ case ERL_LARGE_BIG_EXT:
+ n = get32be(s);
+ s += n+1;
+ break;
+
+ default:
+ erl_errno = EIO;
+ return -1;
+ }
+
+ *index += s-s0;
+
+ return 0;
+}