📄 erl_trace.c
字号:
ASSERT(is_internal_pid(p->tracer_proc) && internal_pid_index(p->tracer_proc) < erts_max_processes);#ifndef ERTS_SMP tracer = process_tab[internal_pid_index(p->tracer_proc)]; if (INVALID_PID(tracer, p->tracer_proc) || (tracer->trace_flags & F_TRACER) == 0) { p->trace_flags &= ~TRACEE_FLAGS; p->tracer_proc = NIL; return; }#endif size = size_object(mess);#ifdef ERTS_SMP bp = new_message_buffer(size); hp = bp->mem; off_heap = &bp->off_heap;#else hp = erts_alloc_message_heap(size, &bp, &off_heap, tracer, 0);#endif /* * Copy the trace message into the buffer and enqueue it. */ mess = copy_struct(mess, size, &hp, off_heap);#ifdef ERTS_SMP enqueue_sys_msg_unlocked(SYS_MSG_TYPE_TRACE, p->id, p->tracer_proc, mess, bp);#else erts_queue_message(tracer, 0, bp, mess, NIL);#endif } erts_smp_mtx_unlock(&smq_mtx);}/* Send {trace_ts, Pid, return_from, {Mod, Name, Arity}, Retval, Timestamp} * or {trace, Pid, return_from, {Mod, Name, Arity}, Retval} */voiderts_trace_return(Process* p, Eterm* fi, Eterm retval, Eterm *tracer_pid){ Eterm* hp; Eterm mfa; Eterm mess; Eterm mod, name; int arity; Uint meta_flags, *tracee_flags;#ifdef ERTS_SMP Eterm tracee;#endif ASSERT(tracer_pid); if (*tracer_pid == am_true) { /* Breakpoint trace enabled without specifying tracer => * use process tracer and flags */ tracer_pid = &p->tracer_proc; } if (is_nil(*tracer_pid)) { /* Trace disabled */ return; } ASSERT(is_internal_pid(*tracer_pid) || is_internal_port(*tracer_pid)); if (*tracer_pid == p->id) { /* Do not generate trace messages to oneself */ return; } if (tracer_pid == &p->tracer_proc) { /* Tracer specified in process structure => * non-breakpoint trace => * use process flags */ tracee_flags = &p->trace_flags;#ifdef ERTS_SMP tracee = p->id;#endif } else { /* Tracer not specified in process structure => * tracer specified in breakpoint => * meta trace => * use fixed flag set instead of process flags */ meta_flags = F_TRACE_CALLS | F_TIMESTAMP; tracee_flags = &meta_flags;#ifdef ERTS_SMP tracee = NIL;#endif } if (! (*tracee_flags & F_TRACE_CALLS)) { return; } mod = fi[0]; name = fi[1]; arity = fi[2]; if (is_internal_port(*tracer_pid)) { Eterm local_heap[4+6+5]; hp = local_heap; mfa = TUPLE3(hp, mod, name, make_small(arity)); hp += 4; mess = TUPLE5(hp, am_trace, p->id, am_return_from, mfa, retval); hp += 6; erts_smp_mtx_lock(&smq_mtx); if (*tracee_flags & F_TIMESTAMP) { hp = patch_ts(mess, hp); } send_to_port(p, mess, tracer_pid, tracee_flags); erts_smp_mtx_unlock(&smq_mtx); } else { ErlHeapFragment *bp; ErlOffHeap *off_heap;#ifndef ERTS_SMP Process *tracer;#endif unsigned size; unsigned retval_size;#ifdef DEBUG Eterm* limit;#endif ASSERT(is_internal_pid(*tracer_pid) && internal_pid_index(*tracer_pid) < erts_max_processes);#ifndef ERTS_SMP tracer = process_tab[internal_pid_index(*tracer_pid)]; if (INVALID_PID(tracer, *tracer_pid) || (tracer->trace_flags & F_TRACER) == 0) { *tracee_flags &= ~TRACEE_FLAGS; *tracer_pid = NIL; return; }#endif retval_size = size_object(retval); size = 6 + 4 + retval_size; if (*tracee_flags & F_TIMESTAMP) { size += 1+4; }#ifdef ERTS_SMP bp = new_message_buffer(size); hp = bp->mem; off_heap = &bp->off_heap;#else hp = erts_alloc_message_heap(size, &bp, &off_heap, tracer, 0);#endif#ifdef DEBUG limit = hp + size;#endif /* * Build the trace tuple and put it into receive queue of the tracer process. */ mfa = TUPLE3(hp, mod, name, make_small(arity)); hp += 4; retval = copy_struct(retval, retval_size, &hp, off_heap); mess = TUPLE5(hp, am_trace, p->id/* Local pid */, am_return_from, mfa, retval); hp += 6; erts_smp_mtx_lock(&smq_mtx); if (*tracee_flags & F_TIMESTAMP) { hp = patch_ts(mess, hp); } ASSERT(hp == limit);#ifdef ERTS_SMP enqueue_sys_msg_unlocked(SYS_MSG_TYPE_TRACE, tracee, *tracer_pid, mess, bp); erts_smp_mtx_unlock(&smq_mtx);#else erts_queue_message(tracer, 0, bp, mess, NIL);#endif }}/* Send {trace_ts, Pid, exception_from, {Mod, Name, Arity}, {Class,Value}, * Timestamp} * or {trace, Pid, exception_from, {Mod, Name, Arity}, {Class,Value}, * Timestamp} * * Where Class is atomic but Value is any term. */voiderts_trace_exception(Process* p, Eterm mfa[3], Eterm class, Eterm value, Eterm *tracer_pid){ Eterm* hp; Eterm mfa_tuple; Eterm cv; Eterm mess; Uint meta_flags, *tracee_flags;#ifdef ERTS_SMP Eterm tracee;#endif ASSERT(tracer_pid); if (*tracer_pid == am_true) { /* Breakpoint trace enabled without specifying tracer => * use process tracer and flags */ tracer_pid = &p->tracer_proc; } if (is_nil(*tracer_pid)) { /* Trace disabled */ return; } ASSERT(is_internal_pid(*tracer_pid) || is_internal_port(*tracer_pid)); if (*tracer_pid == p->id) { /* Do not generate trace messages to oneself */ return; } if (tracer_pid == &p->tracer_proc) { /* Tracer specified in process structure => * non-breakpoint trace => * use process flags */ tracee_flags = &p->trace_flags;#ifdef ERTS_SMP tracee = p->id;#endif if (! (*tracee_flags & F_TRACE_CALLS)) { return; } } else { /* Tracer not specified in process structure => * tracer specified in breakpoint => * meta trace => * use fixed flag set instead of process flags */ meta_flags = F_TRACE_CALLS | F_TIMESTAMP; tracee_flags = &meta_flags;#ifdef ERTS_SMP tracee = NIL;#endif } if (is_internal_port(*tracer_pid)) { Eterm local_heap[4+3+6+5]; hp = local_heap; mfa_tuple = TUPLE3(hp, mfa[0], mfa[1], make_small(mfa[2])); hp += 4; cv = TUPLE2(hp, class, value); hp += 3; mess = TUPLE5(hp, am_trace, p->id, am_exception_from, mfa_tuple, cv); hp += 6; ASSERT((hp - local_heap)*sizeof(*hp) <= sizeof(local_heap)); erts_smp_mtx_lock(&smq_mtx); if (*tracee_flags & F_TIMESTAMP) { hp = patch_ts(mess, hp); /* hp += 5 */ ASSERT((hp - local_heap)*sizeof(*hp) == sizeof(local_heap)); } send_to_port(p, mess, tracer_pid, tracee_flags); erts_smp_mtx_unlock(&smq_mtx); } else { ErlHeapFragment *bp; ErlOffHeap *off_heap;#ifndef ERTS_SMP Process *tracer;#endif unsigned size; unsigned value_size;#ifdef DEBUG Eterm* limit;#endif ASSERT(is_internal_pid(*tracer_pid) && internal_pid_index(*tracer_pid) < erts_max_processes);#ifndef ERTS_SMP tracer = process_tab[internal_pid_index(*tracer_pid)]; if (INVALID_PID(tracer, *tracer_pid) || (tracer->trace_flags & F_TRACER) == 0) { *tracee_flags &= ~TRACEE_FLAGS; *tracer_pid = NIL; return; }#endif value_size = size_object(value); size = 6 + 4 + 3 + value_size; if (*tracee_flags & F_TIMESTAMP) { size += 1+4; }#ifdef ERTS_SMP bp = new_message_buffer(size); hp = bp->mem; off_heap = &bp->off_heap;#else hp = erts_alloc_message_heap(size, &bp, &off_heap, tracer, 0);#endif#ifdef DEBUG limit = hp + size;#endif /* * Build the trace tuple and put it into receive queue of the tracer process. */ mfa_tuple = TUPLE3(hp, mfa[0], mfa[1], make_small(mfa[2])); hp += 4; value = copy_struct(value, value_size, &hp, off_heap); cv = TUPLE2(hp, class, value); hp += 3; mess = TUPLE5(hp, am_trace, p->id/* Local pid */, am_exception_from, mfa_tuple, cv); hp += 6; erts_smp_mtx_lock(&smq_mtx); if (*tracee_flags & F_TIMESTAMP) { hp = patch_ts(mess, hp); } ASSERT(hp == limit);#ifdef ERTS_SMP enqueue_sys_msg_unlocked(SYS_MSG_TYPE_TRACE, tracee, *tracer_pid, mess, bp); erts_smp_mtx_unlock(&smq_mtx);#else erts_queue_message(tracer, 0, bp, mess, NIL);#endif }}/* * This function implements the new call trace. * * Send {trace_ts, Pid, call, {Mod, Func, A}, PamResult, Timestamp} * or {trace_ts, Pid, call, {Mod, Func, A}, Timestamp} * or {trace, Pid, call, {Mod, Func, A}, PamResult} * or {trace, Pid, call, {Mod, Func, A} * * where 'A' is arity or argument list depending on trace flag 'arity'. * * If *tracer_pid is am_true, it is a breakpoint trace that shall use * the process tracer, if it is NIL no trace message is generated, * if it is a pid or port we do a meta trace. */Uint32erts_call_trace(Process* p, Eterm mfa[3], Binary *match_spec, Eterm* args, int local, Eterm *tracer_pid){ Eterm* hp; Eterm mfa_tuple; int arity; int i; Uint32 return_flags; Eterm pam_result = am_true; Eterm mess; Uint meta_flags, *tracee_flags;#ifdef ERTS_SMP Eterm tracee;#endif ASSERT(tracer_pid); if (*tracer_pid == am_true) { /* Breakpoint trace enabled without specifying tracer => * use process tracer and flags */ tracer_pid = &p->tracer_proc; } if (is_nil(*tracer_pid)) { /* Trace disabled */ return 0; } ASSERT(is_internal_pid(*tracer_pid) || is_internal_port(*tracer_pid)); if (*tracer_pid == p->id) { /* Do not generate trace messages to oneself */ return 0; } if (tracer_pid == &p->tracer_proc) { /* Tracer specified in process structure => * non-breakpoint trace => * use process flags */ tracee_flags = &p->trace_flags;#ifdef ERTS_SMP tracee = p->id;#endif } else { /* Tracer not specified in process structure => * tracer specified in breakpoint => * meta trace => * use fixed flag set instead of process flags */ if (p->trace_flags & F_SENSITIVE) { /* No trace messages for sensitive processes. */ return 0; } meta_flags = F_TRACE_CALLS | F_TIMESTAMP; tracee_flags = &meta_flags;#ifdef ERTS_SMP tracee = NIL;#endif } if (is_internal_port(*tracer_pid)) { Eterm local_heap[64+MAX_ARG]; hp = local_heap; if (!erts_is_valid_tracer_port(*tracer_pid)) {#ifdef ERTS_SMP ASSERT(is_nil(tracee) || tracer_pid == &p->tracer_proc); if (is_not_nil(tracee)) erts_smp_proc_lock(p, ERTS_PROC_LOCKS_ALL_MINOR);#endif *tracee_flags &= ~TRACEE_FLAGS; *tracer_pid = NIL;#ifdef ERTS_SMP if (is_not_nil(tracee)) erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL_MINOR);#endif return 0; } /* * If there is a PAM program, run it. Return if it fails. * * Some precedence rules: * * - No proc flags, e.g 'silent' or 'return_to' * has any effect on meta trace. * - The 'silent' process trace flag silences all call * related messages, e.g 'call', 'return_to' and 'return_from'. * - The {message,_} PAM function does not affect {return_trace}. * - The {message,false} PAM function shall give the same * 'call' trace message as no PAM match. * - The {message,true} PAM function shall give the same * 'call' trace message as a nonexistent PAM program. */ /* BEGIN this code should be the same for port and pid trace */ return_flags = 0; arity = mfa[2]; if (match_spec) { pam_result = erts_match_set_run(p, match_spec, args, arity, &return_flags); if (is_non_value(pam_result)) { erts_match_set_release_result(p); return 0; } } if (tracee_flags == &meta_flags) { /* Meta trace */ if (pam_result == am_false) { erts_match_set_release_result(p); return return_flags; } } else { /* Non-meta trace */ if (*tracee_flags & F_TRACE_SILENT) { erts_match_set_release_result(p); return 0; } if (pam_result == am_false) { erts_match_set_release_result(p); return return_flags; } if (local && (*tracee_flags & F_TRACE_RETURN_TO)) { return_flags |= MATCH_SET_RETURN_TO_TRACE; } } /* END this code should be the same for port and pid trace */ /* * Build the the {M,F,A} tuple in the local heap. * (A is arguments or arity.) */ if (*tracee_flags & F_TRACE_ARITY_ONLY) { mfa_tuple = make_small(arity); } else { mfa_tuple = NIL; for (i = arity-1; i >= 0; i--) { mfa_tuple = CONS(hp, args[i], mfa_tuple); hp += 2; } } mfa_tuple = TUPLE3(hp, mfa[0], mfa[1], mfa_tuple); hp += 4; /* * Build the trace tuple and send it to the port. */ mess = TUPLE4(hp, am_trace, p->id, am_call, mfa_tuple); hp += 5; if (pam_result != am_true) { hp[-5] = make_arityval(5); *hp++ = pam_result; } erts_smp_mtx_lock(&smq_mtx); if (*tracee_flags & F_TIMESTAMP) { hp = patch_ts(mess, hp); } send_to_port(p, mess, tracer_pid, tracee_flags); erts_smp_mtx_unlock(&smq_mtx); erts_match_set_release_result(p); return *tracer_pid == NIL ? 0 : return_flags; } else {#ifdef ERTS_SMP Eterm tpid;#endif ErlHeapFragment *bp; ErlOffHeap *off_heap; Process *tracer; unsigned size; unsigned sizes[256]; unsigned pam_result_size = 0; int invalid_tracer;#ifdef DEBUG Eterm* limit;#endif ASSERT(is_internal_pid(*tracer_pid)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -