/* Chrysalide - Outil d'analyse de fichiers binaires
* helpers.c - aide à la mise en place des opérandes ARMv7
*
* Copyright (C) 2014-2017 Cyrille Bagard
*
* This file is part of Chrysalide.
*
* Chrysalide is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Chrysalide 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Foobar. If not, see .
*/
#include "helpers.h"
#include
#include
#include
#include
#include "register.h"
/******************************************************************************
* *
* Paramètres : x = valeur sur 32 bits maximum à traiter. *
* shift = nombre de décalages visés. *
* *
* Description : Effectue une rotation vers la droit d'une valeur. *
* *
* Retour : Adresse de la structure mise en place. *
* *
* Remarques : Correspond à la pseudo fonction 'ROR_C'. *
* *
******************************************************************************/
GArchOperand *ror_armv7_imm(uint32_t x, unsigned int shift)
{
GArchOperand *result; /* Opérande à faire remonter */
uint32_t val32; /* Valeur sur 32 bits */
shift %= 32;
val32 = (x >> shift) | (x << (32 - shift));
result = g_imm_operand_new_from_value(MDS_32_BITS_UNSIGNED, val32);
return result;
}
#if 0
// Shift_C()
// =========
(bits(N), bit) Shift_C(bits(N) value, SRType type, integer amount, bit carry_in)
assert !(type == SRType_RRX && amount != 1);
if amount == 0 then
(result, carry_out) = (value, carry_in);
else
case type of
when SRType_LSL
(result, carry_out) = LSL_C(value, amount);
when SRType_LSR
(result, carry_out)
when SRType_ASR
(result, carry_out)
when SRType_ROR
(result, carry_out)
when SRType_RRX
(result, carry_out)
= LSR_C(value, amount);
= ASR_C(value, amount);
= ROR_C(value, amount);
= RRX_C(value, carry_in);
#endif
/******************************************************************************
* *
* Paramètres : value = valeur sur 32 bits maximum à traiter. *
* topbit = valeur du bit de poids fort manipulé. *
* size = taille de la valeur finale à constituer. *
* *
* Description : Crée un opérande de valeur immédiate avec extension de signe.*
* *
* Retour : Adresse de la structure mise en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GArchOperand *sign_extend_armv7_imm(uint32_t value, bool topbit, unsigned int size)
{
GArchOperand *result; /* Opérande à faire remonter */
unsigned int msb; /* Position du premier bit à 1 */
MemoryDataSize mds; /* Conversion de la taille */
uint32_t val4; /* Valeur sur 4 bits */
uint32_t val8; /* Valeur sur 8 bits */
uint32_t val16; /* Valeur sur 16 bits */
uint32_t val32; /* Valeur sur 32 bits */
unsigned int i; /* Boucle de parcours */
result = NULL;
topbit &= msb_32(value, &msb);
switch (size)
{
#define SIGN_EXTEND_CASE(sz) \
case sz: \
mds = MDS_ ## sz ## _BITS_SIGNED; \
val ## sz = value; \
if (topbit) \
for (i = msb; i < sz; i++) \
val ## sz |= (1 << i); \
result = g_imm_operand_new_from_value(mds, val ## sz); \
break;
SIGN_EXTEND_CASE(4);
SIGN_EXTEND_CASE(8);
SIGN_EXTEND_CASE(16);
SIGN_EXTEND_CASE(32);
}
return result;
}
/******************************************************************************
* *
* Paramètres : value = valeur sur 32 bits maximum à traiter. *
* *
* Description : Etend une valeur immédiate en mode 'Thumb' ARMv7. *
* *
* Retour : Adresse de la structure mise en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GArchOperand *thumb_expand_armv7_imm(uint32_t value)
{
GArchOperand *result; /* Opérande à faire remonter */
uint8_t byte; /* Octet à reproduire */
uint32_t val32; /* Valeur sur 32 bits */
uint32_t unrotated; /* Transformation à décaller */
result = NULL;
if (((value >> 10) & b11) == b00)
{
byte = value & 0xff;
switch ((value >> 8) & b11)
{
case b00:
result = zero_extend_armv7_imm(byte, 32);
break;
case b01:
if (byte == 0) return NULL;
val32 = byte << 16 | byte;
result = g_imm_operand_new_from_value(MDS_32_BITS_UNSIGNED, val32);
break;
case b10:
if (byte == 0) return NULL;
val32 = byte << 24 | byte << 8;
result = g_imm_operand_new_from_value(MDS_32_BITS_UNSIGNED, val32);
break;
case b11:
if (byte == 0) return NULL;
val32 = byte << 24 | byte << 16 | byte << 8 | byte;
result = g_imm_operand_new_from_value(MDS_32_BITS_UNSIGNED, val32);
break;
}
}
else
{
unrotated = 1 << 7 | (value & 0x3f);
result = ror_armv7_imm(unrotated, (value >> 7) & 0x1f);
}
return result;
}
/******************************************************************************
* *
* Paramètres : value = valeur sur 32 bits maximum à traiter. *
* size = taille de la valeur finale à constituer. *
* *
* Description : Réalise un simple transtypage de valeur entière. *
* *
* Retour : Adresse de la structure mise en place. *
* *
* Remarques : Correspond à la pseudo fonction 'ZeroExtend'. *
* *
******************************************************************************/
GArchOperand *zero_extend_armv7_imm(uint32_t value, unsigned int size)
{
GArchOperand *result; /* Opérande à faire remonter */
MemoryDataSize mds; /* Conversion de la taille */
uint32_t val4; /* Valeur sur 4 bits */
uint32_t val8; /* Valeur sur 8 bits */
uint32_t val16; /* Valeur sur 16 bits */
uint32_t val32; /* Valeur sur 32 bits */
result = NULL;
switch (size)
{
#define ZERO_EXTEND_CASE(sz) \
case sz: \
mds = MDS_ ## sz ## _BITS_UNSIGNED; \
val ## sz = value; \
result = g_imm_operand_new_from_value(mds, val ## sz); \
break;
ZERO_EXTEND_CASE(4);
ZERO_EXTEND_CASE(8);
ZERO_EXTEND_CASE(16);
ZERO_EXTEND_CASE(32);
}
return result;
}