diff options
Diffstat (limited to 'lib/erl_interface/src/misc/show_msg.c')
-rw-r--r-- | lib/erl_interface/src/misc/show_msg.c | 584 |
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; +} |