11cb0ef41Sopenharmony_ci// Copyright 2021 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ciconst util = require('util');
61cb0ef41Sopenharmony_ciconst execFile = util.promisify(require('child_process').execFile);
71cb0ef41Sopenharmony_ciconst fs = require('fs')
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ciasync function sh(cmd, ...params) {
101cb0ef41Sopenharmony_ci  console.log(cmd, params.join(' '));
111cb0ef41Sopenharmony_ci  const options = {maxBuffer: 256 * 1024 * 1024};
121cb0ef41Sopenharmony_ci  const {stdout} = await execFile(cmd, params, options);
131cb0ef41Sopenharmony_ci  return stdout;
141cb0ef41Sopenharmony_ci}
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_ciclass Symbolizer {
171cb0ef41Sopenharmony_ci  constructor() {
181cb0ef41Sopenharmony_ci    this.nmExec = 'nm';
191cb0ef41Sopenharmony_ci    this.objdumpExec = 'objdump';
201cb0ef41Sopenharmony_ci  }
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ci  middleware(config) {
231cb0ef41Sopenharmony_ci    return async (ctx, next) => {
241cb0ef41Sopenharmony_ci      if (ctx.path == '/v8/loadVMSymbols') {
251cb0ef41Sopenharmony_ci        await this.parseVMSymbols(ctx)
261cb0ef41Sopenharmony_ci      }
271cb0ef41Sopenharmony_ci      await next()
281cb0ef41Sopenharmony_ci    }
291cb0ef41Sopenharmony_ci  }
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ci  async parseVMSymbols(ctx) {
321cb0ef41Sopenharmony_ci    const query = ctx.request.query;
331cb0ef41Sopenharmony_ci    const result = {
341cb0ef41Sopenharmony_ci      libName: query.libName,
351cb0ef41Sopenharmony_ci      symbols: ['', ''],
361cb0ef41Sopenharmony_ci      error: undefined,
371cb0ef41Sopenharmony_ci      fileOffsetMinusVma: 0,
381cb0ef41Sopenharmony_ci    };
391cb0ef41Sopenharmony_ci    switch (query.platform) {
401cb0ef41Sopenharmony_ci      case 'macos':
411cb0ef41Sopenharmony_ci        await this.loadVMSymbolsMacOS(query, result);
421cb0ef41Sopenharmony_ci        break;
431cb0ef41Sopenharmony_ci      case 'linux':
441cb0ef41Sopenharmony_ci        await this.loadVMSymbolsLinux(query, result);
451cb0ef41Sopenharmony_ci        break;
461cb0ef41Sopenharmony_ci      default:
471cb0ef41Sopenharmony_ci        ctx.response.status = '500';
481cb0ef41Sopenharmony_ci        return;
491cb0ef41Sopenharmony_ci    }
501cb0ef41Sopenharmony_ci    ctx.response.type = 'json';
511cb0ef41Sopenharmony_ci    ctx.response.body = JSON.stringify(result);
521cb0ef41Sopenharmony_ci  }
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_ci  async loadVMSymbolsMacOS(query, result) {
551cb0ef41Sopenharmony_ci    let libName =
561cb0ef41Sopenharmony_ci        (query.targetRootFS ? query.targetRootFS : '') + query.libName;
571cb0ef41Sopenharmony_ci    try {
581cb0ef41Sopenharmony_ci      // Fast skip files that don't exist.
591cb0ef41Sopenharmony_ci      if (libName.indexOf('/') === -1 || !fs.existsSync(libName)) return;
601cb0ef41Sopenharmony_ci      result.symbols = [await sh(this.nmExec, '--demangle', '-n', libName), ''];
611cb0ef41Sopenharmony_ci    } catch (e) {
621cb0ef41Sopenharmony_ci      result.error = e.message;
631cb0ef41Sopenharmony_ci    }
641cb0ef41Sopenharmony_ci  }
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ci  async loadVMSymbolsLinux(query, result) {
671cb0ef41Sopenharmony_ci    let libName = query.libName;
681cb0ef41Sopenharmony_ci    if (query.apkEmbeddedLibrary && libName.endsWith('.apk')) {
691cb0ef41Sopenharmony_ci      libName = query.apkEmbeddedLibrary;
701cb0ef41Sopenharmony_ci    }
711cb0ef41Sopenharmony_ci    if (query.targetRootFS) {
721cb0ef41Sopenharmony_ci      libName = libName.substring(libName.lastIndexOf('/') + 1);
731cb0ef41Sopenharmony_ci      libName = query.targetRootFS + libName;
741cb0ef41Sopenharmony_ci    }
751cb0ef41Sopenharmony_ci    try {
761cb0ef41Sopenharmony_ci      // Fast skip files that don't exist.
771cb0ef41Sopenharmony_ci      if (libName.indexOf('/') === -1 || !fs.existsSync(libName)) return;
781cb0ef41Sopenharmony_ci      result.symbols = [
791cb0ef41Sopenharmony_ci        await sh(this.nmExec, '-C', '-n', '-S', libName),
801cb0ef41Sopenharmony_ci        await sh(this.nmExec, '-C', '-n', '-S', '-D', libName)
811cb0ef41Sopenharmony_ci      ];
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci      const objdumpOutput = await sh(this.objdumpExec, '-h', libName);
841cb0ef41Sopenharmony_ci      for (const line of objdumpOutput.split('\n')) {
851cb0ef41Sopenharmony_ci        const [, sectionName, , vma, , fileOffset] = line.trim().split(/\s+/);
861cb0ef41Sopenharmony_ci        if (sectionName === '.text') {
871cb0ef41Sopenharmony_ci          result.fileOffsetMinusVma =
881cb0ef41Sopenharmony_ci              parseInt(fileOffset, 16) - parseInt(vma, 16);
891cb0ef41Sopenharmony_ci        }
901cb0ef41Sopenharmony_ci      }
911cb0ef41Sopenharmony_ci    } catch (e) {
921cb0ef41Sopenharmony_ci      console.log(e);
931cb0ef41Sopenharmony_ci      result.error = e.message;
941cb0ef41Sopenharmony_ci    }
951cb0ef41Sopenharmony_ci  }
961cb0ef41Sopenharmony_ci}
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_cimodule.exports = Symbolizer
99