7a90c32032
Add basic profiler support - Moved profiling-related helpers to profiling.mjs - Added bottom-up profiler table - Added mini-timeline overview wit opt/deopt events and usage graph - Added flame-graph, pivoted on the currently selected function Drive-by-fixes: - Added/updated jsdoc type information - Fixed static symbols (builtins, bytecodehandlers) that were both added by the CppEntriesProvider and from code-events in the v8.log - Support platform-specific (linux/macos) dynamic symbol loader by adding a query path ('/v8/info/platform') to lws-middleware.js - added css var --selection-color Bug: v8:10644 Change-Id: I6412bec63eac13140d6d425e7d9cc33316824c73 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3585453 Reviewed-by: Patrick Thier <pthier@chromium.org> Commit-Queue: Camillo Bruni <cbruni@chromium.org> Cr-Commit-Position: refs/heads/main@{#80192}
102 lines
2.9 KiB
JavaScript
102 lines
2.9 KiB
JavaScript
// Copyright 2021 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
const util = require('util');
|
|
const execFile = util.promisify(require('child_process').execFile);
|
|
const fs = require('fs')
|
|
|
|
async function sh(cmd, ...params) {
|
|
console.log(cmd, params.join(' '));
|
|
const options = {maxBuffer: 256 * 1024 * 1024};
|
|
const {stdout} = await execFile(cmd, params, options);
|
|
return stdout;
|
|
}
|
|
|
|
class Symbolizer {
|
|
constructor() {
|
|
this.nmExec = 'nm';
|
|
this.objdumpExec = 'objdump';
|
|
}
|
|
|
|
middleware(config) {
|
|
return async (ctx, next) => {
|
|
if (ctx.path == '/v8/loadVMSymbols') {
|
|
await this.parseVMSymbols(ctx)
|
|
} else if (ctx.path == '/v8/info/platform') {
|
|
ctx.response.type = 'text';
|
|
ctx.response.body = process.platform;
|
|
}
|
|
await next();
|
|
}
|
|
}
|
|
|
|
async parseVMSymbols(ctx) {
|
|
const query = ctx.request.query;
|
|
const result = {
|
|
libName: query.libName,
|
|
symbols: ['', ''],
|
|
error: undefined,
|
|
fileOffsetMinusVma: 0,
|
|
};
|
|
switch (query.platform) {
|
|
case 'macos':
|
|
await this.loadVMSymbolsMacOS(query, result);
|
|
break;
|
|
case 'linux':
|
|
await this.loadVMSymbolsLinux(query, result);
|
|
break;
|
|
default:
|
|
ctx.response.status = '500';
|
|
return;
|
|
}
|
|
ctx.response.type = 'json';
|
|
ctx.response.body = JSON.stringify(result);
|
|
}
|
|
|
|
async loadVMSymbolsMacOS(query, result) {
|
|
let libName =
|
|
(query.targetRootFS ? query.targetRootFS : '') + query.libName;
|
|
try {
|
|
// Fast skip files that don't exist.
|
|
if (libName.indexOf('/') === -1 || !fs.existsSync(libName)) return;
|
|
result.symbols = [await sh(this.nmExec, '--demangle', '-n', libName), ''];
|
|
} catch (e) {
|
|
result.error = e.message;
|
|
}
|
|
}
|
|
|
|
async loadVMSymbolsLinux(query, result) {
|
|
let libName = query.libName;
|
|
if (query.apkEmbeddedLibrary && libName.endsWith('.apk')) {
|
|
libName = query.apkEmbeddedLibrary;
|
|
}
|
|
if (query.targetRootFS) {
|
|
libName = libName.substring(libName.lastIndexOf('/') + 1);
|
|
libName = query.targetRootFS + libName;
|
|
}
|
|
try {
|
|
// Fast skip files that don't exist.
|
|
if (libName.indexOf('/') === -1 || !fs.existsSync(libName)) return;
|
|
result.symbols = [
|
|
await sh(this.nmExec, '-C', '-n', '-S', libName),
|
|
await sh(this.nmExec, '-C', '-n', '-S', '-D', libName)
|
|
];
|
|
|
|
const objdumpOutput = await sh(this.objdumpExec, '-h', libName);
|
|
for (const line of objdumpOutput.split('\n')) {
|
|
const [, sectionName, , vma, , fileOffset] = line.trim().split(/\s+/);
|
|
if (sectionName === '.text') {
|
|
result.fileOffsetMinusVma =
|
|
parseInt(fileOffset, 16) - parseInt(vma, 16);
|
|
}
|
|
}
|
|
} catch (e) {
|
|
console.log(e);
|
|
result.error = e.message;
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = Symbolizer
|