// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:async';
import 'dart:convert';
import 'dart:io' as io;

import 'package:args/args.dart' show ArgParser, ArgResults;
import 'package:native_stack_traces/native_stack_traces.dart';
import 'package:native_stack_traces/src/macho.dart' show CpuType;
import 'package:path/path.dart' as path;

ArgParser _createBaseDebugParser(ArgParser parser) => parser
  ..addOption('debug',
      abbr: 'd',
      help: 'Filename containing debugging information (REQUIRED)',
      valueHelp: 'FILE')
  ..addFlag('verbose',
      abbr: 'v',
      negatable: false,
      help: 'Translate all frames, not just user or library code frames');

final ArgParser _dumpParser = ArgParser(allowTrailingOptions: true)
  ..addOption('output',
      abbr: 'o', help: 'Filename for generated output', valueHelp: 'FILE');

final ArgParser _translateParser =
    _createBaseDebugParser(ArgParser(allowTrailingOptions: true))
      ..addMultiOption('unit_debug',
          abbr: 'u',
          help: 'filename containing debugging information'
              ' for a deferred loading unit',
          valueHelp: 'FILE')
      ..addMultiOption('unit_id_debug',
          help: 'ID and filename containing debugging information'
              ' for a deferred loading unit',
          valueHelp: 'N=FILE')
      ..addOption('input',
          abbr: 'i', help: 'Filename for processed input', valueHelp: 'FILE')
      ..addOption('output',
          abbr: 'o', help: 'Filename for generated output', valueHelp: 'FILE');

final ArgParser _findParser =
    _createBaseDebugParser(ArgParser(allowTrailingOptions: true))
      ..addMultiOption('location',
          abbr: 'l', help: 'PC address to find', valueHelp: 'PC')
      ..addFlag('force_hexadecimal',
          abbr: 'x',
          negatable: false,
          help: 'Always parse integers as hexadecimal')
      ..addOption('architecture',
          abbr: 'a',
          help: 'Architecture on which the program is run',
          allowed: CpuType.values.map((v) => v.dartName),
          valueHelp: 'ARCH')
      ..addOption('vm_start',
          help: 'Absolute address for start of VM instructions',
          valueHelp: 'PC')
      ..addOption('isolate_start',
          help: 'Absolute address for start of isolate instructions',
          valueHelp: 'PC');

final ArgParser _helpParser = ArgParser(allowTrailingOptions: true);

final ArgParser _argParser = ArgParser(allowTrailingOptions: true)
  ..addCommand('dump', _dumpParser)
  ..addCommand('help', _helpParser)
  ..addCommand('find', _findParser)
  ..addCommand('translate', _translateParser)
  ..addFlag('help',
      abbr: 'h',
      negatable: false,
      help: 'Print usage information for this or a particular subcommand');

final String _mainUsage = '''
Usage: decode <command> [options] ...

Commands:
${_argParser.commands.keys.join("\n")}

Options shared by all commands:
${_argParser.usage}''';

final String _helpUsage = '''
Usage: decode help [<command>]

Returns usage for the decode utility or a particular command.

Commands:
${_argParser.commands.keys.join("\n")}''';

final String _translateUsage = '''
Usage: decode translate [options]

The translate command takes text that includes non-symbolic stack traces
generated by the VM when executing a snapshot compiled with the
--dwarf-stack-traces flag. It outputs almost the same text, but with any
non-symbolic stack traces converted to symbolic stack traces that contain
function names, file names, and line numbers.

If there are deferred loading units and their loading unit ids are known, then
the debugging information for the deferred loading units can be specified
using the --unit_id_debug command line option. E.g., if the debugging
information for loading unit 5 is in debug_5.so and the information for
loading unit 6 in debug_6.so, then the following command line arguments can
be used:
  --unit_id_debug 5=debug_5.so --unit_id_debug 6=debug_6.so
or
  --unit_id_debug 5=debug_5.so,6=debug_6.so

If the loading unit ids are not known, but the build IDs in the debugging
information match those of the deferred units, then the --unit_debug command
line option (which can be abbreviated as -u) can be used:
  -u debug_5.so -u debug_6.so
or
  -u debug_5.so,debug_6.so

Options shared by all commands:
${_argParser.usage}

Options specific to the translate command:
${_translateParser.usage}''';

final String _findUsage = '''
Usage: decode find [options] <PC> ...

The find command looks up program counter (PC) addresses, either given as
arguments on the command line or via the -l/--location option. For each
successful PC lookup, it outputs the call information in one of two formats:

- If the location corresponds to a call site in Dart source code, the call
  information includes the file, function, and line number information.
- If it corresponds to a Dart VM stub, the call information includes the dynamic
  symbol name for the instructions payload and an offset into that payload.

The -l option may be provided multiple times, or a single use of the -l option
may be given multiple arguments separated by commas.

PC addresses can be provided in one of two formats:

- An integer, e.g. 0x2a3f or 15049
- A static symbol in the VM snapshot plus an integer offset, e.g.,
  _kDartIsolateSnapshotInstructions+1523 or _kDartVMSnapshotInstructions+0x403f

Integers without an "0x" prefix that do not includes hexadecimal digits are
assumed to be decimal unless the -x/--force_hexadecimal flag is used.

By default, integer PC addresses are assumed to be virtual addresses valid for
the given debugging information. Otherwise, use both the --vm_start and
--isolate_start arguments to provide the appropriate starting addresses of the
VM and isolate instructions sections.

Options shared by all commands:
${_argParser.usage}

Options specific to the find command:
${_findParser.usage}''';

final String _dumpUsage = '''
Usage: decode dump [options] <snapshot>

The dump command dumps the DWARF information in the given snapshot to either
standard output or a given output file.

Options specific to the dump command:
${_dumpParser.usage}''';

final _usages = <String?, String>{
  null: _mainUsage,
  '': _mainUsage,
  'help': _helpUsage,
  'translate': _translateUsage,
  'find': _findUsage,
  'dump': _dumpUsage,
};

const int _badUsageExitCode = 1;

void errorWithUsage(String message, {String? command}) {
  print('Error: $message.\n');
  print(_usages[command]);
  io.exitCode = _badUsageExitCode;
}

void help(ArgResults options) {
  void usageError(String message) => errorWithUsage(message, command: 'help');

  switch (options.rest.length) {
    case 0:
      return print(_usages['help']);
    case 1:
      {
        final usage = _usages[options.rest.first];
        if (usage != null) return print(usage);
        return usageError('invalid command ${options.rest.first}');
      }
    default:
      return usageError('too many arguments');
  }
}

Dwarf? _loadFromFile(String? original, Function(String) usageError) {
  if (original == null) {
    usageError('must provide -d/--debug');
    return null;
  }
  final filename = path.canonicalize(path.normalize(original));
  try {
    final dwarf = Dwarf.fromFile(filename);
    if (dwarf == null) {
      usageError('file "$original" does not contain debugging information');
    }
    return dwarf;
  } on io.FileSystemException {
    usageError('debug file "$original" does not exist');
    return null;
  }
}

void find(ArgResults options) {
  final bool verbose = options['verbose'];
  final bool forceHexadecimal = options['force_hexadecimal'];

  void usageError(String message) => errorWithUsage(message, command: 'find');
  int? tryParseIntAddress(String s) {
    if (!forceHexadecimal && !s.startsWith('0x')) {
      final decimal = int.tryParse(s);
      if (decimal != null) return decimal;
    }
    return int.tryParse(s.startsWith('0x') ? s.substring(2) : s, radix: 16);
  }

  PCOffset? convertAddress(StackTraceHeader header, String s) {
    final parsedOffset =
        tryParseSymbolOffset(s, forceHexadecimal: forceHexadecimal);
    if (parsedOffset != null) return parsedOffset;

    final address = tryParseIntAddress(s);
    if (address != null) return header.offsetOf(address);

    return null;
  }

  final dwarf = _loadFromFile(options['debug'], usageError);
  if (dwarf == null) return;

  if ((options['vm_start'] == null) != (options['isolate_start'] == null)) {
    return usageError('need both VM start and isolate start');
  }

  var vmStart = dwarf.vmStartAddress();
  if (options['vm_start'] != null) {
    final address = tryParseIntAddress(options['vm_start']);
    if (address == null) {
      return usageError('could not parse VM start address '
          '${options['vm_start']}');
    }
    vmStart = address;
  }
  if (vmStart == null) {
    return usageError('no VM start address found, one must be specified '
        'with --vm_start');
  }

  var isolateStart = dwarf.isolateStartAddress();
  if (options['isolate_start'] != null) {
    final address = tryParseIntAddress(options['isolate_start']);
    if (address == null) {
      return usageError('could not parse isolate start address '
          '${options['isolate_start']}');
    }
    isolateStart = address;
  }
  if (isolateStart == null) {
    return usageError('no isolate start address found, one must be specified '
        'with --isolate_start');
  }

  final arch = options['architecture'];

  final header =
      StackTraceHeader.fromStarts(isolateStart, vmStart, architecture: arch);

  final locations = <PCOffset>[];
  for (final String s in [
    ...(options['location'] as List<String>),
    ...options.rest,
  ]) {
    final location = convertAddress(header, s);
    if (location == null) return usageError('could not parse PC address $s');
    locations.add(location);
  }
  if (locations.isEmpty) return usageError('no PC addresses to find');

  for (final offset in locations) {
    final addr = dwarf.virtualAddressOf(offset);
    final frames = dwarf
        .callInfoForPCOffset(offset, includeInternalFrames: verbose)
        ?.map((CallInfo c) => '  $c');
    final addrString =
        addr > 0 ? '0x${addr.toRadixString(16)}' : addr.toString();
    print('For virtual address $addrString:');
    if (frames == null) {
      print('  Invalid virtual address.');
    } else if (frames.isEmpty) {
      print('  Not a call from user or library code.');
    } else {
      frames.forEach(print);
    }
  }
}

final RegExp _unitDebugRE = RegExp(r'(\d+)=(.*)');

Future<void> translate(ArgResults options) async {
  void usageError(String message) =>
      errorWithUsage(message, command: 'translate');

  final dwarf = _loadFromFile(options['debug'], usageError);
  if (dwarf == null) {
    return;
  }

  final verbose = options['verbose'];
  final output = options['output'] != null
      ? io.File(path.canonicalize(path.normalize(options['output'])))
          .openWrite()
      : io.stdout;
  final input = options['input'] != null
      ? io.File(path.canonicalize(path.normalize(options['input']))).openRead()
      : io.stdin;
  Map<int, Dwarf>? dwarfByUnitId;
  if (options['unit_id_debug'] != null) {
    dwarfByUnitId = <int, Dwarf>{};
    for (final unitArg in options['unit_id_debug']!) {
      final match = _unitDebugRE.firstMatch(unitArg);
      if (match == null) {
        usageError('Expected N=FILE where N is an integer, got $unitArg');
        return;
      }
      final unitId = int.parse(match[1]!);
      final filename = match[2]!;
      final dwarf = _loadFromFile(filename, usageError);
      if (dwarf == null) return;
      dwarfByUnitId[unitId] = dwarf;
    }
  }
  List<Dwarf>? unitDwarfs;
  if (options['unit_debug'] != null) {
    unitDwarfs = <Dwarf>[];
    for (final filename in options['unit_debug']!) {
      final dwarf = _loadFromFile(filename, usageError);
      if (dwarf == null) return;
      unitDwarfs.add(dwarf);
    }
  }

  final convertedStream = input
      .transform(utf8.decoder)
      .transform(const LineSplitter())
      .transform(DwarfStackTraceDecoder(
        dwarf,
        includeInternalFrames: verbose,
        dwarfByUnitId: dwarfByUnitId,
        unitDwarfs: unitDwarfs,
      ))
      .map((s) => '$s\n')
      .transform(utf8.encoder);

  await output.addStream(convertedStream);
  await output.flush();
  await output.close();
}

Future<void> dump(ArgResults options) async {
  void usageError(String message) => errorWithUsage(message, command: 'dump');

  if (options.rest.isEmpty) {
    return usageError('must provide a path to an ELF file or dSYM directory '
        'that contains DWARF information');
  }
  final dwarf = _loadFromFile(options.rest.first, usageError);
  if (dwarf == null) {
    return;
  }

  final output = options['output'] != null
      ? io.File(path.canonicalize(path.normalize(options['output'])))
          .openWrite()
      : io.stdout;
  output.write(dwarf.dumpFileInfo());
  await output.flush();
  await output.close();
}

Future<void> main(List<String> arguments) async {
  ArgResults options;

  try {
    options = _argParser.parse(arguments);
  } on FormatException catch (e) {
    return errorWithUsage(e.message);
  }

  if (options['help']) return print(_usages[options.command?.name]);
  if (options.command == null) return errorWithUsage('no command provided');

  switch (options.command!.name) {
    case 'help':
      return help(options.command!);
    case 'find':
      return find(options.command!);
    case 'translate':
      return await translate(options.command!);
    case 'dump':
      return await dump(options.command!);
  }
}
