/** * Displays a MUF Backtrace message. * * This is used when a MUF program is aborted, if someone who has 'controls' * permissions was running it, or if you type 'where' in the debugger. * Shows a fairly straight forward backtrace, going 'count' deep. If * 'count' is 0, it will display up to STACK_SIZE depth. * * @param player the player getting the backtrace * @param program the program being backtraced * @param count the depth of the trace, or 0 for STACK_SIZE * @param fr the frame pointer */ void muf_backtrace(dbref player, dbref program, int count, struct frame *fr) { char buf2[BUFFER_LEN]; char buf3[BUFFER_LEN]; char *ptr; dbref ref; int i, j, cnt, flag; struct inst *pinst, *lastinst; int lev; notify_nolisten(player, "\033[1;33;40mSystem stack backtrace:\033[0m", 1); i = count; if (!i) i = STACK_SIZE; ref = program; pinst = NULL; j = fr->system.top + 1; /* * i is our depth; iterate until we've run out of depth or we have * broken out of the loop */ while (j > 1 && i-- > 0) { cnt = 0; do { lastinst = pinst; if (--j == fr->system.top) { pinst = fr->pc; } else { ref = fr->system.st[j].progref; pinst = fr->system.st[j].offset; } ptr = unparse_sysreturn(&ref, pinst); cnt++; } while (pinst == lastinst && j > 1); if (cnt > 1) { notifyf_nolisten(player, " [repeats %d times]", cnt); } lev = fr->system.top - j; if (ptr) { int snplen; char *bufend = buf2; struct inst *fntop = fr->pc; struct inst *varinst; while (fntop->type != PROG_FUNCTION) fntop--; snplen = snprintf(buf2, sizeof(buf2), "%.512s\033[1m(\033[0m", ptr); if (snplen == -1) { buf2[sizeof(buf2) - 1] = '\0'; snplen = sizeof(buf2) - 1; } bufend += snplen; for (int k = 0; k < fntop->data.mufproc->args; k++) { const char *nam = scopedvar_getname(fr, lev, k); char *val; if (!nam) { break; } varinst = scopedvar_get(fr, lev, k); val = insttotext(fr, lev, varinst, buf3, sizeof(buf3), 30, program, 1); if (k) { bufend += snprintf(bufend, buf2 - bufend - 18, "\033[1m, %s=\033[0m%s", nam, val); } else { bufend += snprintf(bufend, buf2 - bufend - 18, "\033[1m%s=\033[0m%s", nam, val); } } ptr = buf2; } if (pinst != lastinst) { notifyf_nolisten(player, "\033[1;33;40m%3d)\033[0m \033[1m%s(#%d)\033[0m %s:", lev, NAME(ref), ref, ptr); flag = ((FLAGS(player) & INTERNAL) ? 1 : 0); FLAGS(player) &= ~INTERNAL; list_proglines(player, ref, fr, pinst->line, 0); if (flag) { FLAGS(player) |= INTERNAL; } } } notify_nolisten(player, "\033[1;33;40m*done*\033[0m", 1); }
void muf_backtrace(dbref player, dbref program, int count, struct frame *fr) { char buf[BUFFER_LEN]; char buf2[BUFFER_LEN]; char buf3[BUFFER_LEN]; char *ptr; dbref ref; int i, j, cnt, flag; struct inst *pinst, *lastinst; int lev; anotify_nolisten(player, CINFO "System stack backtrace:", 1); i = count; if (!i) i = STACK_SIZE; ref = program; pinst = NULL; j = fr->system.top + 1; while (j > 1 && i-- > 0) { cnt = 0; do { lastinst = pinst; if (--j == fr->system.top) { pinst = fr->pc + 1; } else { ref = fr->system.st[j].progref; pinst = fr->system.st[j].offset; } ptr = unparse_sysreturn(&ref, pinst); cnt++; } while (pinst == lastinst && j > 1); if (cnt > 1) { sprintf(buf, " [repeats %d times]", cnt); notify_nolisten(player, buf, 1); } lev = fr->system.top - j; if (ptr) { int k; char *bufend = buf2; struct inst *fntop = fr->pc; struct inst *varinst; while (fntop->type != PROG_FUNCTION) --fntop; bufend += sprintf(buf2, "%.512s" SYSWHITE "(" SYSNORMAL, ptr); for (k = 0; k < fntop->data.mufproc->args; ++k) { const char *nam = scopedvar_getname(fr, lev, k); char *val; const char *fmt; if (!nam) { break; } varinst = scopedvar_get(fr, lev, k); val = insttotext(fr, lev, varinst, buf3, sizeof(buf3), 30, program); if (k) { fmt = SYSWHITE ", %s=" SYSNORMAL "%s"; } else { fmt = SYSWHITE "%s=" SYSNORMAL "%s"; } bufend += snprintf(bufend, buf2 - bufend - 18, fmt, nam, val); } bufend += snprintf(bufend, buf2 - bufend - 1, SYSWHITE ")" SYSNORMAL, ptr); ptr = buf2; } if (pinst != lastinst) { sprintf(buf, "%3d) %s(#%d) %s:", j, NAME(ref), ref, ptr); notify_nolisten(player, buf, 1); flag = ((FLAGS(player) & INTERNAL) ? 1 : 0); FLAGS(player) &= ~INTERNAL; list_proglines(player, ref, fr, (pinst - 1)->line, 0); if (flag) { FLAGS(player) |= INTERNAL; } } } anotify_nolisten(player, CINFO "Done.", 1); }