Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 96a42c8

Browse files
committed
User trace feature.
1 parent 921c824 commit 96a42c8

1 file changed

Lines changed: 162 additions & 27 deletions

File tree

Python/ceval.c

Lines changed: 162 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
3636
#include "traceback.h"
3737

3838
#ifndef NDEBUG
39-
#define TRACE
39+
/* For debugging the interpreter: */
40+
#define LLTRACE 1 /* Low-level trace feature */
41+
#define CHECKEXC 1 /* Double-check exception checking */
4042
#endif
4143

4244
/* Forward declarations */
@@ -69,6 +71,7 @@ static int testbool();
6971
static int assign_subscript PROTO((object *, object *, object *));
7072
static int assign_slice PROTO((object *, object *, object *, object *));
7173
static int import_from PROTO((object *, object *, object *));
74+
static object *call_trace PROTO((object *, frameobject *, char *, object *));
7275

7376

7477
static frameobject *current_frame;
@@ -106,12 +109,12 @@ eval_code(co, globals, locals, arg)
106109
register object *u;
107110
register object *t;
108111
register frameobject *f; /* Current frame */
109-
int lineno; /* Current line number */
112+
object *trace; /* Trace function or NULL */
110113
object *retval; /* Return value iff why == WHY_RETURN */
111114
char *name; /* Name used by some instructions */
112115
FILE *fp; /* Used by print operations */
113-
#ifdef TRACE
114-
int trace = dictlookup(globals, "__trace__") != NULL;
116+
#ifdef LLTRACE
117+
int lltrace = dictlookup(globals, "__lltrace__") != NULL;
115118
#endif
116119

117120
/* Code access macros */
@@ -134,9 +137,9 @@ eval_code(co, globals, locals, arg)
134137
#define BASIC_PUSH(v) (*stack_pointer++ = (v))
135138
#define BASIC_POP() (*--stack_pointer)
136139

137-
#ifdef TRACE
138-
#define PUSH(v) (BASIC_PUSH(v), trace && prtrace(TOP(), "push"))
139-
#define POP() (trace && prtrace(TOP(), "pop"), BASIC_POP())
140+
#ifdef LLTRACE
141+
#define PUSH(v) (BASIC_PUSH(v), lltrace && prtrace(TOP(), "push"))
142+
#define POP() (lltrace && prtrace(TOP(), "pop"), BASIC_POP())
140143
#else
141144
#define PUSH(v) BASIC_PUSH(v)
142145
#define POP() BASIC_POP()
@@ -153,9 +156,37 @@ eval_code(co, globals, locals, arg)
153156
return NULL;
154157

155158
current_frame = f;
159+
160+
trace = sysget("trace");
161+
if (trace != NULL) {
162+
/* sys.trace, if defined, is a function that will
163+
be called on *every* entry to a code block.
164+
Its return value, if not None, is a function that
165+
will be called at the start of each executed line
166+
of code. (Actually, the function must return
167+
itself in order to continue tracing.)
168+
The trace functions are called with three arguments:
169+
a pointer to the current frame, a string indicating
170+
why the function is called, and an argument which
171+
depends on the situation. The global trace function
172+
(sys.trace) is also called whenever an exception
173+
is detected. */
174+
trace = call_trace(trace, f, "call", arg);
175+
if (trace == NULL) {
176+
/* Trace function raised an error */
177+
sysset("trace", (object *)NULL);
178+
current_frame = f->f_back;
179+
DECREF(f);
180+
return NULL;
181+
}
182+
if (trace == None) {
183+
/* No need to trace this code block */
184+
DECREF(trace);
185+
trace = NULL;
186+
}
187+
}
156188

157189
next_instr = GETUSTRINGVALUE(f->f_code->co_code);
158-
159190
stack_pointer = f->f_valuestack;
160191

161192
if (arg != NULL) {
@@ -166,7 +197,6 @@ eval_code(co, globals, locals, arg)
166197
why = WHY_NOT;
167198
err = 0;
168199
x = None; /* Not a reference, just anything non-NULL */
169-
lineno = -1;
170200

171201
for (;;) {
172202
static int ticker;
@@ -178,7 +208,6 @@ eval_code(co, globals, locals, arg)
178208
if (intrcheck()) {
179209
err_set(KeyboardInterrupt);
180210
why = WHY_EXCEPTION;
181-
tb_here(f, INSTR_OFFSET(), lineno);
182211
goto on_error;
183212
}
184213
}
@@ -189,10 +218,10 @@ eval_code(co, globals, locals, arg)
189218
if (HAS_ARG(opcode))
190219
oparg = NEXTARG();
191220

192-
#ifdef TRACE
221+
#ifdef LLTRACE
193222
/* Instruction tracing */
194223

195-
if (trace) {
224+
if (lltrace) {
196225
if (HAS_ARG(opcode)) {
197226
printf("%d: %d, %d\n",
198227
(int) (INSTR_OFFSET() - 3),
@@ -273,6 +302,7 @@ eval_code(co, globals, locals, arg)
273302

274303
case UNARY_CALL:
275304
v = POP();
305+
f->f_lasti = INSTR_OFFSET() - 1; /* For tracing */
276306
x = call_object(v, (object *)NULL);
277307
DECREF(v);
278308
PUSH(x);
@@ -342,6 +372,7 @@ eval_code(co, globals, locals, arg)
342372
case BINARY_CALL:
343373
w = POP();
344374
v = POP();
375+
f->f_lasti = INSTR_OFFSET() - 1; /* For tracing */
345376
x = call_object(v, w);
346377
DECREF(v);
347378
DECREF(w);
@@ -921,17 +952,31 @@ eval_code(co, globals, locals, arg)
921952
break;
922953

923954
case SET_LINENO:
924-
#ifdef TRACE
925-
if (trace)
955+
#ifdef LLTRACE
956+
if (lltrace)
926957
printf("--- Line %d ---\n", oparg);
927958
#endif
928-
lineno = oparg;
959+
f->f_lineno = oparg;
960+
if (trace != NULL) {
961+
/* Trace each line of code reached */
962+
f->f_lasti = INSTR_OFFSET();
963+
x = call_trace(trace, f, "line", None);
964+
/* The trace function must return itself
965+
in order to continue tracing */
966+
DECREF(trace);
967+
if (x == None) {
968+
DECREF(x);
969+
trace = NULL;
970+
}
971+
else
972+
trace = x;
973+
}
929974
break;
930975

931976
default:
932977
fprintf(stderr,
933978
"XXX lineno: %d, opcode: %d\n",
934-
lineno, opcode);
979+
f->f_lineno, opcode);
935980
err_setstr(SystemError, "eval_code: unknown opcode");
936981
why = WHY_EXCEPTION;
937982
break;
@@ -950,7 +995,7 @@ eval_code(co, globals, locals, arg)
950995
err = 0;
951996
}
952997

953-
#ifndef NDEBUG
998+
#ifndef CHECKEXC
954999
/* Double-check exception status */
9551000

9561001
if (why == WHY_EXCEPTION || why == WHY_RERAISE) {
@@ -971,10 +1016,49 @@ eval_code(co, globals, locals, arg)
9711016
/* Log traceback info if this is a real exception */
9721017

9731018
if (why == WHY_EXCEPTION) {
974-
int lasti = INSTR_OFFSET() - 1;
1019+
f->f_lasti = INSTR_OFFSET() - 1;
9751020
if (HAS_ARG(opcode))
976-
lasti -= 2;
977-
tb_here(f, lasti, lineno);
1021+
f->f_lasti -= 2;
1022+
tb_here(f);
1023+
1024+
if (trace)
1025+
v = trace;
1026+
else
1027+
v = sysget("trace");
1028+
if (v) {
1029+
object *type, *value, *traceback, *arg;
1030+
err_get(&type, &value);
1031+
traceback = tb_fetch();
1032+
arg = newtupleobject(3);
1033+
if (arg == NULL)
1034+
err_clear();
1035+
else {
1036+
settupleitem(arg, 0, type);
1037+
settupleitem(arg, 1, value);
1038+
settupleitem(arg, 2, traceback);
1039+
}
1040+
v = call_trace(v, f, "exception", arg);
1041+
if (v == NULL) {
1042+
/* Trace function raised error */
1043+
tb_here(f);
1044+
sysset("trace", (object *)NULL);
1045+
XDECREF(trace);
1046+
trace = NULL;
1047+
}
1048+
else {
1049+
/* Restore original exception */
1050+
err_setval(type, value);
1051+
tb_store(traceback);
1052+
if (v == None)
1053+
DECREF(v);
1054+
else {
1055+
/* Set trace function */
1056+
XDECREF(trace);
1057+
trace = v;
1058+
}
1059+
}
1060+
XDECREF(arg);
1061+
}
9781062
}
9791063

9801064
/* For the rest, treat WHY_RERAISE as WHY_EXCEPTION */
@@ -1012,9 +1096,7 @@ eval_code(co, globals, locals, arg)
10121096
Python main loop. Don't do
10131097
this for 'finally'. */
10141098
if (b->b_type == SETUP_EXCEPT) {
1015-
#if 1 /* Oops, this breaks too many things */
10161099
sysset("exc_traceback", v);
1017-
#endif
10181100
sysset("exc_value", val);
10191101
sysset("exc_type", exc);
10201102
err_clear();
@@ -1049,18 +1131,31 @@ eval_code(co, globals, locals, arg)
10491131
XDECREF(v);
10501132
}
10511133

1134+
if (why != WHY_RETURN)
1135+
retval = NULL;
1136+
1137+
if (trace) {
1138+
if (why == WHY_RETURN) {
1139+
x = call_trace(trace, f, "return", retval);
1140+
if (x == NULL) {
1141+
XDECREF(retval);
1142+
retval = NULL;
1143+
}
1144+
else
1145+
DECREF(x);
1146+
}
1147+
DECREF(trace);
1148+
}
1149+
10521150
/* Restore previous frame and release the current one */
10531151

10541152
current_frame = f->f_back;
10551153
DECREF(f);
10561154

1057-
if (why == WHY_RETURN)
1058-
return retval;
1059-
else
1060-
return NULL;
1155+
return retval;
10611156
}
10621157

1063-
#ifdef TRACE
1158+
#ifdef LLTRACE
10641159
static int
10651160
prtrace(v, str)
10661161
object *v;
@@ -1073,6 +1168,46 @@ prtrace(v, str)
10731168
}
10741169
#endif
10751170

1171+
static object *
1172+
call_trace(trace, f, msg, arg)
1173+
object *trace;
1174+
frameobject *f;
1175+
char *msg;
1176+
object *arg;
1177+
{
1178+
object *arglist, *what, *res;
1179+
static int tracing = 0;
1180+
1181+
if (tracing) {
1182+
/* Don't trace the trace code! */
1183+
INCREF(None);
1184+
return None;
1185+
}
1186+
1187+
arglist = newtupleobject(3);
1188+
if (arglist == NULL)
1189+
return NULL;
1190+
what = newstringobject(msg);
1191+
if (what == NULL) {
1192+
DECREF(arglist);
1193+
return NULL;
1194+
}
1195+
INCREF(f);
1196+
if (arg == NULL)
1197+
arg = None;
1198+
INCREF(arg);
1199+
settupleitem(arglist, 0, (object *)f);
1200+
settupleitem(arglist, 1, what);
1201+
settupleitem(arglist, 2, arg);
1202+
tracing++;
1203+
res = call_object(trace, arglist);
1204+
tracing--;
1205+
if (res == NULL)
1206+
tb_here(f);
1207+
DECREF(arglist);
1208+
return res;
1209+
}
1210+
10761211
object *
10771212
getlocals()
10781213
{

0 commit comments

Comments
 (0)