/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
// Map from csu => set of immediate subclasses var subclasses = new Map();
// Map from csu => set of immediate superclasses var superclasses = new Map();
// Map from "csu.name:nargs" => set of full method name var virtualDefinitions = new Map();
// Every virtual method declaration, anywhere. // // Map from csu => Set of function-info. // function-info: { // name : simple string // typedfield : "name:nargs" ("mangled" field name) // field: full Field datastructure // annotations : Set of [annotation-name, annotation-value] 2-element arrays // inherited : whether the method is inherited from a base class // pureVirtual : whether the method is pure virtual on this CSU // dtor : if this is a virtual destructor with a definition in this class or // a superclass, then the full name of the definition as if it were defined // in this class. This is weird, but it's how gcc emits it. We will add a // synthetic call from this function to its immediate base classes' dtors, // so even if the function does not actually exist and is inherited from a // base class, we will get a path to the inherited function. (Regular // virtual methods are *not* claimed to exist when they don't.) // } var virtualDeclarations = new Map();
var virtualResolutionsSeen = new Set();
var ID = {
jscode: 1,
anyfunc: 2,
nogcfunc: 3,
gc: 4,
};
// map is a map from names to sets of entries. function addToNamedSet(map, name, entry)
{ if (!map.has(name))
map.set(name, new Set()); const s = map.get(name);
s.add(entry); return s;
}
// CSU is "Class/Struct/Union" function processCSU(csuName, csu)
{ if (!("FunctionField" in csu)) return;
for (const {Base} of (csu.CSUBaseClass || [])) {
addToNamedSet(subclasses, Base, csuName);
addToNamedSet(superclasses, csuName, Base);
}
for (const {Field, Variable} of csu.FunctionField) { // Virtual method const info = Field[0]; const name = info.Name[0]; const annotations = new Set(); const funcInfo = {
name,
typedfield: typedField(info),
field: info,
annotations,
inherited: (info.FieldCSU.Type.Name != csuName), // Always false for virtual dtors
pureVirtual: Boolean(Variable),
dtor: false,
};
if (Variable && isSyntheticVirtualDestructor(name)) { // This is one of gcc's artificial dtors.
funcInfo.dtor = Variable.Name[0];
funcInfo.pureVirtual = false;
}
addToNamedSet(virtualDeclarations, csuName, funcInfo); if ('Annotation' in info) { for (const {Name: [annType, annValue]} of info.Annotation) {
annotations.add([annType, annValue]);
}
}
if (Variable) { // Note: not dealing with overloading correctly. const name = Variable.Name[0];
addToNamedSet(virtualDefinitions, fieldKey(csuName, Field[0]), name);
}
}
}
// Return a list of all callees that the given edge might be a call to. Each // one is represented by an object with a 'kind' field that is one of // ('direct', 'field', 'resolved-field', 'indirect', 'unknown'), though note // that 'resolved-field' is really a global record of virtual method // resolutions, indepedent of this particular edge. function translateCallees(edge)
{ if (edge.Kind != "Call") return [];
// At some point, we were intentionally invoking invalid function pointers // (as in, a small integer cast to a function pointer type) to convey a // small amount of information in the crash address. if (callee.Kind == "Int") return []; // Intentional crash
assert(callee.Kind == "Drf");
let called = callee.Exp[0];
let indirection = 1; if (called.Kind == "Drf") { // This is probably a reference to a function pointer (`func*&`). It // would be possible to determine that for certain by looking up the // variable's type, which is doable but unnecessary. Indirect calls // are assumed to call anything (any function in the codebase) unless they // are annotated otherwise, and the `funkyName` annotation applies to // `(**funkyName)(args)` as well as `(*funkyName)(args)`, it's ok.
called = called.Exp[0];
indirection += 1;
}
if (called.Kind == "Var") { // indirect call through a variable. Note that the `indirection` field is // currently unused by the later analysis. It is the number of dereferences // applied to the variable before invoking the resulting function. // // The variable name passed through is the simplified one, since that is // what annotations.js uses and we don't want the annotation to be missed // if eg there is another variable of the same name in a sibling scope such // that the fully decorated name no longer matches. const [decorated, bare] = called.Variable.Name; return [{'kind': "indirect", 'variable': bare, indirection}];
}
// Return one 'field' callee record giving the full description of what's // happening here (which is either a virtual method call, or a call through // a function pointer stored in a field), and then boil the call down to a // synthetic function that incorporates both the name of the field and the // static type of whatever you're calling the method on. Both refer to the // same call; they're just different ways of describing it. const callees = []; const field = called.Field; const staticCSU = getFieldCallInstanceCSU(edge, field);
callees.push({'kind': "field", 'csu': field.FieldCSU.Type.Name, staticCSU, 'field': field.Name[0], 'fieldKey': fieldKey(staticCSU, field), 'isVirtual': ("FieldInstanceFunction" in field)});
callees.push({'kind': "direct", 'name': fieldKey(staticCSU, field)});
return callees;
}
function getCallees(body, edge, scopeAttrs, functionBodies) { const calls = [];
// getCallEdgeProperties can set the ATTR_REPLACED attribute, which // means that the call in the edge has been replaced by zero or // more edges to other functions. This is used when the original // edge will end up calling through a function pointer or something // (eg ~shared_ptr<T> calls a function pointer that can only be // T::~T()). The original call edges are left in the graph in case // they are useful for other purposes. for (const callee of translateCallees(edge)) { if (callee.kind != "direct") {
calls.push({ callee, attrs: scopeAttrs });
} else { const edgeInfo = getCallEdgeProperties(body, edge, callee.name, functionBodies); for (const extra of (edgeInfo.extraCalls || [])) {
calls.push({ attrs: scopeAttrs | extra.attrs, callee: { name: extra.name, 'kind': "direct", } });
}
calls.push({ callee, attrs: scopeAttrs | edgeInfo.attrs});
}
}
return calls;
}
function loadTypes(type_xdb_filename) { const xdb = xdbLibrary();
xdb.open(type_xdb_filename);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.