Index: funcs/func_channel.c
===================================================================
--- funcs/func_channel.c	(revision 89277)
+++ funcs/func_channel.c	(working copy)
@@ -77,6 +77,8 @@
 		ast_copy_string(buf, ast_getformatname(chan->readformat), len);
 	else if (!strcasecmp(data, "audiowriteformat"))
 		ast_copy_string(buf, ast_getformatname(chan->writeformat), len);
+	else if (!strcasecmp(data, "trace"))
+		locked_copy_string(chan, buf, chan->trace_enabled ? "1" : "0", len);
 	else if (!strcasecmp(data, "tonezone") && chan->zone)
 		locked_copy_string(chan, buf, chan->zone->country, len);
 	else if (!strcasecmp(data, "language"))
@@ -111,7 +113,15 @@
 		locked_string_field_set(chan, language, value);
 	else if (!strcasecmp(data, "musicclass"))
 		locked_string_field_set(chan, musicclass, value);
-	else if (!strcasecmp(data, "tonezone")) {
+	else if (!strcasecmp(data, "trace")) {
+		if (!strcmp(value, "1") && !chan->trace_enabled ) {
+			chan->trace_enabled = 1;
+			/* we call this here to save the current context in the trace */
+			ast_channel_update_trace(chan);
+		}	
+		else
+			chan->trace_enabled = 0;
+	} else if (!strcasecmp(data, "tonezone")) {
 		struct ind_tone_zone *new_zone;
 		if (!(new_zone = ast_get_indication_zone(value))) {
 			ast_log(LOG_ERROR, "Unknown country code '%s' for tonezone. Check indications.conf for available country codes.\n", value);
@@ -162,6 +172,7 @@
 		"R/W	tonezone           zone for indications played\n"
 		"R/W	txgain             set txgain level on channel drivers that support it\n"
 		"R/O	videonativeformat  format used natively for video\n"
+		"R/W	trace              whether or not context tracing is enabled\n"
 		"\n"
 		"chan_sip provides the following additional options:\n"
 		"R/O    rtpqos             Get QOS information about the RTP stream\n"
Index: include/asterisk/channel.h
===================================================================
--- include/asterisk/channel.h	(revision 89277)
+++ include/asterisk/channel.h	(working copy)
@@ -380,6 +380,16 @@
 	AST_STATE_MUTE = (1 << 16),
 };
 
+/*! \brief 
+	Structure to save contexts where an ast_chan has been into
+*/
+struct ast_chan_trace {
+	char context[AST_MAX_CONTEXT];			/*!< Dialplan: Current extension context */
+	char exten[AST_MAX_EXTENSION];			/*!< Dialplan: Current extension number */
+	int priority;					/*!< Dialplan: Current extension priority */
+	AST_LIST_ENTRY(ast_chan_trace) entry;           /*!< next trace entry */
+};
+
 /*! \brief Main Channel structure associated with a channel. 
  * This is the side of it mostly used by the pbx and call management.
  *
@@ -444,6 +454,8 @@
 	char dtmfq[AST_MAX_EXTENSION];			/*!< Any/all queued DTMF characters */
 	struct ast_frame dtmff;				/*!< DTMF frame */
 
+	AST_LIST_HEAD_NOLOCK(, ast_chan_trace) trace;   /*!< DialPlan: trace contexts the channel has been into */
+	int trace_enabled;                              /*!< DialPlan: 1 if trace contexts is enabled */
 	char context[AST_MAX_CONTEXT];			/*!< Dialplan: Current extension context */
 	char exten[AST_MAX_EXTENSION];			/*!< Dialplan: Current extension number */
 	int priority;					/*!< Dialplan: Current extension priority */
@@ -644,6 +656,9 @@
 /*! \brief Remove a datastore from a channel */
 int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore);
 
+/*! \brief Update context trace on the given channel */
+int ast_channel_update_trace(struct ast_channel *chan);
+
 /*! \brief Find a datastore on a channel */
 struct ast_datastore *ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid);
 
Index: include/asterisk/pbx.h
===================================================================
--- include/asterisk/pbx.h	(revision 89277)
+++ include/asterisk/pbx.h	(working copy)
@@ -860,6 +860,11 @@
 /*!
  * \note Will lock the channel.
  */
+int pbx_builtin_serialize_trace(struct ast_channel *chan, struct ast_str **buf);
+
+/*!
+ * \note Will lock the channel.
+ */
 const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name);
 
 /*!
Index: main/channel.c
===================================================================
--- main/channel.c	(revision 89277)
+++ main/channel.c	(working copy)
@@ -1097,6 +1097,7 @@
 	struct ast_frame *f;
 	struct varshead *headp;
 	struct ast_datastore *datastore = NULL;
+	struct ast_chan_trace *ctrace;
 	char name[AST_CHANNEL_NAME];
 	
 	headp=&chan->varshead;
@@ -1171,6 +1172,10 @@
 	/* Destroy the jitterbuffer */
 	ast_jb_destroy(chan);
 
+	/* remove traces */
+	while ((ctrace = AST_LIST_REMOVE_HEAD(&chan->trace, entry))) 
+		ast_free(ctrace);
+
 	ast_string_field_free_memory(chan);
 	ast_free(chan);
 	AST_RWLIST_UNLOCK(&channels);
@@ -1390,6 +1395,32 @@
 	clone->rawreadformat = clone->nativeformats;
 }
 
+/*! \brief Update context trace on channel */
+int ast_channel_update_trace(struct ast_channel *chan)
+{
+	struct ast_chan_trace *ctrace;
+	/* if we already started the trace and the last context does not match the current one
+	   or we have trace enabled and no context saved so far, save the context */
+	if ( ( !AST_LIST_EMPTY(&chan->trace) && strcasecmp(AST_LIST_FIRST(&chan->trace)->context, chan->context) ) || ( AST_LIST_EMPTY(&chan->trace) ) ) {
+		/* some logging */
+		if ( AST_LIST_EMPTY(&chan->trace) )
+			ast_log(LOG_DEBUG, "setting initial context to %s\n", chan->context);
+		else
+			ast_log(LOG_DEBUG, "changing trace context from %s to %s\n", AST_LIST_FIRST(&chan->trace)->context, chan->context);
+
+		/* alloc or bail out */
+		ctrace = ast_malloc(sizeof(*ctrace));
+		if ( !ctrace )
+			return -1;
+		/* real work, save the new location in the trace */
+		ast_copy_string(ctrace->context, chan->context, sizeof(ctrace->context));
+		ast_copy_string(ctrace->exten, chan->exten, sizeof(ctrace->exten));
+		ctrace->priority = chan->priority;
+		AST_LIST_INSERT_HEAD(&chan->trace, ctrace, entry);
+	}
+	return 0;
+}
+
 /*! \brief Hangup a channel */
 int ast_hangup(struct ast_channel *chan)
 {
@@ -3618,6 +3649,9 @@
 		}
 	}
 
+	/* Get the trace list. */
+	AST_LIST_APPEND_LIST(&original->trace, &clone->trace, entry);
+
 	/* Swap the raw formats */
 	x = original->rawreadformat;
 	original->rawreadformat = clone->rawreadformat;
Index: main/cli.c
===================================================================
--- main/cli.c	(revision 89277)
+++ main/cli.c	(working copy)
@@ -1013,6 +1013,9 @@
 		ast_cli(a->fd,"      Variables:\n%s\n", out->str);
 	if (c->cdr && ast_cdr_serialize_variables(c->cdr, &out, '=', '\n', 1))
 		ast_cli(a->fd,"  CDR Variables:\n%s\n", out->str);
+	ast_cli(a->fd, "  Context Trace: %s\n", c->trace_enabled ? "Enabled" : "Not Enabled");
+	if (pbx_builtin_serialize_trace(c, &out))
+		ast_cli(a->fd, "          Trace:\n%s\n", out->str);
 	
 	ast_channel_unlock(c);
 	return CLI_SUCCESS;
Index: main/pbx.c
===================================================================
--- main/pbx.c	(revision 89277)
+++ main/pbx.c	(working copy)
@@ -2500,6 +2500,9 @@
 				ast_copy_string(c->exten, exten, sizeof(c->exten));
 			c->priority = priority;
 			pbx_substitute_variables(passdata, sizeof(passdata), c, e);
+
+			if ( c->trace_enabled ) ast_channel_update_trace(c);
+
 			if (option_debug) {
 				char atmp[80];
 				char atmp2[EXT_DATA_SIZE+100];
@@ -6717,6 +6720,30 @@
 	return total;
 }
 
+int pbx_builtin_serialize_trace(struct ast_channel *chan, struct ast_str **buf)
+{
+	struct ast_chan_trace *ctrace;
+	int total = 0;
+	if ( !chan )
+		return 0;
+	(*buf)->used = 0;
+	(*buf)->str[0] = '\0';
+
+	ast_channel_lock(chan);
+
+	AST_LIST_TRAVERSE(&chan->trace, ctrace, entry) {
+		if(ast_str_append(buf, 0, "[%d] => %s, %s, %d\n", total, ctrace->context, ctrace->exten, ctrace->priority) < 0) {
+			ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
+			break;
+		} else
+			total++;
+	}
+
+	ast_channel_unlock(chan);
+
+	return total;
+}
+
 const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
 {
 	struct ast_var_t *variables;
