//===-- llvm/CodeGen/DwarfWriter.cpp - Dwarf Framework ----------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by James M. Laskey and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains support for writing dwarf debug info into asm files.
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/DwarfWriter.h"

#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineDebugInfo.h"
#include "llvm/Support/CommandLine.h"

#include <iostream>

using namespace llvm;

static cl::opt<bool>
DwarfVerbose("dwarf-verbose", cl::Hidden,
                                cl::desc("Add comments to dwarf directives."));

/// EmitULEB128Bytes - Emit an assembler byte data directive to compose an
/// unsigned leb128 value.  Comment is added to the end of the directive if
/// DwarfVerbose is true (should not contain any newlines.)
///
void DwarfWriter::EmitULEB128Bytes(unsigned Value, const char *Comment) const {
  if (hasLEB128) {
    O << "\t.uleb128\t"
      << Value;
  } else {
    O << Asm->Data8bitsDirective;
    EmitULEB128(Value);
  }
  if (DwarfVerbose) {
    O << "\t"
      << Asm->CommentString
      << " "
      << Comment
      << " "
      << Value;
  }
  O << "\n";
}

/// EmitSLEB128Bytes - Emit an assembler byte data directive to compose a
/// signed leb128 value.  Comment is added to the end of the directive if
/// DwarfVerbose is true (should not contain any newlines.)
///
void DwarfWriter::EmitSLEB128Bytes(int Value, const char *Comment) const {
  if (hasLEB128) {
    O << "\t.sleb128\t"
      << Value;
  } else {
    O << Asm->Data8bitsDirective;
    EmitSLEB128(Value);
  }
  if (DwarfVerbose) {
    O << "\t"
      << Asm->CommentString
      << " "
      << Comment
      << " "
      << Value;
  }
  O << "\n";
}

/// EmitHex - Emit a hexidecimal string to the output stream.
///
void DwarfWriter::EmitHex(unsigned Value) const {
  O << "0x"
    << std::hex
    << Value
    << std::dec;
}

/// EmitComment - Emit a simple string comment.
///
void DwarfWriter::EmitComment(const char *Comment) const {
  O << "\t"
    << Asm->CommentString
    << " "
    << Comment
    << "\n";
}

/// EmitULEB128 - Emit a series of hexidecimal values (separated by commas)
/// representing an unsigned leb128 value.
///
void DwarfWriter::EmitULEB128(unsigned Value) const {
  do {
    unsigned Byte = Value & 0x7f;
    Value >>= 7;
    if (Value) Byte |= 0x80;
    EmitHex(Byte);
    if (Value) O << ", ";
  } while (Value);
}

/// EmitSLEB128 - Emit a series of hexidecimal values (separated by commas)
/// representing a signed leb128 value.
///
void DwarfWriter::EmitSLEB128(int Value) const {
  int Sign = Value >> (8 * sizeof(Value) - 1);
  bool IsMore;
  
  do {
    unsigned Byte = Value & 0x7f;
    Value >>= 7;
    IsMore = Value != Sign || ((Byte ^ Sign) & 0x40) != 0;
    if (IsMore) Byte |= 0x80;
    EmitHex(Byte);
    if (IsMore) O << ", ";
  } while (IsMore);
}

/// EmitLabelName - Emit label name for internal use by dwarf.
///
void DwarfWriter::EmitLabelName(const char *Tag, int Num) const {
  O << Asm->PrivateGlobalPrefix
    << "debug_"
    << Tag
    << Num;
}

/// EmitLabel - Emit location label for internal use by dwarf.
///
void DwarfWriter::EmitLabel(const char *Tag, int Num) const {
  EmitLabelName(Tag, Num);
  O << ":\n";
}

/// EmitInitial -Emit initial dwarf declarations.
///
void DwarfWriter::EmitInitial() const {
  // Dwarf section's base addresses.
  Asm->SwitchSection(DwarfAbbrevSection, 0);
  EmitLabel("abbrev", 0);
  Asm->SwitchSection(DwarfInfoSection, 0);
  EmitLabel("info", 0);
  Asm->SwitchSection(DwarfLineSection, 0);
  EmitLabel("line", 0);
}

/// ShouldEmitDwarf - Determine if dwarf declarations should be made.
///
bool DwarfWriter::ShouldEmitDwarf() {
  // Check if debug info is present.
  if (!DebugInfo || !DebugInfo->hasInfo()) return false;
  
  // Make sure initial declarations are made.
  if (!didInitial) {
    EmitInitial();
    didInitial = true;
  }
  
  // Okay to emit.
  return true;
}

/// BeginModule - Emit all dwarf sections that should come prior to the content.
///
void DwarfWriter::BeginModule() {
  if (!ShouldEmitDwarf()) return;
  EmitComment("Dwarf Begin Module");
}

/// EndModule - Emit all dwarf sections that should come after the content.
///
void DwarfWriter::EndModule() {
  if (!ShouldEmitDwarf()) return;
  EmitComment("Dwarf End Module");
  // Print out dwarf file info
  std::vector<std::string> Sources = DebugInfo->getSourceFiles();
  for (unsigned i = 0, N = Sources.size(); i < N; i++) {
    O << "\t; .file\t" << (i + 1) << "," << "\"" << Sources[i]  << "\"" << "\n";
  }
}

/// BeginFunction - Emit pre-function debug information.
///
void DwarfWriter::BeginFunction() {
  if (!ShouldEmitDwarf()) return;
  EmitComment("Dwarf Begin Function");
}

/// EndFunction - Emit post-function debug information.
///
void DwarfWriter::EndFunction() {
  if (!ShouldEmitDwarf()) return;
  EmitComment("Dwarf End Function");
}