// Copyright (c) 2017, 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.

// @dart = 2.9

/// VMOptions=--dwarf-stack-traces --save-debugging-info=dwarf.so

import 'dart:convert';
import 'dart:io';

import 'package:native_stack_traces/native_stack_traces.dart';
import 'package:path/path.dart' as path;
import 'package:expect/expect.dart';

@pragma("vm:prefer-inline")
bar() {
  // Keep the 'throw' and its argument on separate lines.
  throw // force linebreak with dartfmt
      "Hello, Dwarf!";
}

@pragma("vm:never-inline")
foo() {
  bar();
}

Future<void> main() async {
  String rawStack = "";
  try {
    foo();
  } catch (e, st) {
    rawStack = st.toString();
  }

  if (path.basenameWithoutExtension(Platform.executable) !=
      "dart_precompiled_runtime") {
    return; // Not running from an AOT compiled snapshot.
  }

  if (Platform.isAndroid) {
    return; // Generated dwarf.so not available on the test device.
  }

  final dwarf = Dwarf.fromFile("dwarf.so");

  await checkStackTrace(rawStack, dwarf, expectedCallsInfo);
}

Future<void> checkStackTrace(String rawStack, Dwarf dwarf,
    List<List<DartCallInfo>> expectedCallsInfo) async {
  print("");
  print("Raw stack trace:");
  print(rawStack);

  final rawLines =
      await Stream.value(rawStack).transform(const LineSplitter()).toList();

  final pcOffsets = collectPCOffsets(rawLines).toList();

  // We should have at least enough PC addresses to cover the frames we'll be
  // checking.
  Expect.isTrue(pcOffsets.length >= expectedCallsInfo.length);

  final virtualAddresses =
      pcOffsets.map((o) => dwarf.virtualAddressOf(o)).toList();

  // Some double-checks using other information in the non-symbolic stack trace.
  final dsoBase = dsoBaseAddresses(rawLines).single;
  final absolutes = absoluteAddresses(rawLines);
  final relocatedAddresses = absolutes.map((a) => a - dsoBase);
  final explicits = explicitVirtualAddresses(rawLines);

  // Explicits will be empty if not generating ELF snapshots directly, which
  // means we can't depend on virtual addresses in the snapshot lining up with
  // those in the separate debugging information.
  if (explicits.isNotEmpty) {
    // Direct-to-ELF snapshots should have a build ID.
    Expect.isNotNull(dwarf.buildId);
    Expect.deepEquals(relocatedAddresses, virtualAddresses);
    Expect.deepEquals(explicits, virtualAddresses);
  }

  final gotCallsInfo = <List<DartCallInfo>>[];

  for (final addr in virtualAddresses) {
    final externalCallInfo = dwarf.callInfoFor(addr);
    Expect.isNotNull(externalCallInfo);
    final allCallInfo = dwarf.callInfoFor(addr, includeInternalFrames: true);
    Expect.isNotNull(allCallInfo);
    for (final call in externalCallInfo) {
      Expect.isTrue(call is DartCallInfo, "got non-Dart call info ${call}");
      Expect.isFalse(call.isInternal);
      Expect.isTrue(allCallInfo.contains(call),
          "External call info ${call} is not among all calls");
    }
    for (final call in allCallInfo) {
      if (!call.isInternal) {
        Expect.isTrue(externalCallInfo.contains(call),
            "External call info ${call} is not among external calls");
      }
    }
    gotCallsInfo.add(externalCallInfo.cast<DartCallInfo>().toList());
  }

  print("");
  print("Call information for PC addresses:");
  for (var i = 0; i < virtualAddresses.length; i++) {
    print("For PC 0x${virtualAddresses[i].toRadixString(16)}:");
    print("  Calls corresponding to user or library code:");
    gotCallsInfo[i].forEach((frame) => print("    ${frame}"));
  }

  // Remove empty entries which correspond to skipped internal frames.
  gotCallsInfo.removeWhere((calls) => calls.isEmpty);

  checkFrames(gotCallsInfo, expectedCallsInfo);

  final gotSymbolizedLines = await Stream.fromIterable(rawLines)
      .transform(DwarfStackTraceDecoder(dwarf, includeInternalFrames: false))
      .toList();

  final gotSymbolizedCalls =
      gotSymbolizedLines.where((s) => s.startsWith('#')).toList();

  print("");
  print("Symbolized stack trace:");
  gotSymbolizedLines.forEach(print);
  print("");
  print("Extracted calls:");
  gotSymbolizedCalls.forEach(print);

  final expectedStrings = extractCallStrings(expectedCallsInfo);
  // There are two strings in the list for each line in the output.
  final expectedCallCount = expectedStrings.length ~/ 2;

  Expect.isTrue(gotSymbolizedCalls.length >= expectedCallCount);

  // Strip off any unexpected lines, so we can also make sure we didn't get
  // unexpected calls prior to those calls we expect.
  final gotCallsTrace =
      gotSymbolizedCalls.sublist(0, expectedCallCount).join('\n');

  Expect.stringContainsInOrder(gotCallsTrace, expectedStrings);
}

final expectedCallsInfo = <List<DartCallInfo>>[
  // The first frame should correspond to the throw in bar, which was inlined
  // into foo (so we'll get information for two calls for that PC address).
  [
    DartCallInfo(
        function: "bar",
        filename: "dwarf_stack_trace_test.dart",
        line: 19,
        column: 3,
        inlined: true),
    DartCallInfo(
        function: "foo",
        filename: "dwarf_stack_trace_test.dart",
        line: 25,
        column: 3,
        inlined: false)
  ],
  // The second frame corresponds to call to foo in main.
  [
    DartCallInfo(
        function: "main",
        filename: "dwarf_stack_trace_test.dart",
        line: 31,
        column: 5,
        inlined: false)
  ],
  // Don't assume anything about any of the frames below the call to foo
  // in main, as this makes the test too brittle.
];

void checkFrames(
    List<List<DartCallInfo>> gotInfo, List<List<DartCallInfo>> expectedInfo) {
  // There may be frames below those we check.
  Expect.isTrue(gotInfo.length >= expectedInfo.length);

  // We can't just use deep equality, since we only have the filenames in the
  // expected version, not the whole path, and we don't really care if
  // non-positive line numbers match, as long as they're both non-positive.
  for (var i = 0; i < expectedInfo.length; i++) {
    for (var j = 0; j < expectedInfo[i].length; j++) {
      final got = gotInfo[i][j];
      final expected = expectedInfo[i][j];
      Expect.equals(expected.function, got.function);
      Expect.equals(expected.inlined, got.inlined);
      Expect.equals(expected.filename, path.basename(got.filename));
      if (expected.isInternal) {
        Expect.isTrue(got.isInternal);
      } else {
        Expect.equals(expected.line, got.line);
      }
    }
  }
}

List<String> extractCallStrings(List<List<CallInfo>> expectedCalls) {
  var ret = <String>[];
  for (final frame in expectedCalls) {
    for (final call in frame) {
      if (call is DartCallInfo) {
        ret.add(call.function);
        if (call.isInternal) {
          ret.add("${call.filename}:??");
        } else {
          ret.add("${call.filename}:${call.line}");
        }
      }
    }
  }
  return ret;
}

Iterable<int> parseUsingAddressRegExp(RegExp re, Iterable<String> lines) sync* {
  for (final line in lines) {
    final match = re.firstMatch(line);
    if (match == null) continue;
    final s = match.group(1);
    if (s == null) continue;
    yield int.parse(s, radix: 16);
  }
}

final _absRE = RegExp(r'abs ([a-f\d]+)');

Iterable<int> absoluteAddresses(Iterable<String> lines) =>
    parseUsingAddressRegExp(_absRE, lines);

final _virtRE = RegExp(r'virt ([a-f\d]+)');

Iterable<int> explicitVirtualAddresses(Iterable<String> lines) =>
    parseUsingAddressRegExp(_virtRE, lines);

final _dsoBaseRE = RegExp(r'isolate_dso_base: ([a-f\d]+)');

Iterable<int> dsoBaseAddresses(Iterable<String> lines) =>
    parseUsingAddressRegExp(_dsoBaseRE, lines);
