ObjectData *FrameInjection::GetThis(bool skip /* = false */) { FrameInjection *t = ThreadInfo::s_threadInfo->m_top; if (t && skip) { t = t->m_prev; } if (t) { return t->getObjectV(); } return NULL; }
String FrameInjection::GetContainingFileName(bool skip /* = false */) { FrameInjection *t = ThreadInfo::s_threadInfo->m_top; if (t && skip) { t = t->m_prev; } if (t) { return t->getFileName(); } return ""; }
static String get_current_alias() { DECLARE_THREAD_INFO; FrameInjection *fi; for (fi = info->m_top; fi; fi= fi->getPrev()) { if (fi->isEvalFrame()) { break; } } EvalFrameInjection *efi = static_cast<EvalFrameInjection*>(fi); return (efi) ? efi->getEnv().getCalleeAlias() : String(); }
void eval_set_callee_alias(CStrRef alias) { DECLARE_THREAD_INFO; FrameInjection *fi; for (fi = info->m_top; fi; fi= fi->getPrev()) { if (fi->isEvalFrame()) { break; } } EvalFrameInjection *efi = static_cast<EvalFrameInjection*>(fi); if (efi) efi->getEnv().setCalleeAlias(alias); }
FrameInjection *FrameInjection::GetStackFrame(int level) { FrameInjection *frame = ThreadInfo::s_threadInfo->m_top; for (int i = 0; i < level && frame; i++) { while (frame && (frame->m_flags & PseudoMain)) { frame = frame->getPrev(); } if (frame) { frame = frame->getPrev(); } } return frame; }
CStrRef FrameInjection::GetStaticClassName(ThreadInfo *info) { ASSERT(info); for (FrameInjection *t = info->m_top; t; t = t->m_prev) { if (t != info->m_top) { if (t->m_staticClass) return *t->m_staticClass; } ObjectData *obj = t->getObjectV(); if (obj) { return obj->o_getClassName(); } } return empty_string; }
Eval::VariableEnvironment * FrameInjection::GetVariableEnvironment(bool skip /* = false */) { FrameInjection *t = ThreadInfo::s_threadInfo->m_top; if (skip && t) { t = t->m_prev; } if (t && t->isEvalFrame()) { Eval::EvalFrameInjection* efi = static_cast<Eval::EvalFrameInjection*>(t); return &(efi->getEnv()); } return NULL; }
bool CmdVariable::onServer(DebuggerProxy *proxy) { FrameInjection *frame = ThreadInfo::s_threadInfo->m_top; for (int i = 0; i < m_frame && frame; i++) { frame = frame->getPrev(); } m_global = (!frame || !frame->getPrev()); if (frame) { EvalFrameInjection *eframe = dynamic_cast<EvalFrameInjection*>(frame); if (eframe) { m_variables = eframe->getEnv().getDefinedVariables(); m_variables.remove("GLOBALS"); } } return proxy->send(this); }
CStrRef FrameInjection::GetStaticClassName(ThreadInfo *info) { ASSERT(info); for (FrameInjection *t = info->m_top; t; t = t->m_prev) { if (t != info->m_top) { if (t->m_staticClass) return *t->m_staticClass; } ObjectData *obj = t->getObjectV(); if (obj) { return obj->o_getClassName(); } if (!(t->m_flags & (PseudoMain|BuiltinFunction|StaticMethod|ObjectMethod))) { break; } } return empty_string; }
CStrRef FrameInjection::GetClassName(bool skip /* = false */) { FrameInjection *t = ThreadInfo::s_threadInfo->m_top; if (t && skip) { t = t->m_prev; } // If we have included a file inside a class method or called a builtin // function, we should walk up to find that class if (t) { while (t->m_prev && t->getClassName().empty() && t->m_flags & (PseudoMain | BuiltinFunction)) { t = t->m_prev; } CStrRef name = t->getClassName(); if (!name.empty()) { return name; } } return empty_string; }
bool eval_get_call_info_hook(const CallInfo *&ci, void *&extra, const char *s, int64 hash /* = -1 */) { const Eval::Function *fs = Eval::RequestEvalState::findFunction(s); if (fs) { ci = fs->getCallInfo(); if (extra) { DECLARE_THREAD_INFO; EvalFrameInjection *efi = NULL; for (FrameInjection *fi = info->m_top; fi; fi= fi->getPrev()) { efi = dynamic_cast<EvalFrameInjection*>(fi); if (efi) break; } ASSERT(efi); efi->getEnv().setClosure(extra); } extra = (void*)fs; return true; } return false; }
Array FrameInjection::GetBacktrace(bool skip /* = false */, bool withSelf /* = false */, bool withThis /* = true */) { Array bt = Array::Create(); FrameInjection *t = ThreadInfo::s_threadInfo->m_top; if (skip && t) { t = t->m_prev; } // This is used by onError with extended exceptions if (withSelf && t) { String filename = t->getFileName(); // If the top frame is not an extension function, // add it to the trace if (filename != "") { Array frame = Array::Create(); frame.set(s_file, filename, true); frame.set(s_line, t->m_line, true); bt.append(frame); } } while (t) { Array frame = Array::Create(); if (t->m_prev) { String file = t->m_prev->getFileName(); if (!file.empty() && t->m_prev->m_line) { frame.set(s_file, file, true); frame.set(s_line, t->m_prev->m_line, true); } } else if (t->m_flags & PseudoMain) { // Stop at top, don't include top file break; } if (t->m_flags & PseudoMain) { frame.set(s_function, "include", true); frame.set(s_args, Array::Create(t->getFileName()), true); } else { const char *c = strstr(t->m_name, "::"); if (c) { frame.set(s_function, String(c + 2), true); frame.set(s_class, t->m_class->copy(), true); if (!t->m_object.isNull()) { if (withThis) { frame.set(s_object, t->m_object, true); } frame.set(s_type, "->", true); } else { frame.set(s_type, "::", true); } } else { frame.set(s_function, t->m_name, true); } Array args = t->getArgs(); if (!args.isNull()) { frame.set(s_args, args, true); } else { frame.set(s_args, Array::Create(), true); } } bt.append(frame); t = t->m_prev; } return bt; }
Array FrameInjection::GetBacktrace(bool skip /* = false */, bool withSelf /* = false */, bool withThis /* = true */) { Array bt = Array::Create(); FrameInjection *t = ThreadInfo::s_threadInfo->m_top; if (skip && t) { t = t->m_prev; } // This is used by onError with extended exceptions if (withSelf && t) { String filename = t->getFileName(); // If the top frame is not an extension function, and has actually been // entered (i.e. has a real line number) add it to the trace if (filename != "" && t->m_line != 0) { Array frame = Array::Create(); frame.set(s_file, filename, true); frame.set(s_line, t->m_line, true); bt.append(frame); } } Array sbt = bt; FrameInjection *st = t; while (t && (RuntimeOption::InjectedStackTraceLimit < 0 || bt.size() < RuntimeOption::InjectedStackTraceLimit)) { Array frame = t->getStackFrame(withSelf, withThis); if (frame.isNull()) return bt; bt.append(frame); t = t->m_prev; } if (!t) return bt; // The stack depth has exceeded the limit. Re-construct bt to include the // top and bottom frames. This is considered more useful in cases such as // infinite recursion. ASSERT(bt.size() == RuntimeOption::InjectedStackTraceLimit); int half = RuntimeOption::InjectedStackTraceLimit / 2; // start over, get the top half bt = sbt; t = st; while (t && bt.size() < half) { Array frame = t->getStackFrame(withSelf, withThis); if (frame.isNull()) assert(false); bt.append(frame); t = t->m_prev; } // then the bottom half std::vector<FrameInjection *> remainingFrames; while (t) { if (!t->m_prev && (t->m_flags & PseudoMain)) break; remainingFrames.push_back(t); t = t->m_prev; } int remaining = remainingFrames.size(); int omitted = remaining - half; assert(omitted >= 0); if (omitted > 0) { std::string tmp("(...) "); tmp += boost::lexical_cast<std::string>(omitted) + " omitted frame" + ((omitted > 1) ? "s" : ""); Array frame; frame.set(s_function, tmp); bt.append(frame); } for (int i = omitted; i < remaining; i++) { Array frame = remainingFrames[i]->getStackFrame(withSelf, withThis); if (frame.isNull()) assert(false); bt.append(frame); } return bt; }