This commit is contained in:
Jamie Wong 2024-03-09 16:02:00 +08:00 committed by GitHub
commit 911638f6e7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 62 additions and 31 deletions

View File

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<ufwb version="1.17">
<grammar name="INDEX grammar" start="id:10" author="Jamie Wong" fileextension="index">
<grammar name="INDEX grammar" start="id:43" author="Jamie Wong" fileextension="index">
<description>Grammar for INDEX files</description>
<structure name="integeruniquer.index file" id="10" encoding="ISO_8859-1:1987" endian="big" signed="no">
<binary name="Header" id="12" length="32"/>
<structure name="Entry" id="16" length="8" repeatmax="-1">
<number name="ByteOffset" id="15" type="integer" length="4" endian="little"/>
<number name="MegabyteOffset" id="18" type="integer" length="4" endian="little"/>
<structure name="integeruniquer.index file" id="43" encoding="ISO_8859-1:1987" endian="big" signed="no">
<binary name="Header" id="44" length="32"/>
<structure name="Entry" id="45" length="8" repeatmax="-1">
<number name="ByteOffset" id="46" fillcolor="FFB598" type="integer" length="4" endian="little"/>
<number name="MegabyteOffset" id="47" fillcolor="A0FF7B" type="integer" length="4" endian="little"/>
</structure>
</structure>
</grammar>

View File

@ -1,21 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<ufwb version="1.17">
<grammar name="time-sample bulkstore" start="id:1" author="Jamie Wong" fileextension="bin" uti="com.apple.macbinary-archive">
<grammar name="time-sample bulkstore" start="id:17" author="Jamie Wong" fileextension="bin" uti="com.apple.macbinary-archive">
<description>Grammar for BIN files</description>
<structure name="time-sample bulkstore" id="1" length="0" encoding="ISO_8859-1:1987" endian="little" signed="no">
<structure name="Header" id="2" length="Size" endian="little">
<binary name="???0" id="3" length="4"/>
<number name="???1" id="4" type="integer" length="4"/>
<number name="???2" id="5" type="integer" length="4"/>
<number name="Size" id="6" type="integer" length="4"/>
<number name="BytesPerEntry" id="7" type="integer" length="2"/>
<number name="???4" id="8" type="integer" length="4"/>
<number name="???5" id="9" type="integer" length="4"/>
<structure name="time-sample bulkstore" id="17" length="0" encoding="ISO_8859-1:1987" endian="little" signed="no">
<structure name="Header" id="18" length="Size" endian="little">
<binary name="???0" id="19" length="4"/>
<number name="???1" id="20" type="integer" length="4"/>
<number name="???2" id="21" type="integer" length="4"/>
<number name="Size" id="22" type="integer" length="4"/>
<number name="BytesPerEntry" id="23" type="integer" length="2"/>
<number name="???4" id="24" type="integer" length="4"/>
<number name="???5" id="25" type="integer" length="4"/>
</structure>
<structure name="Data" id="11" length="BytesPerEntry" repeatmax="-1">
<number name="Timestamp" id="12" fillcolor="33FF70" type="integer" length="6" endian="little"/>
<binary name="&lt;Binary Fill Bytes&gt;" id="13" unused="yes" length="23"/>
<number name="Backtrace ID" id="14" fillcolor="FF8284" type="integer" length="4" endian="little"/>
<structure name="Data" id="27" length="BytesPerEntry" repeatmax="-1">
<number name="Timestamp" id="28" fillcolor="33FF70" type="integer" length="6" endian="little"/>
<number name="Thread ID" id="33" fillcolor="65A0FF" type="integer" length="4"/>
<binary name="&lt;Binary Fill Bytes&gt;" id="29" unused="yes" fillcolor="C0C0C0" length="19"/>
<number name="Backtrace ID" id="30" fillcolor="FF8284" type="integer" length="4" endian="little"/>
</structure>
</structure>
</grammar>

View File

@ -286,13 +286,21 @@ async function getRawSampleList(core: TraceDirectoryTree): Promise<Sample[]> {
while (true) {
// Schema as of Instruments 8.3.3 is a 6 byte timestamp, followed by a bunch
// of stuff we don't care about, followed by a 4 byte backtrace ID
const timestampBytes = 48 / 8
const timestamp = bulkstore.readUint48()
if (timestamp === 0) break
const threadIDBytes = 32 / 8
const threadID = bulkstore.readUint32()
bulkstore.skip(bytesPerEntry - 6 - 4 - 4)
// Skip the stuff we don't care about. We can do this because we know how
// many bytes there shuold be per entry from the header of the file, and
// we know how many bytes we're reading for each of the fields we do care
// about.
const backtraceIDBytes = 32 / 8
bulkstore.skip(bytesPerEntry - timestampBytes - threadIDBytes - backtraceIDBytes)
const backtraceID = bulkstore.readUint32()
samples.push({timestamp, threadID, backtraceID})
}
return samples
@ -516,15 +524,38 @@ export function importThreadFromInstrumentsTrace(args: {
const profile = new StackListProfileBuilder(lastOf(samples)!.timestamp)
profile.setName(`${fileName} - thread ${threadID}`)
// Each sample's stack is identified by a single number. This number might be
// a an address, or an index into the integer array list. If it's an index
// into the integer arrays list, then the integer array it corresponds to
// might itself contain either addresses or indices into the integer array.
function appendRecursive(k: number, stack: FrameInfo[]) {
const frame = addressToFrameMap.get(k)
// First try: let's see if the number is an address and we have
// an associated stack frame for the address.
const address = k
const frame = addressToFrameMap.get(address)
if (frame) {
stack.push(frame)
} else if (k in arrays) {
for (let addr of arrays[k]) {
return
}
// Second try: let's see if the number is an index into the integer array
// list. We'll re-interpret the index as a 32 bit integer here by ignoring
// the upper 32 bits of the integer.
//
// TODO(jlfwong): This seems pretty dubious. Is there a more correct wait to
// differentiate between an address and a number? I wonder if there's either
// some metadata somewhere that we need or if there's something in the byte
// sequence that indicates what kind of number it is.
const arrayIndex = k & 0xffffffff
if (arrayIndex in arrays) {
for (let addr of arrays[arrayIndex]) {
appendRecursive(addr, stack)
}
} else {
return
}
// Fallback case: we'll say we can't find the address, and just
// display the address instead of frame information.
const rawAddressFrame: FrameInfo = {
key: k,
name: `0x${zeroPad(k.toString(16), 16)}`,
@ -532,7 +563,6 @@ export function importThreadFromInstrumentsTrace(args: {
addressToFrameMap.set(k, rawAddressFrame)
stack.push(rawAddressFrame)
}
}
let lastTimestamp: null | number = null
for (let sample of samples) {