summaryrefslogtreecommitdiff
path: root/erts/emulator/beam/erl_bif_trace.c
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/beam/erl_bif_trace.c')
-rw-r--r--erts/emulator/beam/erl_bif_trace.c132
1 files changed, 89 insertions, 43 deletions
diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c
index e3008dfcef..9f79607d97 100644
--- a/erts/emulator/beam/erl_bif_trace.c
+++ b/erts/emulator/beam/erl_bif_trace.c
@@ -47,7 +47,7 @@
const struct trace_pattern_flags erts_trace_pattern_flags_off = {0, 0, 0, 0, 0};
/*
- * The following variables are protected by code write permission.
+ * The following variables are protected by code modification permission.
*/
static int erts_default_trace_pattern_is_on;
static Binary *erts_default_match_spec;
@@ -55,7 +55,7 @@ static Binary *erts_default_meta_match_spec;
static struct trace_pattern_flags erts_default_trace_pattern_flags;
static ErtsTracer erts_default_meta_tracer;
-static struct { /* Protected by code write permission */
+static struct { /* Protected by code modification permission */
int current;
int install;
int local;
@@ -130,7 +130,7 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist)
ErtsTracer meta_tracer = erts_tracer_nil;
Uint freason = BADARG;
- if (!erts_try_seize_code_write_permission(p)) {
+ if (!erts_try_seize_code_mod_permission(p)) {
ERTS_BIF_YIELD3(BIF_TRAP_EXPORT(BIF_erts_internal_trace_pattern_3), p, MFA, Pattern, flaglist);
}
finish_bp.current = -1;
@@ -213,6 +213,13 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist)
flags.breakpoint = 1;
flags.call_time = 1;
break;
+ case am_call_memory:
+ if (is_global) {
+ goto error;
+ }
+ flags.breakpoint = 1;
+ flags.call_memory = 1;
+ break;
default:
goto error;
@@ -225,8 +232,8 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist)
p->fvalue = am_none;
- if (match_prog_set && !flags.local && !flags.meta && (flags.call_count || flags.call_time)) {
- /* A match prog is not allowed with just call_count or call_time*/
+ if (match_prog_set && !flags.local && !flags.meta && (flags.call_count || flags.call_time || flags.call_memory)) {
+ /* A match prog is not allowed with just call_count or call_time or call_memory */
p->fvalue = am_call_count;
goto error;
}
@@ -356,7 +363,7 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist)
ERTS_BIF_YIELD_RETURN(p, make_small(matches));
}
- erts_release_code_write_permission();
+ erts_release_code_mod_permission();
if (matches >= 0) {
return make_small(matches);
@@ -377,7 +384,7 @@ static void smp_bp_finisher(void* null)
#ifdef DEBUG
finish_bp.stager = NULL;
#endif
- erts_release_code_write_permission();
+ erts_release_code_mod_permission();
erts_proc_lock(p, ERTS_PROC_LOCK_STATUS);
if (!ERTS_PROC_IS_EXITING(p)) {
erts_resume(p, ERTS_PROC_LOCK_STATUS);
@@ -394,8 +401,8 @@ erts_get_default_trace_pattern(int *trace_pattern_is_on,
struct trace_pattern_flags *trace_pattern_flags,
ErtsTracer *meta_tracer)
{
- ERTS_LC_ASSERT(erts_has_code_write_permission() ||
- erts_thr_progress_is_blocking());
+ ERTS_LC_ASSERT(erts_has_code_mod_permission() ||
+ erts_thr_progress_is_blocking());
if (trace_pattern_is_on)
*trace_pattern_is_on = erts_default_trace_pattern_is_on;
if (match_spec)
@@ -410,8 +417,8 @@ erts_get_default_trace_pattern(int *trace_pattern_is_on,
int erts_is_default_trace_enabled(void)
{
- ERTS_LC_ASSERT(erts_has_code_write_permission() ||
- erts_thr_progress_is_blocking());
+ ERTS_LC_ASSERT(erts_has_code_mod_permission() ||
+ erts_thr_progress_is_blocking());
return erts_default_trace_pattern_is_on;
}
@@ -553,7 +560,7 @@ Eterm erts_internal_trace_3(BIF_ALIST_3)
BIF_ERROR(p, BADARG | EXF_HAS_EXT_INFO);
}
- if (!erts_try_seize_code_write_permission(BIF_P)) {
+ if (!erts_try_seize_code_mod_permission(BIF_P)) {
ERTS_TRACER_CLEAR(&tracer);
ERTS_BIF_YIELD3(BIF_TRAP_EXPORT(BIF_erts_internal_trace_3),
BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3);
@@ -771,7 +778,7 @@ Eterm erts_internal_trace_3(BIF_ALIST_3)
erts_thr_progress_unblock();
erts_proc_lock(p, ERTS_PROC_LOCK_MAIN);
}
- erts_release_code_write_permission();
+ erts_release_code_mod_permission();
ERTS_TRACER_CLEAR(&tracer);
BIF_RET(make_small(matches));
@@ -788,7 +795,7 @@ Eterm erts_internal_trace_3(BIF_ALIST_3)
erts_thr_progress_unblock();
erts_proc_lock(p, ERTS_PROC_LOCK_MAIN);
}
- erts_release_code_write_permission();
+ erts_release_code_mod_permission();
BIF_ERROR(p, BADARG);
}
@@ -804,7 +811,7 @@ Eterm trace_info_2(BIF_ALIST_2)
Eterm Key = BIF_ARG_2;
Eterm res;
- if (!erts_try_seize_code_write_permission(p)) {
+ if (!erts_try_seize_code_mod_permission(p)) {
ERTS_BIF_YIELD2(BIF_TRAP_EXPORT(BIF_trace_info_2), p, What, Key);
}
@@ -818,10 +825,10 @@ Eterm trace_info_2(BIF_ALIST_2)
res = trace_info_func(p, What, Key);
} else {
p->fvalue = am_badopt;
- erts_release_code_write_permission();
+ erts_release_code_mod_permission();
BIF_ERROR(p, BADARG | EXF_HAS_EXT_INFO);
}
- erts_release_code_write_permission();
+ erts_release_code_mod_permission();
if (is_value(res) && is_internal_ref(res))
BIF_TRAP1(erts_await_result, BIF_P, res);
@@ -1029,6 +1036,7 @@ trace_info_pid(Process* p, Eterm pid_spec, Eterm key)
#define FUNC_TRACE_META_TRACE (1<<3)
#define FUNC_TRACE_COUNT_TRACE (1<<4)
#define FUNC_TRACE_TIME_TRACE (1<<5)
+#define FUNC_TRACE_MEMORY_TRACE (1<<6)
/*
* Returns either FUNC_TRACE_NOEXIST, FUNC_TRACE_UNTRACED,
* FUNC_TRACE_GLOBAL_TRACE, or,
@@ -1049,7 +1057,8 @@ static int function_is_traced(Process *p,
Binary **ms_meta, /* out */
ErtsTracer *tracer_pid_meta, /* out */
Uint *count, /* out */
- Eterm *call_time) /* out */
+ Eterm *call_time, /* out */
+ Eterm *call_memory) /* out */
{
const ErtsCodeInfo *ci;
Export e;
@@ -1077,9 +1086,12 @@ static int function_is_traced(Process *p,
if (erts_is_mtrace_break(&ep->info, ms_meta, tracer_pid_meta)) {
r |= FUNC_TRACE_META_TRACE;
}
- if (erts_is_time_break(p, &ep->info, call_time)) {
+ if (erts_is_call_break(p, 1, &ep->info, call_time)) {
r |= FUNC_TRACE_TIME_TRACE;
}
+ if (erts_is_call_break(p, 0, &ep->info, call_memory)) {
+ r |= FUNC_TRACE_MEMORY_TRACE;
+ }
return r ? r : FUNC_TRACE_UNTRACED;
}
}
@@ -1093,8 +1105,10 @@ static int function_is_traced(Process *p,
? FUNC_TRACE_META_TRACE : 0)
| (erts_is_count_break(ci, count)
? FUNC_TRACE_COUNT_TRACE : 0)
- | (erts_is_time_break(p, ci, call_time)
- ? FUNC_TRACE_TIME_TRACE : 0);
+ | (erts_is_call_break(p, 1, ci, call_time)
+ ? FUNC_TRACE_TIME_TRACE : 0)
+ | (erts_is_call_break(p, 0, ci, call_memory)
+ ? FUNC_TRACE_MEMORY_TRACE : 0);
return r ? r : FUNC_TRACE_UNTRACED;
}
@@ -1114,6 +1128,7 @@ trace_info_func(Process* p, Eterm func_spec, Eterm key)
Eterm retval = am_false;
ErtsTracer meta = erts_tracer_nil;
Eterm call_time = NIL;
+ Eterm call_memory = NIL;
int r;
@@ -1133,7 +1148,7 @@ trace_info_func(Process* p, Eterm func_spec, Eterm key)
mfa[1] = tp[2];
mfa[2] = signed_val(tp[3]);
- if ( (key == am_call_time) || (key == am_all)) {
+ if ( (key == am_call_time) || (key == am_call_memory) || (key == am_all)) {
erts_proc_unlock(p, ERTS_PROC_LOCK_MAIN);
erts_thr_progress_block();
erts_proc_lock(p, ERTS_PROC_LOCK_MAIN);
@@ -1141,10 +1156,10 @@ trace_info_func(Process* p, Eterm func_spec, Eterm key)
erts_mtx_lock(&erts_dirty_bp_ix_mtx);
- r = function_is_traced(p, mfa, &ms, &ms_meta, &meta, &count, &call_time);
+ r = function_is_traced(p, mfa, &ms, &ms_meta, &meta, &count, &call_time, &call_memory);
erts_mtx_unlock(&erts_dirty_bp_ix_mtx);
- if ( (key == am_call_time) || (key == am_all)) {
+ if ( (key == am_call_time) || (key == am_call_memory) || (key == am_all)) {
erts_thr_progress_unblock();
}
@@ -1206,10 +1221,18 @@ trace_info_func(Process* p, Eterm func_spec, Eterm key)
retval = call_time;
}
break;
+ case am_call_memory:
+ if (r & FUNC_TRACE_MEMORY_TRACE) {
+ retval = call_memory;
+ }
+ break;
case am_all: {
- Eterm match_spec_meta = am_false, c = am_false, t, ct = am_false,
- m = am_false;
+ Eterm match_spec_meta = am_false;
+ Eterm call_count = am_false;
+ Eterm t, m;
+ /* ToDo: Rewrite this to loop and reuse the above cases */
+
if (ms) {
match_spec = MatchSetGetSource(ms);
match_spec = copy_object(match_spec, p);
@@ -1222,19 +1245,24 @@ trace_info_func(Process* p, Eterm func_spec, Eterm key)
match_spec_meta = NIL;
}
if (r & FUNC_TRACE_COUNT_TRACE) {
- c = erts_make_integer(count, p);
+ call_count = erts_make_integer(count, p);
}
- if (r & FUNC_TRACE_TIME_TRACE) {
- ct = call_time;
+ if (!(r & FUNC_TRACE_TIME_TRACE)) {
+ call_time = am_false;
+ }
+ if (!(r & FUNC_TRACE_MEMORY_TRACE)) {
+ call_memory = am_false;
}
m = erts_tracer_to_term(p, meta);
- hp = HAlloc(p, (3+2)*6);
+ hp = HAlloc(p, (3+2)*7);
retval = NIL;
- t = TUPLE2(hp, am_call_count, c); hp += 3;
+ t = TUPLE2(hp, am_call_count, call_count); hp += 3;
retval = CONS(hp, t, retval); hp += 2;
- t = TUPLE2(hp, am_call_time, ct); hp += 3;
+ t = TUPLE2(hp, am_call_time, call_time); hp += 3;
+ retval = CONS(hp, t, retval); hp += 2;
+ t = TUPLE2(hp, am_call_memory, call_memory); hp += 3;
retval = CONS(hp, t, retval); hp += 2;
t = TUPLE2(hp, am_meta_match_spec, match_spec_meta); hp += 3;
retval = CONS(hp, t, retval); hp += 2;
@@ -1432,19 +1460,21 @@ erts_set_trace_pattern(Process*p, ErtsCodeMFA *mfa, int specified,
ErtsTracer meta_tracer, int is_blocking)
{
const ErtsCodeIndex code_ix = erts_active_code_ix();
- int matches = 0;
- int i;
- int n;
+ Uint i, n, matches;
BpFunction* fp;
erts_bp_match_export(&finish_bp.e, mfa, specified);
+
fp = finish_bp.e.matching;
n = finish_bp.e.matched;
+ matches = 0;
for (i = 0; i < n; i++) {
- ErtsCodeInfo *ci_rw = fp[i].ci_rw;
+ ErtsCodeInfo *ci_rw;
Export* ep;
+ /* Export entries are always writable, discard const. */
+ ci_rw = (ErtsCodeInfo *)fp[i].code_info;
ep = ErtsContainerStruct(ci_rw, Export, info);
if (ep->bif_number != -1) {
@@ -1504,6 +1534,9 @@ erts_set_trace_pattern(Process*p, ErtsCodeMFA *mfa, int specified,
if (flags.call_time) {
erts_set_time_break(&finish_bp.f, on);
}
+ if (flags.call_memory) {
+ erts_set_memory_break(&finish_bp.f, on);
+ }
}
} else {
if (flags.local) {
@@ -1518,6 +1551,9 @@ erts_set_trace_pattern(Process*p, ErtsCodeMFA *mfa, int specified,
if (flags.call_time) {
erts_clear_time_break(&finish_bp.f);
}
+ if (flags.call_memory) {
+ erts_clear_memory_break(&finish_bp.f);
+ }
}
finish_bp.current = 0;
@@ -1583,7 +1619,7 @@ consolidate_event_tracing(ErtsTracingEvent te[])
int
erts_finish_breakpointing(void)
{
- ERTS_LC_ASSERT(erts_has_code_write_permission());
+ ERTS_LC_ASSERT(erts_has_code_mod_permission());
/*
* Memory and instruction barriers will be issued for all schedulers
@@ -1648,13 +1684,17 @@ erts_finish_breakpointing(void)
* deallocate the GenericBp structs for them.
*/
clean_export_entries(&finish_bp.e);
- erts_consolidate_bp_data(&finish_bp.e, 0);
- erts_consolidate_bp_data(&finish_bp.f, 1);
+ erts_consolidate_export_bp_data(&finish_bp.e);
+ erts_consolidate_local_bp_data(&finish_bp.f);
erts_bp_free_matched_functions(&finish_bp.e);
erts_bp_free_matched_functions(&finish_bp.f);
consolidate_event_tracing(erts_send_tracing);
consolidate_event_tracing(erts_receive_tracing);
- return 0;
+ return 1;
+ case 4:
+ /* All schedulers have run a code barrier (or will as soon as they
+ * awaken) after updating all breakpoints, it's safe to return now. */
+ return 0;
default:
ASSERT(0);
}
@@ -1670,7 +1710,9 @@ install_exp_breakpoints(BpFunctions* f)
Uint i;
for (i = 0; i < ne; i++) {
- Export* ep = ErtsContainerStruct(fp[i].ci_rw, Export, info);
+ /* Export entries are always writable, discard const. */
+ ErtsCodeInfo *ci_rw = (ErtsCodeInfo*)fp[i].code_info;
+ Export* ep = ErtsContainerStruct(ci_rw, Export, info);
erts_activate_export_trampoline(ep, code_ix);
}
}
@@ -1684,7 +1726,9 @@ uninstall_exp_breakpoints(BpFunctions* f)
Uint i;
for (i = 0; i < ne; i++) {
- Export* ep = ErtsContainerStruct(fp[i].ci_rw, Export, info);
+ /* Export entries are always writable, discard const. */
+ ErtsCodeInfo *ci_rw = (ErtsCodeInfo*)fp[i].code_info;
+ Export* ep = ErtsContainerStruct(ci_rw, Export, info);
if (erts_is_export_trampoline_active(ep, code_ix)) {
ASSERT(BeamIsOpCode(ep->trampoline.common.op, op_trace_jump_W));
@@ -1703,7 +1747,9 @@ clean_export_entries(BpFunctions* f)
Uint i;
for (i = 0; i < ne; i++) {
- Export* ep = ErtsContainerStruct(fp[i].ci_rw, Export, info);
+ /* Export entries are always writable, discard const. */
+ ErtsCodeInfo *ci_rw = (ErtsCodeInfo*)fp[i].code_info;
+ Export* ep = ErtsContainerStruct(ci_rw, Export, info);
if (erts_is_export_trampoline_active(ep, code_ix)) {
continue;