blob: 6323268f16d8ab37f1f56ad8620c940cc5cca48f [file] [log] [blame]
Sui Chenb65280f2020-06-30 18:14:03 -07001// This file parses ASCII text-encoded dbus message dump.
2
3function extractUsec(line) {
4 let i0 = line.indexOf('time=');
5 if (i0 == -1) {
6 return BigInt(-1);
7 }
8 let line1 = line.substr(i0);
9 let i1 = line1.indexOf(' ');
10 if (i1 == -1) {
11 return BigInt(-1);
12 }
13 let line2 = line1.substr(5, i1 - 5);
14 let sp = line2.split('.');
15 return BigInt(sp[0]) * BigInt(1000000) + BigInt(sp[1]);
16}
17
18function extractInt(line, kw) {
19 let N = kw.length;
20 let i0 = line.indexOf(kw);
21 if (i0 == -1) {
22 return null;
23 }
24 let line1 = line.substr(i0);
25 let i1 = line1.indexOf(' ');
26 if (i1 == -1) {
27 i1 = line.length;
28 }
29 let line2 = line1.substr(N, i1 - N);
30 return parseInt(line2);
31}
32
33function extractSerial(line) {
34 return extractInt(line, 'serial=');
35}
36
37function extractReplySerial(line) {
38 return extractInt(line, 'reply_serial=');
39}
40
41// Returns [byte, i+1] if successful
42// Returns [null, i ] if unsuccessful
43function munchByte(lines, i) {
44 if (i >= lines.length) {
45 return [null, i]
46 }
47 let l = lines[i];
48 let idx = l.indexOf('byte');
49 if (idx != -1) {
50 return [parseInt(l.substr(idx + 4), 10), i + 1];
51 } else {
52 return [null, i];
53 }
54}
55
56// array of bytes "@"
57function munchArrayOfBytes1(lines, i) {
58 let l = lines[i];
59 let idx = l.indexOf('array of bytes "');
60 if (idx != -1) {
61 let the_ch = l.substr(idx + 16, 1);
62 return [[the_ch.charCodeAt(0)], i + 1];
63 } else {
64 return [null, i];
65 }
66}
67
68function munchArrayOfBytes2(lines, i) {
69 let l = lines[i];
70 let idx = l.indexOf('array of bytes [');
71 if (idx == -1) {
72 idx = l.indexOf('array [');
73 }
74 if (idx != -1) {
75 let j = i + 1;
76 let payload = [];
77 while (true) {
78 if (j >= lines.length) {
79 break;
80 }
81 l = lines[j];
82 let sp = l.trim().split(' ');
83 let ok = true;
84 for (let k = 0; k < sp.length; k++) {
85 let b = parseInt(sp[k], 16);
86 if (isNaN(b)) {
87 ok = false;
88 break;
89 } else {
90 payload.push(b);
91 }
92 }
93 if (!ok) {
94 j--;
95 break;
96 } else
97 j++;
98 }
99 return [payload, j];
100 } else {
101 return [null, i];
102 }
103}
104
105function munchArrayOfBytes(lines, i) {
106 if (i >= lines.length) return [null, i];
107
108 let x = munchArrayOfBytes1(lines, i);
109 if (x[0] != null) {
110 return x;
111 }
112 x = munchArrayOfBytes2(lines, i);
113 if (x[0] != null) {
114 return x;
115 }
116 return [null, i];
117}
118
119// ReceivedMessage
120function munchLegacyMessageStart(lines, i) {
121 let entry = {
122 netfn: 0,
123 lun: 0,
124 cmd: 0,
125 serial: 0,
126 start_usec: 0,
127 end_usec: 0,
128 request: [],
129 response: []
130 };
131
132 let ts = extractUsec(lines[i]);
133 entry.start_usec = ts;
134
135 let x = munchByte(lines, i + 1);
136 if (x[0] == null) {
137 return [null, i];
138 }
139 entry.serial = x[0];
140 let j = x[1];
141
142 x = munchByte(lines, j);
143 if (x[0] == null) {
144 return [null, i];
145 }
146 entry.netfn = x[0];
147 j = x[1];
148
149 x = munchByte(lines, j);
150 if (x[0] == null) {
151 return [null, i];
152 }
153 entry.lun = x[0];
154 j = x[1];
155
156 x = munchByte(lines, j);
157 if (x[0] == null) {
158 return [null, i];
159 }
160 entry.cmd = x[0];
161 j = x[1];
162
163 x = munchArrayOfBytes(lines, j);
164 if (x[0] == null) {
165 return [null, i];
166 }
167 entry.request = x[0];
168 j = x[1];
169
170 return [entry, j];
171}
172
173function munchLegacyMessageEnd(lines, i, in_flight, parsed_entries) {
174 let ts = extractUsec(lines[i]);
175
176 let x = munchByte(lines, i + 1);
177 if (x[0] == null) {
178 return [null, i];
179 } // serial
180 let serial = x[0];
181 let j = x[1];
182
183 let entry = null;
184 if (serial in in_flight) {
185 entry = in_flight[serial];
186 delete in_flight[serial];
187 } else {
188 return [null, i];
189 }
190
191 entry.end_usec = ts;
192
193 x = munchByte(lines, j); // netfn
194 if (x[0] == null) {
195 return [null, i];
196 }
197 if (entry.netfn + 1 == x[0]) {
198 } else {
199 return [null, i];
200 }
201 j = x[1];
202
203 x = munchByte(lines, j); // lun (not used right now)
204 if (x[0] == null) {
205 return [null, i];
206 }
207 j = x[1];
208
209 x = munchByte(lines, j); // cmd
210 if (x[0] == null) {
211 return [null, i];
212 }
213 if (entry.cmd == x[0]) {
214 } else {
215 return [null, i];
216 }
217 j = x[1];
218
219 x = munchByte(lines, j); // cc
220 if (x[0] == null) {
221 return [null, i];
222 }
223 j = x[1];
224
225 x = munchArrayOfBytes(lines, j);
226 if (x[0] == null) {
227 entry.response = [];
228 } else {
229 entry.response = x[0];
230 }
231 j = x[1];
232
233 parsed_entries.push(entry);
234
235 return [entry, j];
236}
237
238function munchNewMessageStart(lines, i, in_flight) {
239 let ts = extractUsec(lines[i]);
240 let serial = extractSerial(lines[i]);
241
242 let entry = {
243 netfn: 0,
244 lun: 0,
245 cmd: 0,
246 serial: -999,
247 start_usec: 0,
248 end_usec: 0,
249 request: [],
250 response: []
251 };
252 entry.start_usec = ts;
253 entry.serial = serial;
254
255 let x = munchByte(lines, i + 1);
256 if (x[0] == null) {
257 return [null, i];
258 }
259 entry.netfn = x[0];
260 let j = x[1];
261
262 x = munchByte(lines, j);
263 if (x[0] == null) {
264 return [null, i];
265 }
266 entry.lun = x[0];
267 j = x[1];
268
269 x = munchByte(lines, j);
270 if (x[0] == null) {
271 return [null, i];
272 }
273 entry.cmd = x[0];
274 j = x[1];
275
276 x = munchArrayOfBytes(lines, j);
277 if (x[0] == null) {
278 entry.request = [];
279 } // Truncated
280 entry.request = x[0];
281 j = x[1];
282
283 return [entry, j];
284}
285
286function munchNewMessageEnd(lines, i, in_flight, parsed_entries) {
287 let ts = extractUsec(lines[i]);
288 let reply_serial = extractReplySerial(lines[i]);
289
290 let entry = null;
291 if (reply_serial in in_flight) {
292 entry = in_flight[reply_serial];
293 delete in_flight[reply_serial];
294 } else {
295 return [null, i];
296 }
297
298 entry.end_usec = ts;
299
300 let x = munchByte(lines, i + 2); // Skip "struct {"
301 if (x[0] == null) {
302 return [null, i];
303 } // NetFN
304 if (entry.netfn + 1 != x[0]) {
305 return [null, i];
306 }
307 let j = x[1];
308
309 x = munchByte(lines, j); // LUN
310 if (x[0] == null) {
311 return [null, i];
312 }
313 j = x[1];
314
315 x = munchByte(lines, j); // CMD
316 if (x[0] == null) {
317 return [null, i];
318 }
319 if (entry.cmd != x[0]) {
320 return [null, i];
321 }
322 j = x[1];
323
324 x = munchByte(lines, j); // cc
325 if (x[0] == null) {
326 return [null, i];
327 }
328 j = x[1];
329
330 x = munchArrayOfBytes(lines, j);
331 if (x[0] == null) {
332 entry.response = [];
333 } else {
334 entry.response = x[0];
335 }
336 j = x[1];
337
338 parsed_entries.push(entry);
339
340 return [entry, j];
341}
342
343// Parsing state
344let g_ipmi_parse_buf = '';
345let g_ipmi_parse_lines = [];
346let g_ipmi_in_flight = {};
347let g_ipmi_parsed_entries = [];
348function StartParseIPMIDump() {
349 g_ipmi_parse_lines = [];
350 g_ipmi_parsed_entries = [];
351 g_ipmi_in_flight = {};
352 g_ipmi_parse_buf = '';
353}
354function AppendToParseBuffer(x) {
355 g_ipmi_parse_buf += x;
356}
357function MunchLines() {
358 // 1. Extract all lines from the buffer
359 let chars_munched = 0;
360 while (true) {
361 let idx = g_ipmi_parse_buf.indexOf('\n');
362 if (idx == -1) break;
363 let l = g_ipmi_parse_buf.substr(0, idx);
364 g_ipmi_parse_lines.push(l);
365 g_ipmi_parse_buf = g_ipmi_parse_buf.substr(idx + 1);
366 chars_munched += (idx + 1);
367 }
368 console.log(chars_munched + ' chars munched');
369
370 // 2. Parse as many lines as possible
371 let lidx_last = 0;
372 let i = 0;
373 while (i < g_ipmi_parse_lines.length) {
374 let line = g_ipmi_parse_lines[i];
375 if (line.indexOf('interface=org.openbmc.HostIpmi') != -1 &&
376 line.indexOf('member=ReceivedMessage') != -1) {
377 let x = munchLegacyMessageStart(g_ipmi_parse_lines, i);
378 let entry = x[0];
379 if (i != x[1]) lidx_last = x[1]; // Munch success!
380 i = x[1];
381 if (entry != null) {
382 g_ipmi_in_flight[entry.serial] = entry;
383 }
384 } else if (
385 line.indexOf('interface=org.openbmc.HostIpmi') != -1 &&
386 line.indexOf('member=sendMessage') != -1) {
387 let x = munchLegacyMessageEnd(
388 g_ipmi_parse_lines, i, g_ipmi_in_flight, g_ipmi_parsed_entries);
389 if (i != x[1]) lidx_last = x[1]; // Munch success!
390 i = x[1];
391
392 } else if (
393 line.indexOf('interface=xyz.openbmc_project.Ipmi.Server') != -1 &&
394 line.indexOf('member=execute') != -1) {
395 let x = munchNewMessageStart(g_ipmi_parse_lines, i);
396 let entry = x[0];
397 if (i != x[1]) lidx_last = x[1];
398 i = x[1];
399 if (entry != null) {
400 g_ipmi_in_flight[entry.serial] = entry;
401 }
402 } else if (line.indexOf('method return') != -1) {
403 let x = munchNewMessageEnd(
404 g_ipmi_parse_lines, i, g_ipmi_in_flight, g_ipmi_parsed_entries);
405 if (i != x[1]) lidx_last = x[1]; // Munch success
406 i = x[1];
407 }
408 i++;
409 }
410 g_ipmi_parse_lines = g_ipmi_parse_lines.slice(
411 lidx_last,
412 g_ipmi_parse_lines.length); // Remove munched lines
413 console.log(
414 lidx_last + ' lines munched, |lines|=' + g_ipmi_parse_lines.length +
415 ', |entries|=' + g_ipmi_parsed_entries.length,
416 ', |inflight|=' + Object.keys(g_ipmi_in_flight).length);
417}
418
419let last_update_time = 0; // Millis since Unix Epoch
420function UpdateLayout(level) {
421 const this_update_time = new Date().getTime();
422 const over_1s = (this_update_time - last_update_time > 1000);
423 if (!over_1s) {
424 if (level > 0) {
425 setTimeout(function() {
426 UpdateLayout(level - 1);
427 }, 1000);
428 } else {
429 return;
430 }
431 }
432
433 if (g_ipmi_parsed_entries.length > 0) {
434 last_update_time = this_update_time;
435 // Write to Data_IPMI
436 let ts0 = g_ipmi_parsed_entries[0].start_usec;
437 let ts1 = g_ipmi_parsed_entries[g_ipmi_parsed_entries.length - 1].end_usec;
438
439 // When calling from DBus PCap loader, the following happens
440 // >> OnGroupByConditionChanged
441 // >> Preprocess <-- Time shift will happen here
442 // So, we don't do time-shifting here
443 let time_shift;
444 if (g_StartingSec != undefined) {
445 time_shift = BigInt(0);
446 } else { // This is during live capture mode
447 time_shift = ts0;
448 }
449
450 Data_IPMI = [];
451 for (i = 0; i < g_ipmi_parsed_entries.length; i++) {
452 let entry = g_ipmi_parsed_entries[i];
453 let x = [
454 entry.netfn, entry.cmd, parseInt(entry.start_usec - time_shift),
455 parseInt(entry.end_usec - time_shift), entry.request, entry.response
456 ];
457 Data_IPMI.push(x);
458 }
459
460 // Re-calculate time range
461 RANGE_LEFT_INIT = 0;
462 RANGE_RIGHT_INIT =
463 parseInt((ts1 - ts0) / BigInt(1000000) / BigInt(10)) * 10 + 10;
464
465 IsCanvasDirty = true;
466 OnGroupByConditionChanged();
467
468 ComputeHistogram();
469 } else {
470 console.log('No entries parsed');
471 }
472}
473
474function ParseIPMIDump(data) {
475 StartParseIPMIDump();
476 AppendToParseBuffer(data);
477 MunchLines();
478 UpdateLayout();
479}