/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ART_COMPILER_CFI_TEST_H_
#define ART_COMPILER_CFI_TEST_H_

#include <memory>
#include <sstream>
#include <vector>

#include "arch/instruction_set.h"
#include "base/enums.h"
#include "debug/dwarf/dwarf_constants.h"
#include "debug/dwarf/dwarf_test.h"
#include "debug/dwarf/headers.h"
#include "disassembler.h"
#include "gtest/gtest.h"
#include "thread.h"

namespace art {

constexpr dwarf::CFIFormat kCFIFormat = dwarf::DW_DEBUG_FRAME_FORMAT;

class CFITest : public dwarf::DwarfTest {
 public:
  void GenerateExpected(FILE* f, InstructionSet isa, const char* isa_str,
                        ArrayRef<const uint8_t> actual_asm,
                        ArrayRef<const uint8_t> actual_cfi) {
    std::vector<std::string> lines;
    // Print the raw bytes.
    fprintf(f, "static constexpr uint8_t expected_asm_%s[] = {", isa_str);
    HexDump(f, actual_asm);
    fprintf(f, "\n};\n");
    fprintf(f, "static constexpr uint8_t expected_cfi_%s[] = {", isa_str);
    HexDump(f, actual_cfi);
    fprintf(f, "\n};\n");
    // Pretty-print CFI opcodes.
    constexpr bool is64bit = false;
    dwarf::DebugFrameOpCodeWriter<> initial_opcodes;
    dwarf::WriteCIE(is64bit, dwarf::Reg(8), initial_opcodes, kCFIFormat, &debug_frame_data_);
    std::vector<uintptr_t> debug_frame_patches;
    dwarf::WriteFDE(is64bit,
                    /* section_address= */ 0,
                    /* cie_address= */ 0,
                    /* code_address= */ 0,
                    actual_asm.size(),
                    actual_cfi,
                    kCFIFormat,
                    /* buffer_address= */ 0,
                    &debug_frame_data_,
                    &debug_frame_patches);
    ReformatCfi(Objdump(false, "-W"), &lines);
    // Pretty-print assembly.
    const uint8_t* asm_base = actual_asm.data();
    const uint8_t* asm_end = asm_base + actual_asm.size();
    auto* opts = new DisassemblerOptions(false,
                                         asm_base,
                                         asm_end,
                                         true,
                                         is64bit
                                             ? &Thread::DumpThreadOffset<PointerSize::k64>
                                             : &Thread::DumpThreadOffset<PointerSize::k32>);
    std::unique_ptr<Disassembler> disasm(Disassembler::Create(isa, opts));
    std::stringstream stream;
    const uint8_t* base = actual_asm.data() + (isa == InstructionSet::kThumb2 ? 1 : 0);
    disasm->Dump(stream, base, base + actual_asm.size());
    ReformatAsm(&stream, &lines);
    // Print CFI and assembly interleaved.
    std::stable_sort(lines.begin(), lines.end(), CompareByAddress);
    for (const std::string& line : lines) {
      fprintf(f, "// %s\n", line.c_str());
    }
    fprintf(f, "\n");
  }

 private:
  // Helper - get offset just past the end of given string.
  static size_t FindEndOf(const std::string& str, const char* substr) {
    size_t pos = str.find(substr);
    CHECK_NE(std::string::npos, pos);
    return pos + strlen(substr);
  }

  // Spit to lines and remove raw instruction bytes.
  static void ReformatAsm(std::stringstream* stream,
                          std::vector<std::string>* output) {
    std::string line;
    while (std::getline(*stream, line)) {
      line = line.substr(0, FindEndOf(line, ": ")) +
             line.substr(FindEndOf(line, "\t"));
      size_t pos;
      while ((pos = line.find("  ")) != std::string::npos) {
        line = line.replace(pos, 2, " ");
      }
      while (!line.empty() && line.back() == ' ') {
        line.pop_back();
      }
      output->push_back(line);
    }
  }

  // Find interesting parts of objdump output and prefix the lines with address.
  static void ReformatCfi(const std::vector<std::string>& lines,
                          std::vector<std::string>* output) {
    std::string address;
    for (const std::string& line : lines) {
      if (line.find("DW_CFA_nop") != std::string::npos) {
        // Ignore.
      } else if (line.find("DW_CFA_advance_loc") != std::string::npos) {
        // The last 8 characters are the address.
        address = "0x" + line.substr(line.size() - 8);
      } else if (line.find("DW_CFA_") != std::string::npos) {
        std::string new_line(line);
        // "bad register" warning is caused by always using host (x86) objdump.
        const char* bad_reg = "bad register: ";
        size_t pos;
        if ((pos = new_line.find(bad_reg)) != std::string::npos) {
          new_line = new_line.replace(pos, strlen(bad_reg), "");
        }
        // Remove register names in parentheses since they have x86 names.
        if ((pos = new_line.find(" (")) != std::string::npos) {
          new_line = new_line.replace(pos, FindEndOf(new_line, ")") - pos, "");
        }
        // Use the .cfi_ prefix.
        new_line = ".cfi_" + new_line.substr(FindEndOf(new_line, "DW_CFA_"));
        output->push_back(address + ": " + new_line);
      }
    }
  }

  // Compare strings by the address prefix.
  static bool CompareByAddress(const std::string& lhs, const std::string& rhs) {
    EXPECT_EQ(lhs[10], ':');
    EXPECT_EQ(rhs[10], ':');
    return strncmp(lhs.c_str(), rhs.c_str(), 10) < 0;
  }

  // Pretty-print byte array.  12 bytes per line.
  static void HexDump(FILE* f, ArrayRef<const uint8_t> data) {
    for (size_t i = 0; i < data.size(); i++) {
      fprintf(f, i % 12 == 0 ? "\n    " : " ");  // Whitespace.
      fprintf(f, "0x%02X,", data[i]);
    }
  }
};

}  // namespace art

#endif  // ART_COMPILER_CFI_TEST_H_
