⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 beam_debug.c

📁 OTP是开放电信平台的简称
💻 C
字号:
/* ``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$ *//* * Purpose: Basic debugging support. */#ifdef HAVE_CONFIG_H#  include "config.h"#endif#include "sys.h"#include "erl_vm.h"#include "global.h"#include "erl_process.h"#include "error.h"#include "erl_driver.h"#include "bif.h"#include "big.h"#include "external.h"#include "beam_load.h"#include "beam_bp.h"#include "erl_binary.h"#ifdef ARCH_64# define HEXF "%016bpX"#else# define HEXF "%08bpX"#endifvoid dbg_bt(Process* p, Eterm* sp);void dbg_where(Eterm* addr, Eterm x0, Eterm* reg);static void print_big(int to, void *to_arg, Eterm* addr);static int print_op(int to, void *to_arg, int op, int size, Eterm* addr);Etermerts_debug_same_2(Process* p, Eterm term1, Eterm term2){    return (term1 == term2) ? am_true : am_false;}Etermerts_debug_flat_size_1(Process* p, Eterm term){    Uint size = size_object(term);    if (IS_USMALL(0, size)) {	BIF_RET(make_small(size));    } else {	Eterm* hp = HAlloc(p, BIG_UINT_HEAP_SIZE);	BIF_RET(uint_to_big(size, hp));    }}Etermerts_debug_breakpoint_2(Process* p, Eterm MFA, Eterm bool){    Eterm* tp;    Eterm mfa[3];    int i;    int specified = 0;    Eterm res;    if (bool != am_true && bool != am_false)	goto error;    if (is_not_tuple(MFA)) {	goto error;    }    tp = tuple_val(MFA);    if (*tp != make_arityval(3)) {	goto error;    }    mfa[0] = tp[1];    mfa[1] = tp[2];    mfa[2] = tp[3];    if (!is_atom(mfa[0]) || !is_atom(mfa[1]) ||	(!is_small(mfa[2]) && mfa[2] != am_Underscore)) {	goto error;    }    for (i = 0; i < 3 && mfa[i] != am_Underscore; i++, specified++) {	/* Empty loop body */    }    for (i = specified; i < 3; i++) {	if (mfa[i] != am_Underscore) {	    goto error;	}    }    if (is_small(mfa[2])) {	mfa[2] = signed_val(mfa[2]);    }    erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN);    erts_smp_block_system(0);    if (bool == am_true) {	res = make_small(erts_set_debug_break(mfa, specified));    } else {	res = make_small(erts_clear_debug_break(mfa, specified));    }    erts_smp_release_system();    erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);    return res; error:    BIF_ERROR(p, BADARG);}Etermerts_debug_disassemble_1(Process* p, Eterm addr){    erts_dsprintf_buf_t *dsbufp;    Eterm* hp;    Eterm* tp;    Eterm bin;    Eterm mfa;    Eterm* funcinfo = NULL;	/* Initialized to eliminate warning. */    Uint* code_base;    Uint* code_ptr = NULL;	/* Initialized to eliminate warning. */    Uint instr;    Uint uaddr;    Uint hsz;    int i;    if (term_to_Uint(addr, &uaddr)) {	code_ptr = (Uint *) uaddr;	if ((funcinfo = find_function_from_pc(code_ptr)) == NULL) {	    BIF_RET(am_false);	}    } else if (is_tuple(addr)) {	Module* modp;	Eterm mod;	Eterm name;	Export* ep;	Sint arity;	int n;	tp = tuple_val(addr);	if (tp[0] != make_arityval(3)) {	error:	    BIF_ERROR(p, BADARG);	}	mod = tp[1];	name = tp[2];	if (!is_atom(mod) || !is_atom(name) || !is_small(tp[3])) {	    goto error;	}	arity = signed_val(tp[3]);	modp = erts_get_module(mod);	/*	 * Try the export entry first to allow disassembly of special functions	 * such as erts_debug:apply/4.  Then search for it in the module.	 */	if ((ep = erts_find_function(mod, name, arity)) != NULL) {	    /* XXX: add "&& ep->address != ep->code+3" condition?	     * Consider a traced function.	     * Its ep will have ep->address == ep->code+3.	     * erts_find_function() will return the non-NULL ep.	     * Below we'll try to derive a code_ptr from ep->address.	     * But this code_ptr will point to the start of the Export,	     * not the function's func_info instruction. BOOM !?	     */	    code_ptr = ((Eterm *) ep->address) - 5;	    funcinfo = code_ptr+2;	} else if (modp == NULL || (code_base = modp->code) == NULL) {	    BIF_RET(am_undef);	} else {	    n = code_base[MI_NUM_FUNCTIONS];	    for (i = 0; i < n; i++) {		code_ptr = (Uint *) code_base[MI_FUNCTIONS+i];		if (code_ptr[3] == name && code_ptr[4] == arity) {		    funcinfo = code_ptr+2;		    break;		}	    }	    if (i == n) {		BIF_RET(am_undef);	    }	}    } else {	goto error;    }    dsbufp = erts_create_tmp_dsbuf(0);    erts_print(ERTS_PRINT_DSBUF, (void *) dsbufp, HEXF ": ", code_ptr);    instr = (Uint) code_ptr[0];    for (i = 0; i < NUM_SPECIFIC_OPS; i++) {	if (instr == (Uint) BeamOp(i) && opc[i].name[0] != '\0') {	    code_ptr += print_op(ERTS_PRINT_DSBUF, (void *) dsbufp,				 i, opc[i].sz-1, code_ptr+1) + 1;	    break;	}    }    if (i >= NUM_SPECIFIC_OPS) {	erts_print(ERTS_PRINT_DSBUF, (void *) dsbufp,		   "unknown " HEXF "\n", instr);	code_ptr++;    }    bin = new_binary(p, (byte *) dsbufp->str, (int) dsbufp->str_len);    erts_destroy_tmp_dsbuf(dsbufp);    hsz = 4+4;    (void) erts_bld_uint(NULL, &hsz, (Uint) code_ptr);    hp = HAlloc(p, hsz);    addr = erts_bld_uint(&hp, NULL, (Uint) code_ptr);    ASSERT(is_atom(funcinfo[0]));    ASSERT(is_atom(funcinfo[1]));    mfa = TUPLE3(hp, funcinfo[0], funcinfo[1], make_small(funcinfo[2]));    hp += 4;    return TUPLE3(hp, addr, bin, mfa);}voiddbg_bt(Process* p, Eterm* sp){    Eterm* stack = STACK_START(p);    while (sp < stack) {	if (is_CP(*sp)) {	    Eterm* addr = find_function_from_pc(cp_val(*sp));	    if (addr)		erts_fprintf(stderr,			     HEXF ": %T:%T/%bpu\n",			     addr, addr[0], addr[1], addr[2]);	}	sp++;    }}voiddbg_where(Eterm* addr, Eterm x0, Eterm* reg){    Eterm* f = find_function_from_pc(addr);    if (f == NULL) {	erts_fprintf(stderr, "???\n");    } else {	int arity;	int i;	addr = f;	arity = addr[2];	erts_fprintf(stderr, HEXF ": %T:%T(", addr, addr[0], addr[1]);	for (i = 0; i < arity; i++)	    erts_fprintf(stderr, i ? ", %T" : "%T", i ? reg[i] : x0);	erts_fprintf(stderr, ")\n");    }}static intprint_op(int to, void *to_arg, int op, int size, Eterm* addr){    int i;    Uint tag;    char* sign;    char* start_prog;		/* Start of program for packer. */    char* prog;			/* Current position in packer program. */    Uint stack[8];		/* Stack for packer. */    Uint* sp = stack;		/* Points to next free position. */    Uint packed = 0;		/* Accumulator for packed operations. */    Uint args[8];		/* Arguments for this instruction. */    Uint* ap;			/* Pointer to arguments. */    start_prog = opc[op].pack;    if (start_prog[0] == '\0') {	/*	 * There is no pack program.	 * Avoid copying because instructions containing bignum operands	 * are bigger than actually declared.	 */	ap = (Uint *) addr;    } else {	/*	 * Copy all arguments to a local buffer for the unpacking.	 */	ASSERT(size <= sizeof(args)/sizeof(args[0]));	ap = args;	for (i = 0; i < size; i++) {	    *ap++ = addr[i];	}	/*	 * Undo any packing done by the loader.  This is easily done by running	 * the packing program backwards and in reverse.	 */	prog = start_prog + strlen(start_prog);	while (start_prog < prog) {	    prog--;	    switch (*prog) {	    case 'g':		*ap++ = *--sp;		break;	    case 'i':		/* Initialize packing accumulator. */		*ap++ = packed;		break;	    case 's':		*ap++ = packed & 0x3ff;		packed >>= 10;		break;	    case '0':		/* Tight shift */		*ap++ = packed & (BEAM_TIGHT_MASK / sizeof(Eterm));		packed >>= BEAM_TIGHT_SHIFT;		break;	    case '6':		/* Shift 16 steps */		*ap++ = packed & 0xffff;		packed >>= 16;		break;	    case 'p':		*sp++ = *--ap;		break;	    case 'P':		packed = *--sp;		break;	    default:		ASSERT(0);	    }	}	ap = args;    }    /*     * Print the name and all operands of the instructions.     */	    erts_print(to, to_arg, "%s ", opc[op].name);    sign = opc[op].sign;    while (*sign) {	switch (*sign) {	case 'r':		/* x(0) */	    erts_print(to, to_arg, "x(0)");	    break;	case 'x':		/* x(N) */	    erts_print(to, to_arg, "x(%d)", reg_index(ap[0]));	    ap++;	    break;	case 'y':		/* y(N) */	    erts_print(to, to_arg, "y(%d)", reg_index(ap[0]) - CP_SIZE);	    ap++;	    break;	case 'n':		/* Nil */	    erts_print(to, to_arg, "[]");	    break;	case 's':		/* Any source (tagged constant or register) */	    tag = beam_reg_tag(*ap);	    if (tag == X_REG_DEF) {		erts_print(to, to_arg, "x(%d)", reg_index(*ap));		ap++;		break;	    } else if (tag == Y_REG_DEF) {		erts_print(to, to_arg, "y(%d)", reg_index(*ap) - CP_SIZE);		ap++;		break;	    } else if (tag == R_REG_DEF) {		erts_print(to, to_arg, "x(0)");		ap++;		break;	    }	    /*FALLTHROUGH*/	case 'a':		/* Tagged atom */	case 'i':		/* Tagged integer */	case 'c':		/* Tagged constant */	    erts_print(to, to_arg, "%T", *ap);	    ap++;	    break;	case 'A':	    erts_print(to, to_arg, "%d", arityval(ap[0]));	    ap++;	    break;	case 'd':		/* Destination (x(0), x(N), y(N)) */	    switch (beam_reg_tag(*ap)) {	    case X_REG_DEF:		erts_print(to, to_arg, "x(%d)", reg_index(*ap));		break;	    case Y_REG_DEF:		erts_print(to, to_arg, "y(%d)", reg_index(*ap) - CP_SIZE);		break;	    case R_REG_DEF:		erts_print(to, to_arg, "x(0)");		break;	    }	    ap++;	    break;	case 'I':		/* Untagged integer. */	case 't':	    erts_print(to, to_arg, "%d", *ap);	    ap++;	    break;	case 'f':		/* Destination label */	    erts_print(to, to_arg, "f(%X)", *ap);	    ap++;	    break;	case 'p':		/* Pointer (to label) */	    {		Eterm* f = find_function_from_pc((Eterm *)*ap);		if (f+3 != (Eterm *) *ap) {		    erts_print(to, to_arg, "p(%X)", *ap);		} else {		    erts_print(to, to_arg, "%T:%T/%bpu", f[0], f[1], f[2]);		}		ap++;	    }	    break;	case 'j':		/* Pointer (to label) */	    erts_print(to, to_arg, "j(%X)", *ap);	    ap++;	    break;	case 'e':		/* Export entry */	    {		Export* ex = (Export *) *ap;		erts_print(to, to_arg,			   "%T:%T/%bpu", ex->code[0], ex->code[1], ex->code[2]);		ap++;	    }	    break;	case 'F':		/* Function definition */	    break;	case 'b':	    for (i = 0; i < BIF_SIZE; i++) {		BifFunction bif = (BifFunction) *ap;		if (bif == bif_table[i].f) {		    break;		}	    }	    if (i == BIF_SIZE) {		erts_print(to, to_arg, "b(%d)", (Uint) *ap);	    } else {		Eterm name = bif_table[i].name;		unsigned arity = bif_table[i].arity;		erts_print(to, to_arg, "%T/%u", name, arity);	    }	    ap++;	    break;	case 'P':	/* Byte offset into tuple (see beam_load.c) */	    erts_print(to, to_arg, "%d", (*ap / sizeof(Eterm*)) - 1);	    ap++;	    break;	case 'w':	    {		int arity = thing_arityval(ap[0]);		print_big(to, to_arg, ap);		ap += arity + 1;		size += arity;	    }	    break;	case 'o':	    {		FloatDef f;#ifdef ARCH_64		ap++;		f.fdw = *ap++;#else		ap++;		f.fw[0] = *ap++;		f.fw[1] = *ap++;#endif		erts_print(to, to_arg, "%g", f.fd);		size++;	    }	    break;	case 'l':		/* fr(N) */	    erts_print(to, to_arg, "fr(%d)", reg_index(ap[0]));	    ap++;	    break;	default:	    erts_print(to, to_arg, "???");	    ap++;	    break;	}	erts_print(to, to_arg, " ");	sign++;    }    /*     * Print more information about certain instructions.     */    ap = addr + size;    switch (op) {    case op_i_select_val_sfI:	{	    int n = ap[-1];	    while (n > 0) {		erts_print(to, to_arg, "%T f(%X) ", ap[0], ap[1]);		ap += 2;		size += 2;		n--;	    }	}	break;    case op_i_jump_on_val_sfII:	{	    int n;	    for (n = ap[-2]; n > 0; n--) {		erts_print(to, to_arg, "f(%X) ", ap[0]);		ap++;		size++;	    }	}	break;    case op_i_select_big_sf:	while (ap[0]) {	    int arity = thing_arityval(ap[0]);	    print_big(to, to_arg, ap);	    size += arity+1;	    ap += arity+1;	    erts_print(to, to_arg, " f(%X) ", ap[0]);	    ap++;	    size++;	}	ap++;	size++;	break;    }    erts_print(to, to_arg, "\n");    return size;}static voidprint_big(int to, void *to_arg, Eterm* addr){    int i;    int k;    i = BIG_SIZE(addr);    if (BIG_SIGN(addr))	erts_print(to, to_arg, "-#integer(%d) = {", i);    else	erts_print(to, to_arg, "#integer(%d) = {", i);    erts_print(to, to_arg, "%d", BIG_DIGIT(addr, 0));    for (k = 1; k < i; k++)	erts_print(to, to_arg, ",%d", BIG_DIGIT(addr, k));    erts_print(to, to_arg, "}");}

⌨️ 快捷键说明

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