void
Win64Object::DirProcFrame(DirectiveInfo& info, Diagnostic& diags)
{
    assert(info.isObject(m_object));
    NameValues& namevals = info.getNameValues();
    SourceLocation source = info.getSource();

    NameValue& name_nv = namevals.front();
    if (!name_nv.isId())
    {
        diags.Report(info.getSource(), diag::err_value_id)
            << name_nv.getValueRange();
        return;
    }
    llvm::StringRef name = name_nv.getId();

    if (m_proc_frame.isValid())
    {
        diags.Report(info.getSource(),
                     diags.getCustomDiagID(Diagnostic::Error,
            "nested procedures not supported (didn't use [ENDPROC_FRAME]?)"));
        diags.Report(m_proc_frame,
                     diags.getCustomDiagID(Diagnostic::Note,
                                           "previous procedure started here"));
        return;
    }
    m_proc_frame = source;
    m_done_prolog = SourceLocation();
    m_unwind.reset(new UnwindInfo);

    SymbolRef proc = m_object.getSymbol(name);
    proc->Use(source);
    m_unwind->setProc(proc);

    // Optional error handler
    if (namevals.size() > 1)
    {
        NameValue& ehandler_nv = namevals[1];
        if (!ehandler_nv.isId())
        {
            diags.Report(info.getSource(), diag::err_value_id)
                << ehandler_nv.getValueRange();
            return;
        }
        SymbolRef ehandler = m_object.getSymbol(ehandler_nv.getId());
        ehandler->Use(ehandler_nv.getValueRange().getBegin());
        m_unwind->setEHandler(ehandler);
    }
}
bool
Win64Object::CheckProcFrameState(SourceLocation dir_source, Diagnostic& diags)
{
    if (!m_proc_frame.isValid())
    {
        diags.Report(dir_source,
                     diags.getCustomDiagID(Diagnostic::Error,
                                           "no preceding [PROC_FRAME]"));
        return false;
    }

    if (m_done_prolog.isValid())
    {
        diags.Report(dir_source,
                     diags.getCustomDiagID(Diagnostic::Error,
                                           "must come before [END_PROLOGUE]"));
        diags.Report(m_done_prolog,
            diags.getCustomDiagID(Diagnostic::Note, "prologue ended here"));
        return false;
    }
    return true;
}
bool
BinObject::setMapFilename(const NameValue& nv,
                          SourceLocation dir_source,
                          Diagnostic& diags)
{
    if (!m_map_filename.empty())
    {
        diags.Report(nv.getValueRange().getBegin(),
            diags.getCustomDiagID(Diagnostic::Error,
                                  "map file already specified"));
        return true;
    }

    if (!nv.isString())
    {
        diags.Report(nv.getValueRange().getBegin(),
                     diag::err_value_string_or_id);
        return false;
    }
    m_map_filename = nv.getString();
    return true;
}
void
BinObject::DirOrg(DirectiveInfo& info, Diagnostic& diags)
{
    // We only allow a single ORG in a program.
    if (m_org.get() != 0)
    {
        diags.Report(info.getSource(),
            diags.getCustomDiagID(Diagnostic::Error,
                                  "program origin redefined"));
        return;
    }

    // ORG takes just a simple expression as param
    const NameValue& nv = info.getNameValues().front();
    if (!nv.isExpr())
    {
        diags.Report(info.getSource(), diag::err_value_expression)
            << nv.getValueRange();
        return;
    }
    m_org.reset(new Expr(nv.getExpr(info.getObject())));
    m_org_source = info.getSource();
}
void
Win64Object::DirEndProcFrame(DirectiveInfo& info, Diagnostic& diags)
{
    assert(info.isObject(m_object));
    SourceLocation source = info.getSource();

    if (!m_proc_frame.isValid())
    {
        diags.Report(source,
                     diags.getCustomDiagID(Diagnostic::Error,
                                           "no preceding [PROC_FRAME]"));
        return;
    }
    if (!m_done_prolog.isValid())
    {
        diags.Report(info.getSource(),
                     diags.getCustomDiagID(Diagnostic::Error,
            "ended procedure without ending prologue"));
        diags.Report(m_proc_frame,
                     diags.getCustomDiagID(Diagnostic::Note,
                                           "procedure started here"));
        m_unwind.reset(0);
        m_proc_frame = SourceLocation();
        return;
    }
    assert(m_unwind.get() != 0 && "unwind info not present");

    SymbolRef proc_sym = m_unwind->getProc();

    SymbolRef curpos = m_object.getSymbol(info.getLocation());

    //
    // Add unwind info to end of .xdata section.
    //

    Section* xdata = m_object.FindSection(".xdata");

    // Create xdata section if needed.
    if (!xdata)
        xdata = AppendSection(".xdata", source, diags);

    // Get current position in .xdata section.
    SymbolRef unwindpos = m_object.AddNonTableSymbol("$");
    Location unwindpos_loc =
        {&xdata->bytecodes_back(), xdata->bytecodes_back().getFixedLen()};
    unwindpos->DefineLabel(unwindpos_loc);
    // Get symbol for .xdata as we'll want to reference it with WRT.
    SymbolRef xdata_sym = xdata->getAssocData<CoffSection>()->m_sym;

    // Add unwind info.  Use line number of start of procedure.
    Arch& arch = *m_object.getArch();
    Generate(m_unwind, *xdata, m_proc_frame, arch, diags);

    //
    // Add function lookup to end of .pdata section.
    //

    Section* pdata = m_object.FindSection(".pdata");

    // Initialize pdata section if needed.
    if (!pdata)
        pdata = AppendSection(".pdata", source, diags);

    // Add function structure to end of .pdata
    AppendData(*pdata, std::auto_ptr<Expr>(new Expr(proc_sym)), 4, arch,
               source, diags);
    AppendData(*pdata, std::auto_ptr<Expr>(new Expr(WRT(curpos, proc_sym))),
               4, arch, source, diags);
    AppendData(*pdata,
               std::auto_ptr<Expr>(new Expr(WRT(unwindpos, xdata_sym))),
               4, arch, source, diags);

    m_proc_frame = SourceLocation();
    m_done_prolog = SourceLocation();
}
void
BinObject::DirSection(DirectiveInfo& info, Diagnostic& diags)
{
    assert(info.isObject(m_object));
    NameValues& nvs = info.getNameValues();
    SourceLocation source = info.getSource();

    NameValue& sectname_nv = nvs.front();
    if (!sectname_nv.isString())
    {
        diags.Report(sectname_nv.getValueRange().getBegin(),
                     diag::err_value_string_or_id);
        return;
    }
    llvm::StringRef sectname = sectname_nv.getString();

    Section* sect = m_object.FindSection(sectname);
    bool first = true;
    if (sect)
        first = sect->isDefault();
    else
        sect = AppendSection(sectname, source, diags);

    m_object.setCurSection(sect);
    sect->setDefault(false);

    // No name/values, so nothing more to do
    if (nvs.size() <= 1)
        return;

    // Ignore flags if we've seen this section before
    if (!first)
    {
        diags.Report(info.getSource(), diag::warn_section_redef_flags);
        return;
    }

    // Parse section flags
    bool has_follows = false, has_vfollows = false;
    bool has_start = false, has_vstart = false;
    std::auto_ptr<Expr> start(0);
    std::auto_ptr<Expr> vstart(0);

    BinSection* bsd = sect->getAssocData<BinSection>();
    assert(bsd);
    unsigned long bss = sect->isBSS();
    unsigned long code = sect->isCode();

    DirHelpers helpers;
    helpers.Add("follows", true,
                TR1::bind(&DirString, _1, _2, &bsd->follows, &has_follows));
    helpers.Add("vfollows", true,
                TR1::bind(&DirString, _1, _2, &bsd->vfollows, &has_vfollows));
    helpers.Add("start", true,
                TR1::bind(&DirExpr, _1, _2, &m_object, &start, &has_start));
    helpers.Add("vstart", true,
                TR1::bind(&DirExpr, _1, _2, &m_object, &vstart, &has_vstart));
    helpers.Add("align", true,
                TR1::bind(&DirIntNumPower2, _1, _2, &m_object, &bsd->align,
                          &bsd->has_align));
    helpers.Add("valign", true,
                TR1::bind(&DirIntNumPower2, _1, _2, &m_object, &bsd->valign,
                           &bsd->has_valign));
    helpers.Add("nobits", false, TR1::bind(&DirSetFlag, _1, _2, &bss, 1));
    helpers.Add("progbits", false, TR1::bind(&DirClearFlag, _1, _2, &bss, 1));
    helpers.Add("code", false, TR1::bind(&DirSetFlag, _1, _2, &code, 1));
    helpers.Add("data", false, TR1::bind(&DirClearFlag, _1, _2, &code, 1));
    helpers.Add("execute", false, TR1::bind(&DirSetFlag, _1, _2, &code, 1));
    helpers.Add("noexecute", false, TR1::bind(&DirClearFlag, _1, _2, &code, 1));

    helpers(++nvs.begin(), nvs.end(), info.getSource(), diags,
            DirNameValueWarn);

    if (start.get() != 0)
    {
        bsd->start.reset(start.release());
        bsd->start_source = source;
    }
    if (vstart.get() != 0)
    {
        bsd->vstart.reset(vstart.release());
        bsd->vstart_source = source;
    }

    if (bsd->start.get() != 0 && !bsd->follows.empty())
    {
        diags.Report(info.getSource(), diags.getCustomDiagID(Diagnostic::Error,
            "cannot combine '%0' and '%1' section attributes"))
            << "START" << "FOLLOWS";
    }

    if (bsd->vstart.get() != 0 && !bsd->vfollows.empty())
    {
        diags.Report(info.getSource(), diags.getCustomDiagID(Diagnostic::Error,
            "cannot combine '%0' and '%1' section attributes"))
            << "VSTART" << "VFOLLOWS";
    }

    sect->setBSS(bss);
    sect->setCode(code);
}
void
XdfObject::DirSection(DirectiveInfo& info, Diagnostic& diags)
{
    assert(info.isObject(m_object));
    NameValues& nvs = info.getNameValues();

    NameValue& sectname_nv = nvs.front();
    if (!sectname_nv.isString())
    {
        diags.Report(sectname_nv.getValueRange().getBegin(),
                     diag::err_value_string_or_id);
        return;
    }
    llvm::StringRef sectname = sectname_nv.getString();

    Section* sect = m_object.FindSection(sectname);
    bool first = true;
    if (sect)
        first = sect->isDefault();
    else
        sect = AppendSection(sectname, info.getSource(), diags);

    XdfSection* xsect = sect->getAssocData<XdfSection>();
    assert(xsect != 0);

    m_object.setCurSection(sect);
    sect->setDefault(false);
    if (xsect->bits != 0)
        m_object.getArch()->setVar("mode_bits", xsect->bits);       // reapply

    // No name/values, so nothing more to do
    if (nvs.size() <= 1)
        return;

    // Ignore flags if we've seen this section before
    if (!first)
    {
        diags.Report(info.getSource(), diag::warn_section_redef_flags);
        return;
    }

    // Parse section flags
    IntNum align;
    bool has_align = false;

    unsigned long bss = sect->isBSS();
    unsigned long code = sect->isCode();
    IntNum vma = sect->getVMA();
    IntNum lma = sect->getLMA();
    unsigned long flat = xsect->flat;


    DirHelpers helpers;
    helpers.Add("use16", false,
                TR1::bind(&DirResetFlag, _1, _2, &xsect->bits, 16));
    helpers.Add("use32", false,
                TR1::bind(&DirResetFlag, _1, _2, &xsect->bits, 32));
    helpers.Add("use64", false,
                TR1::bind(&DirResetFlag, _1, _2, &xsect->bits, 64));
    helpers.Add("bss", false, TR1::bind(&DirSetFlag, _1, _2, &bss, 1));
    helpers.Add("nobss", false, TR1::bind(&DirClearFlag, _1, _2, &bss, 1));
    helpers.Add("code", false, TR1::bind(&DirSetFlag, _1, _2, &code, 1));
    helpers.Add("data", false, TR1::bind(&DirClearFlag, _1, _2, &code, 1));
    helpers.Add("flat", false, TR1::bind(&DirSetFlag, _1, _2, &flat, 1));
    helpers.Add("noflat", false, TR1::bind(&DirClearFlag, _1, _2, &flat, 1));
    helpers.Add("absolute", true,
                TR1::bind(&DirIntNum, _1, _2, &m_object, &lma,
                          &xsect->has_addr));
    helpers.Add("virtual", true,
                TR1::bind(&DirIntNum, _1, _2, &m_object, &vma,
                          &xsect->has_vaddr));
    helpers.Add("align", true,
                TR1::bind(&DirIntNumPower2, _1, _2, &m_object, &align,
                          &has_align));

    helpers(++nvs.begin(), nvs.end(), info.getSource(), diags,
            DirNameValueWarn);

    if (has_align)
    {
        unsigned long aligni = align.getUInt();

        // Check to see if alignment is supported size
        // FIXME: Use actual value source location
        if (aligni > 4096)
        {
            diags.Report(info.getSource(),
                diags.getCustomDiagID(Diagnostic::Error,
                    "XDF does not support alignments > 4096"));
        }

        sect->setAlign(aligni);
    }

    sect->setBSS(bss);
    sect->setCode(code);
    sect->setVMA(vma);
    sect->setLMA(lma);
    xsect->flat = flat;
    if (xsect->bits != 0)
        m_object.getArch()->setVar("mode_bits", xsect->bits);
}