show_msg.c

来自「OTP是开放电信平台的简称」· C语言 代码 · 共 582 行

C
582
字号
/* ``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 via the world wide web 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. *  * The Initial Developer of the Original Code is Ericsson Utvecklings AB. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings * AB. All Rights Reserved.'' *  *     $Id$ */#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#endifstatic 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 0static 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                                     */};#endifstatic 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;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?