/*
 * Copyright (c) 1996-2011 Barton P. Miller
 * 
 * We provide the Paradyn Parallel Performance Tools (below
 * described as "Paradyn") on an AS IS basis, and do not warrant its
 * validity or performance.  We reserve the right to update, modify,
 * or discontinue this software at any time.  We shall have no
 * obligation to supply such updates or modifications or any other
 * form of support to you.
 * 
 * By your use of Paradyn, you understand and agree that we (or any
 * other person or entity with proprietary rights in Paradyn) are
 * under no obligation to provide either maintenance services,
 * update services, notices of latent defects, or correction of
 * defects for Paradyn.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/* Functions of the relocationEntry class specific to x86 ELF */
#include "Symtab.h"
#include "Serialization.h"
#include "annotations.h"
#include <elf.h>

#if defined(os_freebsd)
#define R_X86_64_JUMP_SLOT R_X86_64_JMP_SLOT
#endif

static const unsigned X86_64_WIDTH = 8;

const char* relocationEntry::relType2Str(unsigned long r, unsigned addressWidth) {
    if( X86_64_WIDTH == addressWidth ) {
        switch(r) {
            CASE_RETURN_STR(R_X86_64_NONE);
            CASE_RETURN_STR(R_X86_64_64);
            CASE_RETURN_STR(R_X86_64_PC32);
            CASE_RETURN_STR(R_X86_64_GOT32);
            CASE_RETURN_STR(R_X86_64_PLT32);
            CASE_RETURN_STR(R_X86_64_COPY);
            CASE_RETURN_STR(R_X86_64_GLOB_DAT);
            CASE_RETURN_STR(R_X86_64_RELATIVE);
            CASE_RETURN_STR(R_X86_64_GOTPCREL);
            CASE_RETURN_STR(R_X86_64_32);
            CASE_RETURN_STR(R_X86_64_32S);
            CASE_RETURN_STR(R_X86_64_16);
            CASE_RETURN_STR(R_X86_64_PC16);
            CASE_RETURN_STR(R_X86_64_8);
            CASE_RETURN_STR(R_X86_64_PC8);
            CASE_RETURN_STR(R_X86_64_DTPMOD64);
            CASE_RETURN_STR(R_X86_64_DTPOFF64);
            CASE_RETURN_STR(R_X86_64_TPOFF64);
            CASE_RETURN_STR(R_X86_64_TLSGD);
            CASE_RETURN_STR(R_X86_64_TLSLD);
            CASE_RETURN_STR(R_X86_64_DTPOFF32);
            CASE_RETURN_STR(R_X86_64_GOTTPOFF);
            CASE_RETURN_STR(R_X86_64_TPOFF32);
            CASE_RETURN_STR(R_X86_64_JUMP_SLOT);
            default:
                return "?";
        }
    }else{
        switch(r) {
            CASE_RETURN_STR(R_386_NONE);
            CASE_RETURN_STR(R_386_32);
            CASE_RETURN_STR(R_386_PC32);
            CASE_RETURN_STR(R_386_GOT32);
            CASE_RETURN_STR(R_386_PLT32);
            CASE_RETURN_STR(R_386_COPY);
            CASE_RETURN_STR(R_386_GLOB_DAT);
            CASE_RETURN_STR(R_386_JMP_SLOT);
            CASE_RETURN_STR(R_386_RELATIVE);
            CASE_RETURN_STR(R_386_GOTOFF);
            CASE_RETURN_STR(R_386_GOTPC);
            CASE_RETURN_STR(R_386_TLS_TPOFF);
            CASE_RETURN_STR(R_386_TLS_IE);
            CASE_RETURN_STR(R_386_TLS_GOTIE);
            CASE_RETURN_STR(R_386_TLS_LE);
            CASE_RETURN_STR(R_386_TLS_GD);
            CASE_RETURN_STR(R_386_TLS_LDM);
            CASE_RETURN_STR(R_386_TLS_GD_32);
            CASE_RETURN_STR(R_386_TLS_GD_PUSH);
            CASE_RETURN_STR(R_386_TLS_GD_CALL);
            CASE_RETURN_STR(R_386_TLS_GD_POP);
            CASE_RETURN_STR(R_386_TLS_LDM_32);
            CASE_RETURN_STR(R_386_TLS_LDM_PUSH);
            CASE_RETURN_STR(R_386_TLS_LDM_CALL);
            CASE_RETURN_STR(R_386_TLS_LDM_POP);
            CASE_RETURN_STR(R_386_TLS_LDO_32);
            CASE_RETURN_STR(R_386_TLS_IE_32);
            CASE_RETURN_STR(R_386_TLS_LE_32);
            CASE_RETURN_STR(R_386_TLS_DTPMOD32);
            CASE_RETURN_STR(R_386_TLS_DTPOFF32);
            CASE_RETURN_STR(R_386_TLS_TPOFF32);
#if !defined(os_freebsd)
            CASE_RETURN_STR(R_386_16);
            CASE_RETURN_STR(R_386_PC16);
            CASE_RETURN_STR(R_386_8);
            CASE_RETURN_STR(R_386_PC8);
            CASE_RETURN_STR(R_386_32PLT);
#endif
            default:
                return "?";
        }
    }
}

SYMTAB_EXPORT unsigned long relocationEntry::getGlobalRelType(unsigned addressWidth) {
    if( X86_64_WIDTH == addressWidth ) {
        return R_X86_64_GLOB_DAT;
    }else{
        return R_386_GLOB_DAT;
    }
}
