blob: 6323268f16d8ab37f1f56ad8620c940cc5cca48f [file] [log] [blame]
// This file parses ASCII text-encoded dbus message dump.
function extractUsec(line) {
let i0 = line.indexOf('time=');
if (i0 == -1) {
return BigInt(-1);
}
let line1 = line.substr(i0);
let i1 = line1.indexOf(' ');
if (i1 == -1) {
return BigInt(-1);
}
let line2 = line1.substr(5, i1 - 5);
let sp = line2.split('.');
return BigInt(sp[0]) * BigInt(1000000) + BigInt(sp[1]);
}
function extractInt(line, kw) {
let N = kw.length;
let i0 = line.indexOf(kw);
if (i0 == -1) {
return null;
}
let line1 = line.substr(i0);
let i1 = line1.indexOf(' ');
if (i1 == -1) {
i1 = line.length;
}
let line2 = line1.substr(N, i1 - N);
return parseInt(line2);
}
function extractSerial(line) {
return extractInt(line, 'serial=');
}
function extractReplySerial(line) {
return extractInt(line, 'reply_serial=');
}
// Returns [byte, i+1] if successful
// Returns [null, i ] if unsuccessful
function munchByte(lines, i) {
if (i >= lines.length) {
return [null, i]
}
let l = lines[i];
let idx = l.indexOf('byte');
if (idx != -1) {
return [parseInt(l.substr(idx + 4), 10), i + 1];
} else {
return [null, i];
}
}
// array of bytes "@"
function munchArrayOfBytes1(lines, i) {
let l = lines[i];
let idx = l.indexOf('array of bytes "');
if (idx != -1) {
let the_ch = l.substr(idx + 16, 1);
return [[the_ch.charCodeAt(0)], i + 1];
} else {
return [null, i];
}
}
function munchArrayOfBytes2(lines, i) {
let l = lines[i];
let idx = l.indexOf('array of bytes [');
if (idx == -1) {
idx = l.indexOf('array [');
}
if (idx != -1) {
let j = i + 1;
let payload = [];
while (true) {
if (j >= lines.length) {
break;
}
l = lines[j];
let sp = l.trim().split(' ');
let ok = true;
for (let k = 0; k < sp.length; k++) {
let b = parseInt(sp[k], 16);
if (isNaN(b)) {
ok = false;
break;
} else {
payload.push(b);
}
}
if (!ok) {
j--;
break;
} else
j++;
}
return [payload, j];
} else {
return [null, i];
}
}
function munchArrayOfBytes(lines, i) {
if (i >= lines.length) return [null, i];
let x = munchArrayOfBytes1(lines, i);
if (x[0] != null) {
return x;
}
x = munchArrayOfBytes2(lines, i);
if (x[0] != null) {
return x;
}
return [null, i];
}
// ReceivedMessage
function munchLegacyMessageStart(lines, i) {
let entry = {
netfn: 0,
lun: 0,
cmd: 0,
serial: 0,
start_usec: 0,
end_usec: 0,
request: [],
response: []
};
let ts = extractUsec(lines[i]);
entry.start_usec = ts;
let x = munchByte(lines, i + 1);
if (x[0] == null) {
return [null, i];
}
entry.serial = x[0];
let j = x[1];
x = munchByte(lines, j);
if (x[0] == null) {
return [null, i];
}
entry.netfn = x[0];
j = x[1];
x = munchByte(lines, j);
if (x[0] == null) {
return [null, i];
}
entry.lun = x[0];
j = x[1];
x = munchByte(lines, j);
if (x[0] == null) {
return [null, i];
}
entry.cmd = x[0];
j = x[1];
x = munchArrayOfBytes(lines, j);
if (x[0] == null) {
return [null, i];
}
entry.request = x[0];
j = x[1];
return [entry, j];
}
function munchLegacyMessageEnd(lines, i, in_flight, parsed_entries) {
let ts = extractUsec(lines[i]);
let x = munchByte(lines, i + 1);
if (x[0] == null) {
return [null, i];
} // serial
let serial = x[0];
let j = x[1];
let entry = null;
if (serial in in_flight) {
entry = in_flight[serial];
delete in_flight[serial];
} else {
return [null, i];
}
entry.end_usec = ts;
x = munchByte(lines, j); // netfn
if (x[0] == null) {
return [null, i];
}
if (entry.netfn + 1 == x[0]) {
} else {
return [null, i];
}
j = x[1];
x = munchByte(lines, j); // lun (not used right now)
if (x[0] == null) {
return [null, i];
}
j = x[1];
x = munchByte(lines, j); // cmd
if (x[0] == null) {
return [null, i];
}
if (entry.cmd == x[0]) {
} else {
return [null, i];
}
j = x[1];
x = munchByte(lines, j); // cc
if (x[0] == null) {
return [null, i];
}
j = x[1];
x = munchArrayOfBytes(lines, j);
if (x[0] == null) {
entry.response = [];
} else {
entry.response = x[0];
}
j = x[1];
parsed_entries.push(entry);
return [entry, j];
}
function munchNewMessageStart(lines, i, in_flight) {
let ts = extractUsec(lines[i]);
let serial = extractSerial(lines[i]);
let entry = {
netfn: 0,
lun: 0,
cmd: 0,
serial: -999,
start_usec: 0,
end_usec: 0,
request: [],
response: []
};
entry.start_usec = ts;
entry.serial = serial;
let x = munchByte(lines, i + 1);
if (x[0] == null) {
return [null, i];
}
entry.netfn = x[0];
let j = x[1];
x = munchByte(lines, j);
if (x[0] == null) {
return [null, i];
}
entry.lun = x[0];
j = x[1];
x = munchByte(lines, j);
if (x[0] == null) {
return [null, i];
}
entry.cmd = x[0];
j = x[1];
x = munchArrayOfBytes(lines, j);
if (x[0] == null) {
entry.request = [];
} // Truncated
entry.request = x[0];
j = x[1];
return [entry, j];
}
function munchNewMessageEnd(lines, i, in_flight, parsed_entries) {
let ts = extractUsec(lines[i]);
let reply_serial = extractReplySerial(lines[i]);
let entry = null;
if (reply_serial in in_flight) {
entry = in_flight[reply_serial];
delete in_flight[reply_serial];
} else {
return [null, i];
}
entry.end_usec = ts;
let x = munchByte(lines, i + 2); // Skip "struct {"
if (x[0] == null) {
return [null, i];
} // NetFN
if (entry.netfn + 1 != x[0]) {
return [null, i];
}
let j = x[1];
x = munchByte(lines, j); // LUN
if (x[0] == null) {
return [null, i];
}
j = x[1];
x = munchByte(lines, j); // CMD
if (x[0] == null) {
return [null, i];
}
if (entry.cmd != x[0]) {
return [null, i];
}
j = x[1];
x = munchByte(lines, j); // cc
if (x[0] == null) {
return [null, i];
}
j = x[1];
x = munchArrayOfBytes(lines, j);
if (x[0] == null) {
entry.response = [];
} else {
entry.response = x[0];
}
j = x[1];
parsed_entries.push(entry);
return [entry, j];
}
// Parsing state
let g_ipmi_parse_buf = '';
let g_ipmi_parse_lines = [];
let g_ipmi_in_flight = {};
let g_ipmi_parsed_entries = [];
function StartParseIPMIDump() {
g_ipmi_parse_lines = [];
g_ipmi_parsed_entries = [];
g_ipmi_in_flight = {};
g_ipmi_parse_buf = '';
}
function AppendToParseBuffer(x) {
g_ipmi_parse_buf += x;
}
function MunchLines() {
// 1. Extract all lines from the buffer
let chars_munched = 0;
while (true) {
let idx = g_ipmi_parse_buf.indexOf('\n');
if (idx == -1) break;
let l = g_ipmi_parse_buf.substr(0, idx);
g_ipmi_parse_lines.push(l);
g_ipmi_parse_buf = g_ipmi_parse_buf.substr(idx + 1);
chars_munched += (idx + 1);
}
console.log(chars_munched + ' chars munched');
// 2. Parse as many lines as possible
let lidx_last = 0;
let i = 0;
while (i < g_ipmi_parse_lines.length) {
let line = g_ipmi_parse_lines[i];
if (line.indexOf('interface=org.openbmc.HostIpmi') != -1 &&
line.indexOf('member=ReceivedMessage') != -1) {
let x = munchLegacyMessageStart(g_ipmi_parse_lines, i);
let entry = x[0];
if (i != x[1]) lidx_last = x[1]; // Munch success!
i = x[1];
if (entry != null) {
g_ipmi_in_flight[entry.serial] = entry;
}
} else if (
line.indexOf('interface=org.openbmc.HostIpmi') != -1 &&
line.indexOf('member=sendMessage') != -1) {
let x = munchLegacyMessageEnd(
g_ipmi_parse_lines, i, g_ipmi_in_flight, g_ipmi_parsed_entries);
if (i != x[1]) lidx_last = x[1]; // Munch success!
i = x[1];
} else if (
line.indexOf('interface=xyz.openbmc_project.Ipmi.Server') != -1 &&
line.indexOf('member=execute') != -1) {
let x = munchNewMessageStart(g_ipmi_parse_lines, i);
let entry = x[0];
if (i != x[1]) lidx_last = x[1];
i = x[1];
if (entry != null) {
g_ipmi_in_flight[entry.serial] = entry;
}
} else if (line.indexOf('method return') != -1) {
let x = munchNewMessageEnd(
g_ipmi_parse_lines, i, g_ipmi_in_flight, g_ipmi_parsed_entries);
if (i != x[1]) lidx_last = x[1]; // Munch success
i = x[1];
}
i++;
}
g_ipmi_parse_lines = g_ipmi_parse_lines.slice(
lidx_last,
g_ipmi_parse_lines.length); // Remove munched lines
console.log(
lidx_last + ' lines munched, |lines|=' + g_ipmi_parse_lines.length +
', |entries|=' + g_ipmi_parsed_entries.length,
', |inflight|=' + Object.keys(g_ipmi_in_flight).length);
}
let last_update_time = 0; // Millis since Unix Epoch
function UpdateLayout(level) {
const this_update_time = new Date().getTime();
const over_1s = (this_update_time - last_update_time > 1000);
if (!over_1s) {
if (level > 0) {
setTimeout(function() {
UpdateLayout(level - 1);
}, 1000);
} else {
return;
}
}
if (g_ipmi_parsed_entries.length > 0) {
last_update_time = this_update_time;
// Write to Data_IPMI
let ts0 = g_ipmi_parsed_entries[0].start_usec;
let ts1 = g_ipmi_parsed_entries[g_ipmi_parsed_entries.length - 1].end_usec;
// When calling from DBus PCap loader, the following happens
// >> OnGroupByConditionChanged
// >> Preprocess <-- Time shift will happen here
// So, we don't do time-shifting here
let time_shift;
if (g_StartingSec != undefined) {
time_shift = BigInt(0);
} else { // This is during live capture mode
time_shift = ts0;
}
Data_IPMI = [];
for (i = 0; i < g_ipmi_parsed_entries.length; i++) {
let entry = g_ipmi_parsed_entries[i];
let x = [
entry.netfn, entry.cmd, parseInt(entry.start_usec - time_shift),
parseInt(entry.end_usec - time_shift), entry.request, entry.response
];
Data_IPMI.push(x);
}
// Re-calculate time range
RANGE_LEFT_INIT = 0;
RANGE_RIGHT_INIT =
parseInt((ts1 - ts0) / BigInt(1000000) / BigInt(10)) * 10 + 10;
IsCanvasDirty = true;
OnGroupByConditionChanged();
ComputeHistogram();
} else {
console.log('No entries parsed');
}
}
function ParseIPMIDump(data) {
StartParseIPMIDump();
AppendToParseBuffer(data);
MunchLines();
UpdateLayout();
}