Split elf_writer_debug.cc to several files.

Refactoring only. The file has grown significantly over time,
and it is time to split it so it can be better managed.

Change-Id: Idce0231718add722292f4701df353d5baf31de5f
diff --git a/compiler/debug/elf_debug_loc_writer.h b/compiler/debug/elf_debug_loc_writer.h
new file mode 100644
index 0000000..fd7f949
--- /dev/null
+++ b/compiler/debug/elf_debug_loc_writer.h
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2016 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_DEBUG_ELF_DEBUG_LOC_WRITER_H_
+#define ART_COMPILER_DEBUG_ELF_DEBUG_LOC_WRITER_H_
+
+#include <map>
+
+#include "arch/instruction_set.h"
+#include "compiled_method.h"
+#include "debug/dwarf/debug_info_entry_writer.h"
+#include "debug/dwarf/register.h"
+#include "debug/method_debug_info.h"
+#include "stack_map.h"
+
+namespace art {
+namespace debug {
+using Reg = dwarf::Reg;
+
+static Reg GetDwarfCoreReg(InstructionSet isa, int machine_reg) {
+  switch (isa) {
+    case kArm:
+    case kThumb2:
+      return Reg::ArmCore(machine_reg);
+    case kArm64:
+      return Reg::Arm64Core(machine_reg);
+    case kX86:
+      return Reg::X86Core(machine_reg);
+    case kX86_64:
+      return Reg::X86_64Core(machine_reg);
+    case kMips:
+      return Reg::MipsCore(machine_reg);
+    case kMips64:
+      return Reg::Mips64Core(machine_reg);
+    case kNone:
+      LOG(FATAL) << "No instruction set";
+  }
+  UNREACHABLE();
+}
+
+static Reg GetDwarfFpReg(InstructionSet isa, int machine_reg) {
+  switch (isa) {
+    case kArm:
+    case kThumb2:
+      return Reg::ArmFp(machine_reg);
+    case kArm64:
+      return Reg::Arm64Fp(machine_reg);
+    case kX86:
+      return Reg::X86Fp(machine_reg);
+    case kX86_64:
+      return Reg::X86_64Fp(machine_reg);
+    case kMips:
+      return Reg::MipsFp(machine_reg);
+    case kMips64:
+      return Reg::Mips64Fp(machine_reg);
+    case kNone:
+      LOG(FATAL) << "No instruction set";
+  }
+  UNREACHABLE();
+}
+
+struct VariableLocation {
+  uint32_t low_pc;
+  uint32_t high_pc;
+  DexRegisterLocation reg_lo;  // May be None if the location is unknown.
+  DexRegisterLocation reg_hi;  // Most significant bits of 64-bit value.
+};
+
+// Get the location of given dex register (e.g. stack or machine register).
+// Note that the location might be different based on the current pc.
+// The result will cover all ranges where the variable is in scope.
+std::vector<VariableLocation> GetVariableLocations(const MethodDebugInfo* method_info,
+                                                   uint16_t vreg,
+                                                   bool is64bitValue,
+                                                   uint32_t dex_pc_low,
+                                                   uint32_t dex_pc_high) {
+  std::vector<VariableLocation> variable_locations;
+
+  // Get stack maps sorted by pc (they might not be sorted internally).
+  const CodeInfo code_info(method_info->compiled_method->GetVmapTable().data());
+  const StackMapEncoding encoding = code_info.ExtractEncoding();
+  std::map<uint32_t, StackMap> stack_maps;
+  for (uint32_t s = 0; s < code_info.GetNumberOfStackMaps(); s++) {
+    StackMap stack_map = code_info.GetStackMapAt(s, encoding);
+    DCHECK(stack_map.IsValid());
+    const uint32_t low_pc = method_info->low_pc + stack_map.GetNativePcOffset(encoding);
+    DCHECK_LE(low_pc, method_info->high_pc);
+    stack_maps.emplace(low_pc, stack_map);
+  }
+
+  // Create entries for the requested register based on stack map data.
+  for (auto it = stack_maps.begin(); it != stack_maps.end(); it++) {
+    const StackMap& stack_map = it->second;
+    const uint32_t low_pc = it->first;
+    auto next_it = it;
+    next_it++;
+    const uint32_t high_pc = next_it != stack_maps.end() ? next_it->first
+                                                         : method_info->high_pc;
+    DCHECK_LE(low_pc, high_pc);
+    if (low_pc == high_pc) {
+      continue;  // Ignore if the address range is empty.
+    }
+
+    // Check that the stack map is in the requested range.
+    uint32_t dex_pc = stack_map.GetDexPc(encoding);
+    if (!(dex_pc_low <= dex_pc && dex_pc < dex_pc_high)) {
+      continue;
+    }
+
+    // Find the location of the dex register.
+    DexRegisterLocation reg_lo = DexRegisterLocation::None();
+    DexRegisterLocation reg_hi = DexRegisterLocation::None();
+    if (stack_map.HasDexRegisterMap(encoding)) {
+      DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(
+          stack_map, encoding, method_info->code_item->registers_size_);
+      reg_lo = dex_register_map.GetDexRegisterLocation(
+          vreg, method_info->code_item->registers_size_, code_info, encoding);
+      if (is64bitValue) {
+        reg_hi = dex_register_map.GetDexRegisterLocation(
+            vreg + 1, method_info->code_item->registers_size_, code_info, encoding);
+      }
+    }
+
+    // Add location entry for this address range.
+    if (!variable_locations.empty() &&
+        variable_locations.back().reg_lo == reg_lo &&
+        variable_locations.back().reg_hi == reg_hi &&
+        variable_locations.back().high_pc == low_pc) {
+      // Merge with the previous entry (extend its range).
+      variable_locations.back().high_pc = high_pc;
+    } else {
+      variable_locations.push_back({low_pc, high_pc, reg_lo, reg_hi});
+    }
+  }
+
+  return variable_locations;
+}
+
+// Write table into .debug_loc which describes location of dex register.
+// The dex register might be valid only at some points and it might
+// move between machine registers and stack.
+static void WriteDebugLocEntry(const MethodDebugInfo* method_info,
+                               uint16_t vreg,
+                               bool is64bitValue,
+                               uint32_t compilation_unit_low_pc,
+                               uint32_t dex_pc_low,
+                               uint32_t dex_pc_high,
+                               InstructionSet isa,
+                               dwarf::DebugInfoEntryWriter<>* debug_info,
+                               std::vector<uint8_t>* debug_loc_buffer,
+                               std::vector<uint8_t>* debug_ranges_buffer) {
+  using Kind = DexRegisterLocation::Kind;
+  if (!method_info->IsFromOptimizingCompiler()) {
+    return;
+  }
+
+  dwarf::Writer<> debug_loc(debug_loc_buffer);
+  dwarf::Writer<> debug_ranges(debug_ranges_buffer);
+  debug_info->WriteSecOffset(dwarf::DW_AT_location, debug_loc.size());
+  debug_info->WriteSecOffset(dwarf::DW_AT_start_scope, debug_ranges.size());
+
+  std::vector<VariableLocation> variable_locations = GetVariableLocations(
+      method_info,
+      vreg,
+      is64bitValue,
+      dex_pc_low,
+      dex_pc_high);
+
+  // Write .debug_loc entries.
+  const bool is64bit = Is64BitInstructionSet(isa);
+  std::vector<uint8_t> expr_buffer;
+  for (const VariableLocation& variable_location : variable_locations) {
+    // Translate dex register location to DWARF expression.
+    // Note that 64-bit value might be split to two distinct locations.
+    // (for example, two 32-bit machine registers, or even stack and register)
+    dwarf::Expression expr(&expr_buffer);
+    DexRegisterLocation reg_lo = variable_location.reg_lo;
+    DexRegisterLocation reg_hi = variable_location.reg_hi;
+    for (int piece = 0; piece < (is64bitValue ? 2 : 1); piece++) {
+      DexRegisterLocation reg_loc = (piece == 0 ? reg_lo : reg_hi);
+      const Kind kind = reg_loc.GetKind();
+      const int32_t value = reg_loc.GetValue();
+      if (kind == Kind::kInStack) {
+        const size_t frame_size = method_info->compiled_method->GetFrameSizeInBytes();
+        // The stack offset is relative to SP. Make it relative to CFA.
+        expr.WriteOpFbreg(value - frame_size);
+        if (piece == 0 && reg_hi.GetKind() == Kind::kInStack &&
+            reg_hi.GetValue() == value + 4) {
+          break;  // the high word is correctly implied by the low word.
+        }
+      } else if (kind == Kind::kInRegister) {
+        expr.WriteOpReg(GetDwarfCoreReg(isa, value).num());
+        if (piece == 0 && reg_hi.GetKind() == Kind::kInRegisterHigh &&
+            reg_hi.GetValue() == value) {
+          break;  // the high word is correctly implied by the low word.
+        }
+      } else if (kind == Kind::kInFpuRegister) {
+        if ((isa == kArm || isa == kThumb2) &&
+            piece == 0 && reg_hi.GetKind() == Kind::kInFpuRegister &&
+            reg_hi.GetValue() == value + 1 && value % 2 == 0) {
+          // Translate S register pair to D register (e.g. S4+S5 to D2).
+          expr.WriteOpReg(Reg::ArmDp(value / 2).num());
+          break;
+        }
+        expr.WriteOpReg(GetDwarfFpReg(isa, value).num());
+        if (piece == 0 && reg_hi.GetKind() == Kind::kInFpuRegisterHigh &&
+            reg_hi.GetValue() == reg_lo.GetValue()) {
+          break;  // the high word is correctly implied by the low word.
+        }
+      } else if (kind == Kind::kConstant) {
+        expr.WriteOpConsts(value);
+        expr.WriteOpStackValue();
+      } else if (kind == Kind::kNone) {
+        break;
+      } else {
+        // kInStackLargeOffset and kConstantLargeValue are hidden by GetKind().
+        // kInRegisterHigh and kInFpuRegisterHigh should be handled by
+        // the special cases above and they should not occur alone.
+        LOG(ERROR) << "Unexpected register location kind: "
+                   << DexRegisterLocation::PrettyDescriptor(kind);
+        break;
+      }
+      if (is64bitValue) {
+        // Write the marker which is needed by split 64-bit values.
+        // This code is skipped by the special cases.
+        expr.WriteOpPiece(4);
+      }
+    }
+
+    if (expr.size() > 0) {
+      if (is64bit) {
+        debug_loc.PushUint64(variable_location.low_pc - compilation_unit_low_pc);
+        debug_loc.PushUint64(variable_location.high_pc - compilation_unit_low_pc);
+      } else {
+        debug_loc.PushUint32(variable_location.low_pc - compilation_unit_low_pc);
+        debug_loc.PushUint32(variable_location.high_pc - compilation_unit_low_pc);
+      }
+      // Write the expression.
+      debug_loc.PushUint16(expr.size());
+      debug_loc.PushData(expr.data());
+    } else {
+      // Do not generate .debug_loc if the location is not known.
+    }
+  }
+  // Write end-of-list entry.
+  if (is64bit) {
+    debug_loc.PushUint64(0);
+    debug_loc.PushUint64(0);
+  } else {
+    debug_loc.PushUint32(0);
+    debug_loc.PushUint32(0);
+  }
+
+  // Write .debug_ranges entries.
+  // This includes ranges where the variable is in scope but the location is not known.
+  for (size_t i = 0; i < variable_locations.size(); i++) {
+    uint32_t low_pc = variable_locations[i].low_pc;
+    uint32_t high_pc = variable_locations[i].high_pc;
+    while (i + 1 < variable_locations.size() && variable_locations[i+1].low_pc == high_pc) {
+      // Merge address range with the next entry.
+      high_pc = variable_locations[++i].high_pc;
+    }
+    if (is64bit) {
+      debug_ranges.PushUint64(low_pc - compilation_unit_low_pc);
+      debug_ranges.PushUint64(high_pc - compilation_unit_low_pc);
+    } else {
+      debug_ranges.PushUint32(low_pc - compilation_unit_low_pc);
+      debug_ranges.PushUint32(high_pc - compilation_unit_low_pc);
+    }
+  }
+  // Write end-of-list entry.
+  if (is64bit) {
+    debug_ranges.PushUint64(0);
+    debug_ranges.PushUint64(0);
+  } else {
+    debug_ranges.PushUint32(0);
+    debug_ranges.PushUint32(0);
+  }
+}
+
+}  // namespace debug
+}  // namespace art
+
+#endif  // ART_COMPILER_DEBUG_ELF_DEBUG_LOC_WRITER_H_
+