Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 33 additions & 30 deletions src/profile-logic/profile-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4660,6 +4660,35 @@ export function nudgeReturnAddresses(profile: Profile): Profile {
return newProfile;
}

/**
* The source of a frame with an address, which is what can prove to the
* symbolication API's /source/v1 that the source belongs to the library. Null
* when the frame has no address or its func no source.
*/
function _getAddressProvenSource(
frameTable: RawFrameTable,
funcTable: RawFuncTable,
frameIndex: IndexIntoFrameTable
): IndexIntoSourceTable | null {
if ((frameTable.flags[frameIndex] & FrameFlag.HasAddress) === 0) {
return null;
}
const funcIndex = frameTable.func[frameIndex];
if ((funcTable.flags[funcIndex] & FuncFlag.HasSource) === 0) {
return null;
}
return funcTable.source[funcIndex];
}

function _getAddressProofForFrame(
profile: Profile,
frameIndex: IndexIntoFrameTable
): AddressProof {
const { frameTable } = profile.shared;
const { debugName, breakpadId } = profile.libs[frameTable.lib[frameIndex]];
return { debugName, breakpadId, address: frameTable.address[frameIndex] };
}

/**
* Find the address and library (debugName, breakpadId) for any frame which
* was symbolicated to the given filename.
Expand All @@ -4668,41 +4697,15 @@ export function findAddressProofForFile(
profile: Profile,
sourceIndex: IndexIntoSourceTable
): AddressProof | null {
const { libs } = profile;
const { frameTable, funcTable } = profile.shared;
// Scan for the func manually rather than using `funcTable.source.indexOf`:
// the `source` column only carries a meaningful value for funcs which have
// the `HasSource` flag set, and holds an arbitrary value (usually zero) for
// all other funcs. An `indexOf` would happily match one of those.
let func = -1;
for (let i = 0; i < funcTable.length; i++) {
for (let frameIndex = 0; frameIndex < frameTable.length; frameIndex++) {
if (
(funcTable.flags[i] & FuncFlag.HasSource) !== 0 &&
funcTable.source[i] === sourceIndex
_getAddressProvenSource(frameTable, funcTable, frameIndex) === sourceIndex
) {
func = i;
break;
return _getAddressProofForFrame(profile, frameIndex);
}
}
if (func === -1) {
return null;
}
const frame = frameTable.func.indexOf(func);
if (frame === -1) {
return null;
}
if ((frameTable.flags[frame] & FrameFlag.HasAddress) === 0) {
return null;
}
const address = frameTable.address[frame];
const libIndex = frameTable.lib[frame];
const lib = libs[libIndex];
const { debugName, breakpadId } = lib;
return {
debugName,
breakpadId,
address,
};
return null;
}

/**
Expand Down
19 changes: 19 additions & 0 deletions src/test/unit/profile-data.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1546,6 +1546,25 @@ describe('findAddressProofForFile', function () {
);
expect(missingAddressProof).toBeNull();
});

it('finds an address for a file whose first frame has none', function () {
const { profile } = getProfileFromTextSamples(`
A[lib:XUL][file:a.cpp]
B[lib:XUL][file:a.cpp][address:20]
`);
const stringTable = StringTable.withBackingArray(
profile.shared.stringArray
);
const sourceIndex = profile.shared.sources.filename.indexOf(
stringTable.indexForString('a.cpp')
);

expect(findAddressProofForFile(profile, sourceIndex)).toEqual({
debugName: 'XUL',
breakpadId: 'SOMETHING_FAKE',
address: 0x20,
});
});
});

describe('calculateFunctionSizeLowerBound', function () {
Expand Down
Loading