mirror of
https://github.com/capstone-engine/capstone.git
synced 2024-11-23 05:29:53 +00:00
Coverity defects (#2469)
* Fix CID 508418 - Uninitialized struct * Fix CID 509089 - Fix OOB read and write * Fix CID 509088 - OOB. Also adds tests and to ensure no OOB access. * Fix CID 509085 - Resource leak. * Fix CID 508414 and companions - Using undefined values. * Fix CID 508405 - Use of uninitialized value * Remove unnecessary and badly implemented dev fuzz code. * Fix CID 508396 - Uninitialzied variable. * Fix CID 508393, 508365 -- OOB read. * Fix CID 432207 - OVerlapping memory access. * Remove unused functions * Fix CID 432170 - Overlapping memory access. * Fix CID 166022 - Check for negative index * Let strncat not depend n src operand. * Fix 509083 and 509084 - NULL dereference * Remove duplicated code. * Initialize sysop * Fix resource leak * Remove unreachable code. * Remove duplicate code. * Add assert to check return value of cmoack * Fixed: d should be a signed value, since it is checked against < 0 * Add missing break. * Add NULL check * Fix signs of binary search comparisons. * Add explicit cast of or result * Fix correct scope of case. * Handle invalid integer type. * Return UINT_MAX instead of implicitly casted -1 * Remove dead code * Fix type of im * Fix type of d * Remove duplicated code. * Add returns after CS_ASSERTS * Check for len == 0 case. * Ensure shift operates on uint64 * Replace strcpy with strncpy. * Handle edge cases for 32bit rotate * Fix some out of enum warnings * Replace a strcpy with strncpy. * Fix increment of address * Skip some linting * Fix: set instruction id * Remove unused enum * Replace the last usages of strcpy with SStream functions. * Increase number of allowed AArch64 operands. * Check safety of incrementing t the next operand. * Fix naming of operand * Update python constants * Fix option setup of CS_OPT_DETAIL_REAL * Document DETAIL_REAL has to be used with CS_OPT_ON. * Run Coverity scan every Monday. * Remove dead code * Fix OOB read * Rename macro to reflect it is only used with sstreams * Fix rebase issues
This commit is contained in:
parent
af1ed2fb3d
commit
3a2cd3c331
2
.github/workflows/coverity.yml
vendored
2
.github/workflows/coverity.yml
vendored
@ -2,7 +2,7 @@ name: Coverity Scan
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 0 01 * *' # On the 1st every month at midnight UTC
|
||||
- cron: '0 0 * * 1' # On every Monday at midnight UTC
|
||||
|
||||
|
||||
# Automatically cancel any previous workflow on new push.
|
||||
|
@ -232,8 +232,8 @@ unsigned int binsearch_IndexTypeStrEncoding(const struct IndexTypeStr *index, si
|
||||
|
||||
right = size - 1;
|
||||
|
||||
size_t str_left_cmp = strcmp(name, index[0].name);
|
||||
size_t str_right_cmp = strcmp(name, index[right].name);
|
||||
int str_left_cmp = strcmp(name, index[0].name);
|
||||
int str_right_cmp = strcmp(name, index[right].name);
|
||||
if (str_left_cmp < 0 || str_right_cmp > 0)
|
||||
// not found
|
||||
return -1;
|
||||
|
12
Mapping.c
12
Mapping.c
@ -150,7 +150,10 @@ void map_implicit_reads(MCInst *MI, const insn_map *imap)
|
||||
return;
|
||||
}
|
||||
detail->regs_read[detail->regs_read_count++] = reg;
|
||||
reg = imap[Opcode].regs_use[++i];
|
||||
if (i + 1 < MAX_IMPL_R_REGS) {
|
||||
// Select next one
|
||||
reg = imap[Opcode].regs_use[++i];
|
||||
}
|
||||
}
|
||||
#endif // CAPSTONE_DIET
|
||||
}
|
||||
@ -175,7 +178,10 @@ void map_implicit_writes(MCInst *MI, const insn_map *imap)
|
||||
return;
|
||||
}
|
||||
detail->regs_write[detail->regs_write_count++] = reg;
|
||||
reg = imap[Opcode].regs_mod[++i];
|
||||
if (i + 1 < MAX_IMPL_W_REGS) {
|
||||
// Select next one
|
||||
reg = imap[Opcode].regs_mod[++i];
|
||||
}
|
||||
}
|
||||
#endif // CAPSTONE_DIET
|
||||
}
|
||||
@ -348,7 +354,7 @@ DEFINE_get_detail_op(systemz, SystemZ);
|
||||
/// So it can be toggled between disas() calls.
|
||||
bool map_use_alias_details(const MCInst *MI) {
|
||||
assert(MI);
|
||||
return !(MI->csh->detail_opt & CS_OPT_DETAIL_REAL);
|
||||
return (MI->csh->detail_opt & CS_OPT_ON) && !(MI->csh->detail_opt & CS_OPT_DETAIL_REAL);
|
||||
}
|
||||
|
||||
/// Sets the setDetailOps flag to @p Val.
|
||||
|
16
Mapping.h
16
Mapping.h
@ -209,6 +209,22 @@ DEFINE_get_arch_detail(mips, Mips);
|
||||
DEFINE_get_arch_detail(riscv, RISCV);
|
||||
DEFINE_get_arch_detail(systemz, SystemZ);
|
||||
|
||||
#define DEFINE_check_safe_inc(Arch, ARCH) \
|
||||
static inline void Arch##_check_safe_inc() { \
|
||||
CS_ASSERT(Arch##_get_detail(MI)->op_count + 1 < NUM_##ARCH##_OPS); \
|
||||
}
|
||||
|
||||
DEFINE_check_safe_inc(ARM, ARM);
|
||||
DEFINE_check_safe_inc(PPC, PPC);
|
||||
DEFINE_check_safe_inc(TriCore, TRICORE);
|
||||
DEFINE_check_safe_inc(AArch64, AARCH64);
|
||||
DEFINE_check_safe_inc(Alpha, ALPHA);
|
||||
DEFINE_check_safe_inc(HPPA, HPPA);
|
||||
DEFINE_check_safe_inc(LoongArch, LOONGARCH);
|
||||
DEFINE_check_safe_inc(RISCV, RISCV);
|
||||
DEFINE_check_safe_inc(SystemZ, SYSTEMZ);
|
||||
DEFINE_check_safe_inc(Mips, MIPS);
|
||||
|
||||
static inline bool detail_is_set(const MCInst *MI)
|
||||
{
|
||||
assert(MI && MI->flat_insn);
|
||||
|
12
MathExtras.h
12
MathExtras.h
@ -29,6 +29,8 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
// NOTE: The following support functions use the _32/_64 extensions instead of
|
||||
// type overloading so that signed and unsigned integers can be used without
|
||||
// ambiguity.
|
||||
@ -280,15 +282,21 @@ static inline unsigned CountPopulation_64(uint64_t Value) {
|
||||
}
|
||||
|
||||
/// Log2_32 - This function returns the floor log base 2 of the specified value,
|
||||
/// -1 if the value is zero. (32 bit edition.)
|
||||
/// UINT_MAX if the value is zero. (32 bit edition.)
|
||||
/// Ex. Log2_32(32) == 5, Log2_32(1) == 0, Log2_32(0) == -1, Log2_32(6) == 2
|
||||
static inline unsigned Log2_32(uint32_t Value) {
|
||||
if (Value == 0) {
|
||||
return UINT_MAX;
|
||||
}
|
||||
return 31 - CountLeadingZeros_32(Value);
|
||||
}
|
||||
|
||||
/// Log2_64 - This function returns the floor log base 2 of the specified value,
|
||||
/// -1 if the value is zero. (64 bit edition.)
|
||||
/// UINT_MAX if the value is zero. (64 bit edition.)
|
||||
static inline unsigned Log2_64(uint64_t Value) {
|
||||
if (Value == 0) {
|
||||
return UINT32_MAX;
|
||||
}
|
||||
return 63 - CountLeadingZeros_64(Value);
|
||||
}
|
||||
|
||||
|
98
SStream.c
98
SStream.c
@ -18,20 +18,108 @@
|
||||
#include "cs_priv.h"
|
||||
#include "utils.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable: 4996) // disable MSVC's warning on strcpy()
|
||||
#endif
|
||||
|
||||
void SStream_Init(SStream *ss)
|
||||
{
|
||||
assert(ss);
|
||||
ss->index = 0;
|
||||
ss->buffer[0] = '\0';
|
||||
memset(ss->buffer, 0, sizeof(ss->buffer));
|
||||
ss->is_closed = false;
|
||||
ss->markup_stream = false;
|
||||
ss->prefixed_by_markup = false;
|
||||
}
|
||||
|
||||
/// Returns the a pointer to the internal string buffer of the stream.
|
||||
/// For reading only.
|
||||
const char *SStream_rbuf(const SStream *ss) {
|
||||
assert(ss);
|
||||
return ss->buffer;
|
||||
}
|
||||
|
||||
/// Searches in the stream for the first (from the left) occurrence of @elem and replaces
|
||||
/// it with @repl. It returns the pointer *after* the replaced character
|
||||
/// or NULL if no character was replaced.
|
||||
///
|
||||
/// It will never replace the final \0 byte in the stream buffer.
|
||||
const char *SStream_replc(const SStream *ss, char elem, char repl) {
|
||||
assert(ss);
|
||||
char *found = strchr(ss->buffer, elem);
|
||||
if (!found || found == ss->buffer + (SSTREAM_BUF_LEN - 1)) {
|
||||
return NULL;
|
||||
}
|
||||
*found = repl;
|
||||
found++;
|
||||
return found;
|
||||
}
|
||||
|
||||
/// Searches in the stream for the first (from the left) occurrence of @chr and replaces
|
||||
/// it with @rstr.
|
||||
void SStream_replc_str(SStream *ss, char chr, const char *rstr) {
|
||||
assert(ss && rstr);
|
||||
char *found = strchr(ss->buffer, chr);
|
||||
if (!found || found == ss->buffer + (SSTREAM_BUF_LEN - 1)) {
|
||||
return;
|
||||
}
|
||||
size_t post_len = strlen(found + 1);
|
||||
size_t buf_str_len = strlen(ss->buffer);
|
||||
size_t repl_len = strlen(rstr);
|
||||
if (repl_len - 1 + buf_str_len >= SSTREAM_BUF_LEN) {
|
||||
return;
|
||||
}
|
||||
memmove(found + repl_len, found + 1, post_len);
|
||||
memcpy(found, rstr, repl_len);
|
||||
ss->index = strlen(ss->buffer);
|
||||
}
|
||||
|
||||
/// Removes the space characters '\t' and ' ' from the beginning of the stream buffer.
|
||||
void SStream_trimls(SStream *ss) {
|
||||
assert(ss);
|
||||
size_t buf_off = 0;
|
||||
/// Remove leading spaces
|
||||
while (ss->buffer[buf_off] == ' ' || ss->buffer[buf_off] == '\t') {
|
||||
buf_off++;
|
||||
}
|
||||
if (buf_off > 0) {
|
||||
memmove(ss->buffer, ss->buffer + buf_off, SSTREAM_BUF_LEN - buf_off);
|
||||
ss->index -= buf_off;
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract the mnemonic to @mnem_buf and the operand string into @op_str_buf from the stream buffer.
|
||||
/// The mnemonic is everything up until the first ' ' or '\t' character.
|
||||
/// The operand string is everything after the first ' ' or '\t' sequence.
|
||||
void SStream_extract_mnem_opstr(const SStream *ss, char *mnem_buf, size_t mnem_buf_size, char *op_str_buf, size_t op_str_buf_size) {
|
||||
assert(ss && mnem_buf && mnem_buf_size > 0 && op_str_buf && op_str_buf_size > 0);
|
||||
size_t off = 0;
|
||||
// Copy all non space chars to as mnemonic.
|
||||
while (ss->buffer[off] && ss->buffer[off] != ' ' && ss->buffer[off] != '\t') {
|
||||
if (off < mnem_buf_size - 1) {
|
||||
// Only copy if there is space left.
|
||||
mnem_buf[off] = ss->buffer[off];
|
||||
}
|
||||
off++;
|
||||
}
|
||||
if (!ss->buffer[off]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Iterate until next non space char.
|
||||
do {
|
||||
off++;
|
||||
} while (ss->buffer[off] && (ss->buffer[off] == ' ' || ss->buffer[off] == '\t'));
|
||||
|
||||
if (!ss->buffer[off]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy all follow up characters as op_str
|
||||
const char *ss_op_str = ss->buffer + off;
|
||||
off = 0;
|
||||
while (ss_op_str[off] && off < op_str_buf_size - 1) {
|
||||
op_str_buf[off] = ss_op_str[off];
|
||||
off++;
|
||||
}
|
||||
}
|
||||
|
||||
/// Empty the stream @ss to given @file (stdin/stderr).
|
||||
/// @file can be NULL. Then the buffer content is not emitted.
|
||||
void SStream_Flush(SStream *ss, FILE *file)
|
||||
|
10
SStream.h
10
SStream.h
@ -40,6 +40,16 @@ do { \
|
||||
|
||||
void SStream_Init(SStream *ss);
|
||||
|
||||
const char *SStream_replc(const SStream *ss, char elem, char repl);
|
||||
|
||||
void SStream_replc_str(SStream *ss, char chr, const char *rstr);
|
||||
|
||||
const char *SStream_rbuf(const SStream *ss);
|
||||
|
||||
void SStream_extract_mnem_opstr(const SStream *ss, char *mnem_buf, size_t mnem_buf_size, char *op_str_buf, size_t op_str_buf_size);
|
||||
|
||||
void SStream_trimls(SStream *ss);
|
||||
|
||||
void SStream_Flush(SStream *ss, FILE *file);
|
||||
|
||||
void SStream_Open(SStream *ss);
|
||||
|
@ -390,7 +390,10 @@ static inline uint64_t AArch64_AM_decodeLogicalImmediate(uint64_t val,
|
||||
unsigned imms = val & 0x3f;
|
||||
|
||||
int len = 31 - countLeadingZeros((N << 6) | (~imms & 0x3f));
|
||||
assert(len >= 1);
|
||||
if (len < 1) {
|
||||
assert(len >= 1 && "Unhandled integer type");
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned size = (1 << len);
|
||||
unsigned R = immr & (size - 1);
|
||||
|
@ -727,7 +727,7 @@ Search_IC: {
|
||||
!AArch64_testFeatureList(MI->csh->mode, IC->FeaturesRequired))
|
||||
return false;
|
||||
if (detail_is_set(MI)) {
|
||||
aarch64_sysop sysop;
|
||||
aarch64_sysop sysop = { 0 };
|
||||
sysop.reg = IC->SysReg;
|
||||
sysop.sub_type = AARCH64_OP_IC;
|
||||
AArch64_get_detail_op(MI, 0)->type = AARCH64_OP_SYSREG;
|
||||
@ -754,7 +754,7 @@ Search_IC: {
|
||||
MI->csh->mode, DC->FeaturesRequired))
|
||||
return false;
|
||||
if (detail_is_set(MI)) {
|
||||
aarch64_sysop sysop;
|
||||
aarch64_sysop sysop = { 0 };
|
||||
sysop.alias = DC->SysAlias;
|
||||
sysop.sub_type = AARCH64_OP_DC;
|
||||
AArch64_get_detail_op(MI, 0)->type =
|
||||
@ -777,7 +777,7 @@ Search_IC: {
|
||||
return false;
|
||||
|
||||
if (detail_is_set(MI)) {
|
||||
aarch64_sysop sysop;
|
||||
aarch64_sysop sysop = { 0 };
|
||||
sysop.alias = AT->SysAlias;
|
||||
sysop.sub_type = AARCH64_OP_AT;
|
||||
AArch64_get_detail_op(MI, 0)->type =
|
||||
@ -799,7 +799,7 @@ Search_IC: {
|
||||
return false;
|
||||
|
||||
if (detail_is_set(MI)) {
|
||||
aarch64_sysop sysop;
|
||||
aarch64_sysop sysop = { 0 };
|
||||
sysop.reg = TLBI->SysReg;
|
||||
sysop.sub_type = AARCH64_OP_TLBI;
|
||||
AArch64_get_detail_op(MI, 0)->type = AARCH64_OP_SYSREG;
|
||||
@ -868,7 +868,7 @@ bool printSyspAlias(MCInst *MI, SStream *O)
|
||||
return false;
|
||||
|
||||
if (detail_is_set(MI)) {
|
||||
aarch64_sysop sysop;
|
||||
aarch64_sysop sysop = { 0 };
|
||||
sysop.reg = TLBI->SysReg;
|
||||
sysop.sub_type = AARCH64_OP_TLBI;
|
||||
AArch64_get_detail_op(MI, 0)->type = AARCH64_OP_SYSREG;
|
||||
|
@ -595,7 +595,7 @@ static void AArch64_add_not_defined_ops(MCInst *MI, const SStream *OS)
|
||||
const char *disp_off = NULL;
|
||||
disp_off = strstr(OS->buffer, " za");
|
||||
if (disp_off) {
|
||||
aarch64_sysop sysop;
|
||||
aarch64_sysop sysop = { 0 };
|
||||
sysop.alias.svcr = AARCH64_SVCR_SVCRZA;
|
||||
sysop.sub_type = AARCH64_OP_SVCR;
|
||||
AArch64_insert_detail_op_sys(MI, -1, sysop,
|
||||
@ -604,7 +604,7 @@ static void AArch64_add_not_defined_ops(MCInst *MI, const SStream *OS)
|
||||
}
|
||||
disp_off = strstr(OS->buffer, " sm");
|
||||
if (disp_off) {
|
||||
aarch64_sysop sysop;
|
||||
aarch64_sysop sysop = { 0 };
|
||||
sysop.alias.svcr = AARCH64_SVCR_SVCRSM;
|
||||
sysop.sub_type = AARCH64_OP_SVCR;
|
||||
AArch64_insert_detail_op_sys(MI, -1, sysop,
|
||||
@ -1384,7 +1384,7 @@ static void add_cs_detail_general(MCInst *MI, aarch64_op_group op_group,
|
||||
}
|
||||
case AArch64_OP_GROUP_BarriernXSOption: {
|
||||
unsigned Val = MCInst_getOpVal(MI, OpNum);
|
||||
aarch64_sysop sysop;
|
||||
aarch64_sysop sysop = { 0 };
|
||||
const AArch64DBnXS_DBnXS *DB =
|
||||
AArch64DBnXS_lookupDBnXSByEncoding(Val);
|
||||
if (DB)
|
||||
@ -1398,7 +1398,7 @@ static void add_cs_detail_general(MCInst *MI, aarch64_op_group op_group,
|
||||
case AArch64_OP_GROUP_BarrierOption: {
|
||||
unsigned Val = MCOperand_getImm(MCInst_getOperand(MI, OpNum));
|
||||
unsigned Opcode = MCInst_getOpcode(MI);
|
||||
aarch64_sysop sysop;
|
||||
aarch64_sysop sysop = { 0 };
|
||||
|
||||
if (Opcode == AArch64_ISB) {
|
||||
const AArch64ISB_ISB *ISB =
|
||||
@ -1434,7 +1434,7 @@ static void add_cs_detail_general(MCInst *MI, aarch64_op_group op_group,
|
||||
break;
|
||||
}
|
||||
case AArch64_OP_GROUP_BTIHintOp: {
|
||||
aarch64_sysop sysop;
|
||||
aarch64_sysop sysop = { 0 };
|
||||
unsigned btihintop = MCInst_getOpVal(MI, OpNum) ^ 32;
|
||||
const AArch64BTIHint_BTI *BTI =
|
||||
AArch64BTIHint_lookupBTIByEncoding(btihintop);
|
||||
@ -1523,6 +1523,7 @@ static void add_cs_detail_general(MCInst *MI, aarch64_op_group op_group,
|
||||
(int) (AARCH64_REG_ZAD0 + I));
|
||||
AArch64_inc_op_count(MI);
|
||||
}
|
||||
AArch64_get_detail(MI)->is_doing_sme = false;
|
||||
break;
|
||||
}
|
||||
case AArch64_OP_GROUP_MRSSystemRegister:
|
||||
@ -1541,7 +1542,7 @@ static void add_cs_detail_general(MCInst *MI, aarch64_op_group op_group,
|
||||
|
||||
if (Reg && !isValidSysReg)
|
||||
Reg = AArch64SysReg_lookupSysRegByName(Reg->AltName);
|
||||
aarch64_sysop sysop;
|
||||
aarch64_sysop sysop = { 0 };
|
||||
// If Reg is NULL it is a generic system register.
|
||||
if (Reg)
|
||||
sysop.reg = Reg->SysReg;
|
||||
@ -1560,7 +1561,7 @@ static void add_cs_detail_general(MCInst *MI, aarch64_op_group op_group,
|
||||
unsigned psbhintop = MCInst_getOpVal(MI, OpNum);
|
||||
const AArch64PSBHint_PSB *PSB =
|
||||
AArch64PSBHint_lookupPSBByEncoding(psbhintop);
|
||||
aarch64_sysop sysop;
|
||||
aarch64_sysop sysop = { 0 };
|
||||
if (PSB)
|
||||
sysop.alias = PSB->SysAlias;
|
||||
else
|
||||
@ -1574,7 +1575,7 @@ static void add_cs_detail_general(MCInst *MI, aarch64_op_group op_group,
|
||||
unsigned prfop = MCInst_getOpVal(MI, OpNum);
|
||||
const AArch64PRFM_PRFM *PRFM =
|
||||
AArch64PRFM_lookupPRFMByEncoding(prfop);
|
||||
aarch64_sysop sysop;
|
||||
aarch64_sysop sysop = { 0 };
|
||||
if (PRFM)
|
||||
sysop.alias = PRFM->SysAlias;
|
||||
else
|
||||
@ -1611,7 +1612,7 @@ static void add_cs_detail_general(MCInst *MI, aarch64_op_group op_group,
|
||||
unsigned svcrop = MCInst_getOpVal(MI, OpNum);
|
||||
const AArch64SVCR_SVCR *SVCR =
|
||||
AArch64SVCR_lookupSVCRByEncoding(svcrop);
|
||||
aarch64_sysop sysop;
|
||||
aarch64_sysop sysop = { 0 };
|
||||
if (SVCR)
|
||||
sysop.alias = SVCR->SysAlias;
|
||||
else
|
||||
@ -1629,7 +1630,7 @@ static void add_cs_detail_general(MCInst *MI, aarch64_op_group op_group,
|
||||
AArch64_set_detail_op_imm(MI, OpNum, AARCH64_OP_IMM, Val);
|
||||
break;
|
||||
}
|
||||
aarch64_sysop sysop;
|
||||
aarch64_sysop sysop = { 0 };
|
||||
sysop.alias = Pat->SysAlias;
|
||||
sysop.sub_type = AARCH64_OP_SVEPREDPAT;
|
||||
AArch64_set_detail_op_sys(MI, OpNum, sysop,
|
||||
@ -1646,7 +1647,7 @@ static void add_cs_detail_general(MCInst *MI, aarch64_op_group op_group,
|
||||
Val);
|
||||
if (!Pat)
|
||||
break;
|
||||
aarch64_sysop sysop;
|
||||
aarch64_sysop sysop = { 0 };
|
||||
sysop.alias = Pat->SysAlias;
|
||||
sysop.sub_type = AARCH64_OP_SVEVECLENSPECIFIER;
|
||||
AArch64_set_detail_op_sys(MI, OpNum, sysop,
|
||||
@ -1667,7 +1668,7 @@ static void add_cs_detail_general(MCInst *MI, aarch64_op_group op_group,
|
||||
case AArch64_OP_GROUP_SystemPStateField: {
|
||||
unsigned Val = MCInst_getOpVal(MI, OpNum);
|
||||
|
||||
aarch64_sysop sysop;
|
||||
aarch64_sysop sysop = { 0 };
|
||||
const AArch64PState_PStateImm0_15 *PStateImm15 =
|
||||
AArch64PState_lookupPStateImm0_15ByEncoding(Val);
|
||||
const AArch64PState_PStateImm0_1 *PStateImm1 =
|
||||
@ -1881,7 +1882,7 @@ static void add_cs_detail_template_1(MCInst *MI, aarch64_op_group op_group,
|
||||
case AArch64_OP_GROUP_PrefetchOp_1: {
|
||||
bool IsSVEPrefetch = (bool)temp_arg_0;
|
||||
unsigned prfop = MCInst_getOpVal(MI, (OpNum));
|
||||
aarch64_sysop sysop;
|
||||
aarch64_sysop sysop = { 0 };
|
||||
if (IsSVEPrefetch) {
|
||||
const AArch64SVEPRFM_SVEPRFM *PRFM =
|
||||
AArch64SVEPRFM_lookupSVEPRFMByEncoding(prfop);
|
||||
@ -2036,7 +2037,7 @@ static void add_cs_detail_template_2(MCInst *MI, aarch64_op_group op_group,
|
||||
const AArch64ExactFPImm_ExactFPImm *Imm1Desc =
|
||||
AArch64ExactFPImm_lookupExactFPImmByEnum(ImmIs1);
|
||||
unsigned Val = MCInst_getOpVal(MI, (OpNum));
|
||||
aarch64_sysop sysop;
|
||||
aarch64_sysop sysop = { 0 };
|
||||
sysop.imm = Val ? Imm1Desc->SysImm : Imm0Desc->SysImm;
|
||||
sysop.sub_type = AARCH64_OP_EXACTFPIMM;
|
||||
AArch64_set_detail_op_sys(MI, OpNum, sysop, AARCH64_OP_SYSIMM);
|
||||
@ -2474,6 +2475,8 @@ void AArch64_set_detail_op_reg(MCInst *MI, unsigned OpNum, aarch64_reg Reg)
|
||||
{
|
||||
if (!detail_is_set(MI))
|
||||
return;
|
||||
AArch64_check_safe_inc();
|
||||
|
||||
if (Reg == AARCH64_REG_ZA ||
|
||||
(Reg >= AARCH64_REG_ZAB0 && Reg < AARCH64_REG_ZT0)) {
|
||||
// A tile register should be treated as SME operand.
|
||||
@ -2519,6 +2522,7 @@ void AArch64_set_detail_op_imm(MCInst *MI, unsigned OpNum,
|
||||
{
|
||||
if (!detail_is_set(MI))
|
||||
return;
|
||||
AArch64_check_safe_inc();
|
||||
|
||||
if (AArch64_get_detail(MI)->is_doing_sme) {
|
||||
assert(map_get_op_type(MI, OpNum) & CS_OP_BOUND);
|
||||
@ -2553,6 +2557,7 @@ void AArch64_set_detail_op_imm_range(MCInst *MI, unsigned OpNum,
|
||||
{
|
||||
if (!detail_is_set(MI))
|
||||
return;
|
||||
AArch64_check_safe_inc();
|
||||
|
||||
if (AArch64_get_detail(MI)->is_doing_sme) {
|
||||
assert(map_get_op_type(MI, OpNum) & CS_OP_BOUND);
|
||||
@ -2585,6 +2590,7 @@ void AArch64_set_detail_op_mem(MCInst *MI, unsigned OpNum, uint64_t Val)
|
||||
{
|
||||
if (!detail_is_set(MI))
|
||||
return;
|
||||
AArch64_check_safe_inc();
|
||||
assert(map_get_op_type(MI, OpNum) & CS_OP_MEM);
|
||||
|
||||
AArch64_set_mem_access(MI, true);
|
||||
@ -2670,6 +2676,8 @@ void AArch64_set_detail_op_float(MCInst *MI, unsigned OpNum, float Val)
|
||||
{
|
||||
if (!detail_is_set(MI))
|
||||
return;
|
||||
AArch64_check_safe_inc();
|
||||
|
||||
AArch64_get_detail_op(MI, 0)->type = AARCH64_OP_FP;
|
||||
AArch64_get_detail_op(MI, 0)->fp = Val;
|
||||
AArch64_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum);
|
||||
@ -2683,6 +2691,8 @@ void AArch64_set_detail_op_sys(MCInst *MI, unsigned OpNum, aarch64_sysop sys_op,
|
||||
{
|
||||
if (!detail_is_set(MI))
|
||||
return;
|
||||
AArch64_check_safe_inc();
|
||||
|
||||
AArch64_get_detail_op(MI, 0)->type = type;
|
||||
AArch64_get_detail_op(MI, 0)->sysop = sys_op;
|
||||
AArch64_inc_op_count(MI);
|
||||
@ -2691,6 +2701,7 @@ void AArch64_set_detail_op_sys(MCInst *MI, unsigned OpNum, aarch64_sysop sys_op,
|
||||
void AArch64_set_detail_op_pred(MCInst *MI, unsigned OpNum) {
|
||||
if (!detail_is_set(MI))
|
||||
return;
|
||||
AArch64_check_safe_inc();
|
||||
|
||||
if (AArch64_get_detail_op(MI, 0)->type == AARCH64_OP_INVALID) {
|
||||
setup_pred_operand(MI);
|
||||
@ -2718,6 +2729,8 @@ void AArch64_set_detail_op_sme(MCInst *MI, unsigned OpNum,
|
||||
{
|
||||
if (!detail_is_set(MI))
|
||||
return;
|
||||
AArch64_check_safe_inc();
|
||||
|
||||
AArch64_get_detail_op(MI, 0)->type = AARCH64_OP_SME;
|
||||
switch (part) {
|
||||
default:
|
||||
@ -2794,9 +2807,9 @@ static void insert_op(MCInst *MI, unsigned index, cs_aarch64_op op)
|
||||
return;
|
||||
}
|
||||
|
||||
AArch64_check_safe_inc();
|
||||
cs_aarch64_op *ops = AArch64_get_detail(MI)->operands;
|
||||
int i = AArch64_get_detail(MI)->op_count;
|
||||
assert(i < MAX_AARCH64_OPS);
|
||||
if (index == -1) {
|
||||
ops[i] = op;
|
||||
AArch64_inc_op_count(MI);
|
||||
@ -2818,7 +2831,7 @@ void AArch64_insert_detail_op_float_at(MCInst *MI, unsigned index, double val,
|
||||
if (!detail_is_set(MI))
|
||||
return;
|
||||
|
||||
assert(AArch64_get_detail(MI)->op_count < MAX_AARCH64_OPS);
|
||||
AArch64_check_safe_inc();
|
||||
|
||||
cs_aarch64_op op;
|
||||
AArch64_setup_op(&op);
|
||||
@ -2838,7 +2851,7 @@ void AArch64_insert_detail_op_reg_at(MCInst *MI, unsigned index,
|
||||
if (!detail_is_set(MI))
|
||||
return;
|
||||
|
||||
assert(AArch64_get_detail(MI)->op_count < MAX_AARCH64_OPS);
|
||||
AArch64_check_safe_inc();
|
||||
|
||||
cs_aarch64_op op;
|
||||
AArch64_setup_op(&op);
|
||||
@ -2856,8 +2869,7 @@ void AArch64_insert_detail_op_imm_at(MCInst *MI, unsigned index, int64_t Imm)
|
||||
{
|
||||
if (!detail_is_set(MI))
|
||||
return;
|
||||
|
||||
assert(AArch64_get_detail(MI)->op_count < MAX_AARCH64_OPS);
|
||||
AArch64_check_safe_inc();
|
||||
|
||||
cs_aarch64_op op;
|
||||
AArch64_setup_op(&op);
|
||||
@ -2873,7 +2885,7 @@ void AArch64_insert_detail_op_sys(MCInst *MI, unsigned index, aarch64_sysop sys_
|
||||
{
|
||||
if (!detail_is_set(MI))
|
||||
return;
|
||||
assert(AArch64_get_detail(MI)->op_count < MAX_AARCH64_OPS);
|
||||
AArch64_check_safe_inc();
|
||||
|
||||
cs_aarch64_op op;
|
||||
AArch64_setup_op(&op);
|
||||
@ -2887,7 +2899,7 @@ void AArch64_insert_detail_op_sme(MCInst *MI, unsigned index, aarch64_op_sme sme
|
||||
{
|
||||
if (!detail_is_set(MI))
|
||||
return;
|
||||
assert(AArch64_get_detail(MI)->op_count < MAX_AARCH64_OPS);
|
||||
AArch64_check_safe_inc();
|
||||
|
||||
cs_aarch64_op op;
|
||||
AArch64_setup_op(&op);
|
||||
|
@ -28,6 +28,7 @@
|
||||
#define CS_ARM_ADDRESSINGMODES_H
|
||||
|
||||
#include <capstone/platform.h>
|
||||
#include "../../cs_priv.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -120,7 +121,11 @@ static inline const char *ARM_AM_getAMSubModeStr(ARM_AM_SubMode Mode)
|
||||
///
|
||||
static inline unsigned ARM_AM_rotr32(unsigned Val, unsigned Amt)
|
||||
{
|
||||
return (Val >> Amt) | (Val << ((32 - Amt) & 31));
|
||||
CS_ASSERT(Amt >= 32);
|
||||
if (Amt == 32) {
|
||||
return Val;
|
||||
}
|
||||
return (Val >> Amt) | (Val << ((32 - Amt) & 31)); // NOLINT(clang-analyzer-core.BitwiseShift)
|
||||
}
|
||||
|
||||
/// rotl32 - Rotate a 32-bit unsigned value left by a specified # bits.
|
||||
|
@ -490,20 +490,13 @@ void printThumbLdrLabelOperand(MCInst *MI, unsigned OpNum, SStream *O)
|
||||
SStream_concat0(O, "[pc, ");
|
||||
|
||||
int32_t OffImm = (int32_t)MCOperand_getImm(MO1);
|
||||
bool isSub = OffImm < 0;
|
||||
|
||||
// Special value for #-0. All others are normal.
|
||||
if (OffImm == INT32_MIN)
|
||||
OffImm = 0;
|
||||
if (isSub) {
|
||||
SStream_concat(O, "%s", markup("<imm:"));
|
||||
printInt32Bang(O, OffImm);
|
||||
SStream_concat0(O, markup(">"));
|
||||
} else {
|
||||
SStream_concat(O, "%s", markup("<imm:"));
|
||||
printInt32Bang(O, OffImm);
|
||||
SStream_concat0(O, markup(">"));
|
||||
}
|
||||
SStream_concat(O, "%s", markup("<imm:"));
|
||||
printInt32Bang(O, OffImm);
|
||||
SStream_concat0(O, markup(">"));
|
||||
SStream_concat(O, "%s", "]");
|
||||
SStream_concat0(O, markup(">"));
|
||||
}
|
||||
|
@ -935,6 +935,7 @@ static void ARM_set_mem_access(MCInst *MI, bool status)
|
||||
#endif
|
||||
} else {
|
||||
// done, select the next operand slot
|
||||
ARM_check_safe_inc();
|
||||
ARM_inc_op_count(MI);
|
||||
}
|
||||
}
|
||||
@ -1160,6 +1161,7 @@ static void add_cs_detail_general(MCInst *MI, arm_op_group op_group,
|
||||
unsigned Reg =
|
||||
MCOperand_getReg(MCInst_getOperand(MI, i));
|
||||
|
||||
ARM_check_safe_inc();
|
||||
ARM_get_detail_op(MI, 0)->type = ARM_OP_REG;
|
||||
ARM_get_detail_op(MI, 0)->reg = Reg;
|
||||
ARM_get_detail_op(MI, 0)->access = access;
|
||||
@ -1173,7 +1175,7 @@ static void add_cs_detail_general(MCInst *MI, arm_op_group op_group,
|
||||
unsigned CondBit0 = Firstcond & 1;
|
||||
unsigned NumTZ = CountTrailingZeros_32(Mask);
|
||||
unsigned Pos, e;
|
||||
ARM_PredBlockMask PredMask = 0;
|
||||
ARM_PredBlockMask PredMask = ARM_PredBlockMaskInvalid;
|
||||
|
||||
// Check the documentation of ARM_PredBlockMask how the bits are set.
|
||||
for (Pos = 3, e = NumTZ; Pos > e; --Pos) {
|
||||
@ -1192,7 +1194,7 @@ static void add_cs_detail_general(MCInst *MI, arm_op_group op_group,
|
||||
case ARM_OP_GROUP_VPTMask: {
|
||||
unsigned Mask = MCInst_getOpVal(MI, OpNum);
|
||||
unsigned NumTZ = CountTrailingZeros_32(Mask);
|
||||
ARM_PredBlockMask PredMask = 0;
|
||||
ARM_PredBlockMask PredMask = ARM_PredBlockMaskInvalid;
|
||||
|
||||
// Check the documentation of ARM_PredBlockMask how the bits are set.
|
||||
for (unsigned Pos = 3, e = NumTZ; Pos > e; --Pos) {
|
||||
@ -1661,6 +1663,7 @@ static void add_cs_detail_general(MCInst *MI, arm_op_group op_group,
|
||||
int32_t OffImm = MCInst_getOpVal(MI, OpNum);
|
||||
if (OffImm == INT32_MIN)
|
||||
OffImm = 0;
|
||||
ARM_check_safe_inc();
|
||||
ARM_get_detail_op(MI, 0)->type = ARM_OP_MEM;
|
||||
ARM_get_detail_op(MI, 0)->mem.base = ARM_REG_PC;
|
||||
ARM_get_detail_op(MI, 0)->mem.index = ARM_REG_INVALID;
|
||||
@ -1683,6 +1686,7 @@ static void add_cs_detail_general(MCInst *MI, arm_op_group op_group,
|
||||
}
|
||||
case ARM_OP_GROUP_SetendOperand: {
|
||||
bool be = MCInst_getOpVal(MI, OpNum) != 0;
|
||||
ARM_check_safe_inc();
|
||||
if (be) {
|
||||
ARM_get_detail_op(MI, 0)->type = ARM_OP_SETEND;
|
||||
ARM_get_detail_op(MI, 0)->setend = ARM_SETEND_BE;
|
||||
@ -1793,6 +1797,7 @@ static void add_cs_detail_template_1(MCInst *MI, arm_op_group op_group,
|
||||
if (AlwaysPrintImm0)
|
||||
map_add_implicit_write(MI, MCInst_getOpVal(MI, OpNum));
|
||||
|
||||
ARM_check_safe_inc();
|
||||
cs_arm_op *Op = ARM_get_detail_op(MI, 0);
|
||||
Op->type = ARM_OP_MEM;
|
||||
Op->mem.base = MCInst_getOpVal(MI, OpNum);
|
||||
@ -1932,7 +1937,7 @@ void ARM_insert_detail_op_reg_at(MCInst *MI, unsigned index, arm_reg Reg,
|
||||
if (!detail_is_set(MI))
|
||||
return;
|
||||
|
||||
assert(ARM_get_detail(MI)->op_count < MAX_ARM_OPS);
|
||||
ARM_check_safe_inc();
|
||||
|
||||
cs_arm_op op;
|
||||
ARM_setup_op(&op);
|
||||
@ -1942,7 +1947,6 @@ void ARM_insert_detail_op_reg_at(MCInst *MI, unsigned index, arm_reg Reg,
|
||||
|
||||
cs_arm_op *ops = ARM_get_detail(MI)->operands;
|
||||
int i = ARM_get_detail(MI)->op_count;
|
||||
assert(i < MAX_ARM_OPS);
|
||||
for (; i > 0 && i > index; --i) {
|
||||
ops[i] = ops[i - 1];
|
||||
}
|
||||
@ -1957,8 +1961,7 @@ void ARM_insert_detail_op_imm_at(MCInst *MI, unsigned index, int64_t Val,
|
||||
{
|
||||
if (!detail_is_set(MI))
|
||||
return;
|
||||
|
||||
assert(ARM_get_detail(MI)->op_count < MAX_ARM_OPS);
|
||||
ARM_check_safe_inc();
|
||||
|
||||
cs_arm_op op;
|
||||
ARM_setup_op(&op);
|
||||
@ -1968,7 +1971,6 @@ void ARM_insert_detail_op_imm_at(MCInst *MI, unsigned index, int64_t Val,
|
||||
|
||||
cs_arm_op *ops = ARM_get_detail(MI)->operands;
|
||||
int i = ARM_get_detail(MI)->op_count;
|
||||
assert(i < MAX_ARM_OPS);
|
||||
for (; i > 0 && i > index; --i) {
|
||||
ops[i] = ops[i - 1];
|
||||
}
|
||||
@ -1982,6 +1984,7 @@ void ARM_set_detail_op_reg(MCInst *MI, unsigned OpNum, arm_reg Reg)
|
||||
{
|
||||
if (!detail_is_set(MI))
|
||||
return;
|
||||
ARM_check_safe_inc();
|
||||
assert(!(map_get_op_type(MI, OpNum) & CS_OP_MEM));
|
||||
assert(map_get_op_type(MI, OpNum) == CS_OP_REG);
|
||||
|
||||
@ -1998,6 +2001,7 @@ void ARM_set_detail_op_imm(MCInst *MI, unsigned OpNum, arm_op_type ImmType,
|
||||
{
|
||||
if (!detail_is_set(MI))
|
||||
return;
|
||||
ARM_check_safe_inc();
|
||||
assert(!(map_get_op_type(MI, OpNum) & CS_OP_MEM));
|
||||
assert(map_get_op_type(MI, OpNum) == CS_OP_IMM);
|
||||
assert(ImmType == ARM_OP_IMM || ImmType == ARM_OP_PIMM ||
|
||||
@ -2107,12 +2111,14 @@ void ARM_set_detail_op_sysop(MCInst *MI, int Val, arm_op_type type,
|
||||
{
|
||||
if (!detail_is_set(MI))
|
||||
return;
|
||||
ARM_check_safe_inc();
|
||||
|
||||
ARM_get_detail_op(MI, 0)->type = type;
|
||||
switch (type) {
|
||||
default:
|
||||
assert(0 && "Unknown system operand type.");
|
||||
case ARM_OP_SYSREG:
|
||||
ARM_get_detail_op(MI, 0)->sysop.reg.mclasssysreg = Val;
|
||||
ARM_get_detail_op(MI, 0)->sysop.reg.mclasssysreg = Val; // NOLINT(clang-analyzer-optin.core.EnumCastOutOfRange)
|
||||
break;
|
||||
case ARM_OP_BANKEDREG:
|
||||
ARM_get_detail_op(MI, 0)->sysop.reg.bankedreg = Val;
|
||||
@ -2121,7 +2127,7 @@ void ARM_set_detail_op_sysop(MCInst *MI, int Val, arm_op_type type,
|
||||
case ARM_OP_CPSR:
|
||||
ARM_get_detail_op(MI, 0)->reg =
|
||||
type == ARM_OP_SPSR ? ARM_REG_SPSR : ARM_REG_CPSR;
|
||||
ARM_get_detail_op(MI, 0)->sysop.psr_bits = Val;
|
||||
ARM_get_detail_op(MI, 0)->sysop.psr_bits = Val; // NOLINT(clang-analyzer-optin.core.EnumCastOutOfRange)
|
||||
break;
|
||||
}
|
||||
ARM_get_detail_op(MI, 0)->sysop.sysm = Sysm;
|
||||
@ -2136,6 +2142,8 @@ void ARM_set_detail_op_float(MCInst *MI, unsigned OpNum, uint64_t Imm)
|
||||
{
|
||||
if (!detail_is_set(MI))
|
||||
return;
|
||||
ARM_check_safe_inc();
|
||||
|
||||
ARM_get_detail_op(MI, 0)->type = ARM_OP_FP;
|
||||
ARM_get_detail_op(MI, 0)->fp = ARM_AM_getFPImmFloat(Imm);
|
||||
ARM_inc_op_count(MI);
|
||||
|
@ -718,6 +718,7 @@ static bool checkDecoderPredicate(MCInst *Inst, unsigned Idx) {
|
||||
static DecodeStatus fname(DecodeStatus S, unsigned Idx, InsnType insn, MCInst *MI, \
|
||||
uint64_t Address, const void *Decoder, bool *DecodeComplete) \
|
||||
{ \
|
||||
*DecodeComplete = true; \
|
||||
InsnType tmp; \
|
||||
switch (Idx) { \
|
||||
default: /* llvm_unreachable("Invalid index!"); */ \
|
||||
|
@ -221,8 +221,8 @@ static void push_str_modifier(hppa_ext *hppa, const char *modifier)
|
||||
hppa_modifier *mod = &hppa->modifiers[hppa->mod_num++];
|
||||
assert(hppa->mod_num <= HPPA_MAX_MODIFIERS_LEN);
|
||||
mod->type = HPPA_MOD_STR;
|
||||
assert(strlen(modifier) <= HPPA_STR_MODIFIER_LEN);
|
||||
strcpy(mod->str_mod, modifier);
|
||||
assert(strlen(modifier) < HPPA_STR_MODIFIER_LEN);
|
||||
strncpy(mod->str_mod, modifier, HPPA_STR_MODIFIER_LEN - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1457,7 +1457,7 @@ static void fill_ldst_w_insn_name(MCInst *MI, uint32_t insn)
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_ldst_w_mods(uint32_t insn, hppa_ext *hppa_ext, uint32_t im)
|
||||
static void fill_ldst_w_mods(uint32_t insn, hppa_ext *hppa_ext, int32_t im)
|
||||
{
|
||||
if (im >= 0) {
|
||||
push_str_modifier(hppa_ext, "mb");
|
||||
@ -1470,7 +1470,7 @@ static bool decode_ldst_w(const cs_struct *ud, MCInst *MI, uint32_t insn)
|
||||
{
|
||||
uint32_t opcode = insn >> 26;
|
||||
uint32_t ext = get_insn_bit(insn, 29);
|
||||
uint32_t im = extract_16(insn, MODE_IS_HPPA_20W(ud->mode));
|
||||
int32_t im = extract_16(insn, MODE_IS_HPPA_20W(ud->mode));
|
||||
im &= ~3;
|
||||
uint32_t r = get_insn_field(insn, 11, 15);
|
||||
uint32_t b = get_insn_field(insn, 6, 10);
|
||||
@ -3621,7 +3621,7 @@ static bool decode_load(const cs_struct *ud, MCInst *MI, uint32_t insn)
|
||||
{
|
||||
uint32_t opcode = insn >> 26;
|
||||
if (MODE_IS_HPPA_20(ud->mode)) {
|
||||
uint32_t d = extract_16(insn, MODE_IS_HPPA_20W(ud->mode));
|
||||
int32_t d = extract_16(insn, MODE_IS_HPPA_20W(ud->mode));
|
||||
if (opcode == HPPA_OP_TYPE_LDWM) {
|
||||
if (d < 0) {
|
||||
push_str_modifier(HPPA_EXT_REF(MI), "mb");
|
||||
@ -3644,7 +3644,7 @@ static bool decode_store(const cs_struct *ud, MCInst *MI, uint32_t insn)
|
||||
uint32_t opcode = insn >> 26;
|
||||
CREATE_GR_REG(MI, get_insn_field(insn, 11, 15));
|
||||
if (MODE_IS_HPPA_20(ud->mode)) {
|
||||
uint32_t d = extract_16(insn, MODE_IS_HPPA_20W(ud->mode));
|
||||
int d = extract_16(insn, MODE_IS_HPPA_20W(ud->mode));
|
||||
if (opcode == HPPA_OP_TYPE_STWM) {
|
||||
if (d < 0) {
|
||||
push_str_modifier(HPPA_EXT_REF(MI), "mb");
|
||||
|
@ -1125,7 +1125,7 @@ static void reg_bits_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
|
||||
add_insn_group(MI->flat_insn->detail, M680X_GRP_RET);
|
||||
|
||||
for (bit_index = 0; bit_index < 8; ++bit_index) {
|
||||
if (reg_bits & (1 << bit_index))
|
||||
if (reg_bits & (1 << bit_index) && reg_to_reg_ids)
|
||||
add_reg_operand(info, reg_to_reg_ids[bit_index]);
|
||||
}
|
||||
}
|
||||
@ -1680,7 +1680,7 @@ static void indexedS16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
|
||||
uint16_t offset = 0;
|
||||
|
||||
read_word(info, &offset, *address);
|
||||
address += 2;
|
||||
*address += 2;
|
||||
|
||||
add_indexed_operand(info, M680X_REG_S, false, 0, M680X_OFFSET_BITS_16,
|
||||
offset, false);
|
||||
@ -1774,7 +1774,7 @@ static void loop_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
|
||||
|
||||
op->type = M680X_OP_RELATIVE;
|
||||
|
||||
op->rel.offset = (post_byte & 0x10) ? 0xff00 | rel : rel;
|
||||
op->rel.offset = (post_byte & 0x10) ? (int16_t) (0xff00 | rel) : rel;
|
||||
|
||||
op->rel.address = *address + op->rel.offset;
|
||||
|
||||
|
@ -321,13 +321,6 @@ static void get_with_index_address_mode(m68k_info *info, cs_m68k_op* op, uint32_
|
||||
op->mem.base_reg = M68K_REG_INVALID;
|
||||
op->mem.index_reg = M68K_REG_INVALID;
|
||||
|
||||
/* Not sure how to deal with this?
|
||||
if (EXT_EFFECTIVE_ZERO(extension)) {
|
||||
strcpy(mode, "0");
|
||||
break;
|
||||
}
|
||||
*/
|
||||
|
||||
op->mem.in_disp = EXT_BASE_DISPLACEMENT_PRESENT(extension) ? (EXT_BASE_DISPLACEMENT_LONG(extension) ? read_imm_32(info) : read_imm_16(info)) : 0;
|
||||
op->mem.out_disp = EXT_OUTER_DISPLACEMENT_PRESENT(extension) ? (EXT_OUTER_DISPLACEMENT_LONG(extension) ? read_imm_32(info) : read_imm_16(info)) : 0;
|
||||
|
||||
|
@ -55,7 +55,7 @@ cs_err MOS65XX_option(cs_struct *handle, cs_opt_type type, size_t value)
|
||||
info->long_m = value & CS_MODE_MOS65XX_65816_LONG_M ? 1 : 0;
|
||||
info->long_x = value & CS_MODE_MOS65XX_65816_LONG_X ? 1 : 0;
|
||||
|
||||
handle->mode = (cs_mode)value;
|
||||
handle->mode = (cs_mode)value; // NOLINT(clang-analyzer-optin.core.EnumCastOutOfRange)
|
||||
break;
|
||||
case CS_OPT_SYNTAX:
|
||||
switch(value) {
|
||||
|
@ -401,6 +401,7 @@ static void add_cs_detail_general(MCInst *MI, ppc_op_group op_group,
|
||||
return;
|
||||
unsigned Val = MCInst_getOpVal(MI, OpNum) << 2;
|
||||
int32_t Imm = SignExtend32(Val, 32);
|
||||
PPC_check_safe_inc();
|
||||
PPC_get_detail_op(MI, 0)->type = PPC_OP_IMM;
|
||||
PPC_get_detail_op(MI, 0)->imm = Imm;
|
||||
PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum);
|
||||
@ -424,6 +425,7 @@ static void add_cs_detail_general(MCInst *MI, ppc_op_group op_group,
|
||||
uint64_t Address = MI->address + Imm;
|
||||
if (IS_32BIT(MI->csh->mode))
|
||||
Address &= 0xffffffff;
|
||||
PPC_check_safe_inc();
|
||||
PPC_get_detail_op(MI, 0)->type = PPC_OP_IMM;
|
||||
PPC_get_detail_op(MI, 0)->imm = Address;
|
||||
PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum);
|
||||
@ -566,6 +568,7 @@ void PPC_set_detail_op_reg(MCInst *MI, unsigned OpNum, ppc_reg Reg)
|
||||
{
|
||||
if (!detail_is_set(MI))
|
||||
return;
|
||||
PPC_check_safe_inc();
|
||||
assert(!(map_get_op_type(MI, OpNum) & CS_OP_MEM));
|
||||
assert(map_get_op_type(MI, OpNum) == CS_OP_REG);
|
||||
|
||||
@ -581,6 +584,7 @@ void PPC_set_detail_op_imm(MCInst *MI, unsigned OpNum, int64_t Imm)
|
||||
{
|
||||
if (!detail_is_set(MI))
|
||||
return;
|
||||
PPC_check_safe_inc();
|
||||
assert(!(map_get_op_type(MI, OpNum) & CS_OP_MEM));
|
||||
assert(map_get_op_type(MI, OpNum) == CS_OP_IMM);
|
||||
|
||||
@ -594,6 +598,7 @@ void PPC_set_mem_access(MCInst *MI, bool status)
|
||||
{
|
||||
if (!detail_is_set(MI))
|
||||
return;
|
||||
PPC_check_safe_inc();
|
||||
if ((!status && !doing_mem(MI)) || (status && doing_mem(MI)))
|
||||
return; // Nothing to do
|
||||
|
||||
@ -629,7 +634,7 @@ void PPC_insert_detail_op_imm_at(MCInst *MI, unsigned index, int64_t Val,
|
||||
if (!detail_is_set(MI) || !map_fill_detail_ops(MI))
|
||||
return;
|
||||
|
||||
assert(PPC_get_detail(MI)->op_count < PPC_NUM_OPS);
|
||||
PPC_check_safe_inc();
|
||||
|
||||
cs_ppc_op op;
|
||||
PPC_setup_op(&op);
|
||||
|
@ -1198,7 +1198,9 @@ static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI)
|
||||
|
||||
// Fragment 0 encoded into 2 bits for 4 unique commands.
|
||||
switch ((uint32_t)((Bits >> 12) & 3)) {
|
||||
default: CS_ASSERT(0 && "Invalid command number.");
|
||||
default:
|
||||
CS_ASSERT(0 && "Invalid command number.");
|
||||
return;
|
||||
case 0:
|
||||
// DBG_VALUE, DBG_LABEL, BUNDLE, LIFETIME_START, LIFETIME_END, FENTRY_CAL...
|
||||
return;
|
||||
@ -1226,7 +1228,9 @@ static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI)
|
||||
|
||||
// Fragment 1 encoded into 2 bits for 3 unique commands.
|
||||
switch ((uint32_t)((Bits >> 14) & 3)) {
|
||||
default: CS_ASSERT(0 && "Invalid command number.");
|
||||
default:
|
||||
CS_ASSERT(0 && "Invalid command number.");
|
||||
return;
|
||||
case 0:
|
||||
// PseudoCALL, PseudoTAIL, C_J, C_JAL, C_JALR, C_JR
|
||||
return;
|
||||
@ -1247,7 +1251,9 @@ static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI)
|
||||
|
||||
// Fragment 2 encoded into 2 bits for 3 unique commands.
|
||||
switch ((uint32_t)((Bits >> 16) & 3)) {
|
||||
default: CS_ASSERT(0 && "Invalid command number.");
|
||||
default:
|
||||
CS_ASSERT(0 && "Invalid command number.");
|
||||
return;
|
||||
case 0:
|
||||
// PseudoLA, PseudoLI, PseudoLLA, ADD, ADDI, ADDIW, ADDW, AND, ANDI, AUIP...
|
||||
printOperand(MI, 1, O);
|
||||
@ -1268,7 +1274,9 @@ static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI)
|
||||
|
||||
// Fragment 3 encoded into 2 bits for 4 unique commands.
|
||||
switch ((uint32_t)((Bits >> 18) & 3)) {
|
||||
default: CS_ASSERT(0 && "Invalid command number.");
|
||||
default:
|
||||
CS_ASSERT(0 && "Invalid command number.");
|
||||
return;
|
||||
case 0:
|
||||
// PseudoLA, PseudoLI, PseudoLLA, AUIPC, C_BEQZ, C_BNEZ, C_LI, C_LUI, C_M...
|
||||
return;
|
||||
@ -1468,7 +1476,9 @@ getRegisterName(unsigned RegNo, unsigned AltIdx)
|
||||
};
|
||||
|
||||
switch(AltIdx) {
|
||||
default: CS_ASSERT(0 && "Invalid register alt name index!");
|
||||
default:
|
||||
CS_ASSERT(0 && "Invalid register alt name index!");
|
||||
return 0;
|
||||
case RISCV_ABIRegAltName:
|
||||
CS_ASSERT(*(AsmStrsABIRegAltName+RegAsmOffsetABIRegAltName[RegNo-1]) &&
|
||||
"Invalid alt name index for register!");
|
||||
|
@ -1736,7 +1736,8 @@ static DecodeStatus fname(const uint8_t DecodeTable[], MCInst *MI,\
|
||||
NumToSkip |= (*Ptr++) << 8;\
|
||||
NumToSkip |= (*Ptr++) << 16;\
|
||||
\
|
||||
MCInst TmpMI;\
|
||||
MCInst TmpMI = { 0 }; \
|
||||
MCInst_Init(&TmpMI, CS_ARCH_RISCV); \
|
||||
MCInst_setOpcode(&TmpMI, Opc);\
|
||||
bool DecodeComplete = false;\
|
||||
S = decoder(S, DecodeIdx, insn, &TmpMI, Address, DisAsm, &DecodeComplete);\
|
||||
|
@ -99,7 +99,7 @@ static void set_groups(cs_detail *detail, int n, ...)
|
||||
va_start(g, n);
|
||||
while (n > 0) {
|
||||
sh_insn_group grp;
|
||||
grp = va_arg(g, sh_insn_group);
|
||||
grp = va_arg(g, sh_insn_group); // NOLINT(clang-analyzer-valist.Uninitialized)
|
||||
if (detail) {
|
||||
detail->groups[detail->groups_count] = grp;
|
||||
detail->groups_count++;
|
||||
@ -934,7 +934,7 @@ static bool op4xxb(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
|
||||
rw = write;
|
||||
break;
|
||||
case 2:
|
||||
insn = SH_INS_JMP;
|
||||
MCInst_setOpcode(MI, SH_INS_JMP);
|
||||
grp = SH_GRP_JUMP;
|
||||
break;
|
||||
case 8:
|
||||
@ -1605,6 +1605,9 @@ static bool set_dsp_move_d(sh_info *info, int xy, uint16_t code, cs_mode mode, c
|
||||
int op;
|
||||
static const sh_reg base[] = {SH_REG_DSP_A0, SH_REG_DSP_X0};
|
||||
switch (xy) {
|
||||
default:
|
||||
printf("Invalid xy value %" PRId32 "\n", xy);
|
||||
return MCDisassembler_Fail;
|
||||
case 0:
|
||||
op = (code >> 2) & 3;
|
||||
dir = 1 - ((code >> 5) & 1);
|
||||
@ -1762,14 +1765,14 @@ static void set_reg_dsp_write_z(sh_info *info, int pos, int r,
|
||||
}
|
||||
|
||||
static bool dsp_op_cc_3opr(uint32_t code, sh_info *info, sh_dsp_insn insn,
|
||||
sh_dsp_insn_type insn2, cs_detail *detail)
|
||||
sh_dsp_insn insn2, cs_detail *detail)
|
||||
{
|
||||
info->op.operands[2].dsp.cc = (code >> 8) & 3;
|
||||
if (info->op.operands[2].dsp.cc > 0) {
|
||||
info->op.operands[2].dsp.insn = insn;
|
||||
} else {
|
||||
if (insn2 != SH_INS_DSP_INVALID)
|
||||
info->op.operands[2].dsp.insn = (sh_dsp_insn) insn2;
|
||||
info->op.operands[2].dsp.insn = insn2;
|
||||
else
|
||||
return MCDisassembler_Fail;
|
||||
}
|
||||
@ -1914,11 +1917,11 @@ static bool decode_dsp_3op(const uint32_t code, sh_info *info,
|
||||
}
|
||||
case 0x08:
|
||||
return dsp_op_cc_3opr(code, info,
|
||||
SH_INS_DSP_PSUB, (sh_dsp_insn_type) SH_INS_DSP_PSUBC,
|
||||
SH_INS_DSP_PSUB, SH_INS_DSP_PSUBC,
|
||||
detail);
|
||||
case 0x09:
|
||||
return dsp_op_cc_3opr(code, info,
|
||||
SH_INS_DSP_PXOR, (sh_dsp_insn_type) SH_INS_DSP_PWSB,
|
||||
SH_INS_DSP_PXOR, SH_INS_DSP_PWSB,
|
||||
detail);
|
||||
case 0x0a:
|
||||
switch(sx) {
|
||||
@ -1958,7 +1961,7 @@ static bool decode_dsp_3op(const uint32_t code, sh_info *info,
|
||||
case 0x0d:
|
||||
return dsp_op_cc_3opr(code, info,
|
||||
SH_INS_DSP_POR,
|
||||
(sh_dsp_insn_type) SH_INS_DSP_PWAD,
|
||||
SH_INS_DSP_PWAD,
|
||||
detail);
|
||||
case 0x0e:
|
||||
if (cc == 0) {
|
||||
|
@ -73,7 +73,7 @@ static void set_mem_access(MCInst *MI, bool status)
|
||||
}
|
||||
}
|
||||
|
||||
void Sparc_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci)
|
||||
void Sparc_post_printer(csh ud, cs_insn *insn, SStream *insn_asm, MCInst *mci)
|
||||
{
|
||||
if (((cs_struct *)ud)->detail_opt != CS_OPT_ON)
|
||||
return;
|
||||
@ -81,8 +81,10 @@ void Sparc_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci)
|
||||
// fix up some instructions
|
||||
if (insn->id == SPARC_INS_CASX) {
|
||||
// first op is actually a memop, not regop
|
||||
uint8_t base = (uint8_t)insn->detail->sparc.operands[0].reg;
|
||||
memset(&insn->detail->sparc.operands[0], 0, sizeof(cs_sparc_op));
|
||||
insn->detail->sparc.operands[0].type = SPARC_OP_MEM;
|
||||
insn->detail->sparc.operands[0].mem.base = (uint8_t)insn->detail->sparc.operands[0].reg;
|
||||
insn->detail->sparc.operands[0].mem.base = base;
|
||||
insn->detail->sparc.operands[0].mem.disp = 0;
|
||||
}
|
||||
}
|
||||
@ -333,7 +335,7 @@ static void printCCOperand(MCInst *MI, int opNum, SStream *O)
|
||||
SStream_concat0(O, SPARCCondCodeToString((sparc_cc)CC));
|
||||
|
||||
if (MI->csh->detail_opt)
|
||||
MI->flat_insn->detail->sparc.cc = (sparc_cc)CC;
|
||||
MI->flat_insn->detail->sparc.cc = (sparc_cc)CC; // NOLINT(clang-analyzer-optin.core.EnumCastOutOfRange)
|
||||
}
|
||||
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
void Sparc_printInst(MCInst *MI, SStream *O, void *Info);
|
||||
|
||||
void Sparc_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci);
|
||||
void Sparc_post_printer(csh ud, cs_insn *insn, SStream *insn_asm, MCInst *mci);
|
||||
|
||||
void Sparc_addReg(MCInst *MI, int reg);
|
||||
|
||||
|
@ -269,8 +269,8 @@ static DecodeStatus DecodeMemOperandSc(MCInst *Inst, unsigned Val,
|
||||
|
||||
if((base >= TMS320C64X_REG_A0) && (base <= TMS320C64X_REG_A31))
|
||||
base = (base - TMS320C64X_REG_A0 + TMS320C64X_REG_B0);
|
||||
else if((base >= TMS320C64X_REG_B0) && (base <= TMS320C64X_REG_B31))
|
||||
base = (base - TMS320C64X_REG_B0 + TMS320C64X_REG_A0);
|
||||
// base cannot be a B register, because it was ANDed above with 0x1f.
|
||||
// And the TMS320C64X_REG_B0 > 31
|
||||
basereg = getReg(GPRegsDecoderTable, base);
|
||||
if (basereg == ~0U)
|
||||
return MCDisassembler_Fail;
|
||||
@ -292,8 +292,8 @@ static DecodeStatus DecodeMemOperandSc(MCInst *Inst, unsigned Val,
|
||||
case 15:
|
||||
if((offset >= TMS320C64X_REG_A0) && (offset <= TMS320C64X_REG_A31))
|
||||
offset = (offset - TMS320C64X_REG_A0 + TMS320C64X_REG_B0);
|
||||
else if((offset >= TMS320C64X_REG_B0) && (offset <= TMS320C64X_REG_B31))
|
||||
offset = (offset - TMS320C64X_REG_B0 + TMS320C64X_REG_A0);
|
||||
// offset cannot be a B register, because it was ANDed above with 0x1f.
|
||||
// And the TMS320C64X_REG_B0 > 31
|
||||
offsetreg = getReg(GPRegsDecoderTable, offset);
|
||||
if (offsetreg == ~0U)
|
||||
return MCDisassembler_Fail;
|
||||
|
@ -3,17 +3,6 @@
|
||||
|
||||
#ifdef CAPSTONE_HAS_TMS320C64X
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Disable security warnings for strcpy
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
// Banned API Usage : strcpy is a Banned API as listed in dontuse.h for
|
||||
// security purposes.
|
||||
#pragma warning(disable:28719)
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -33,10 +22,11 @@ static void printMemOperand(MCInst *MI, unsigned OpNo, SStream *O);
|
||||
static void printMemOperand2(MCInst *MI, unsigned OpNo, SStream *O);
|
||||
static void printRegPair(MCInst *MI, unsigned OpNo, SStream *O);
|
||||
|
||||
void TMS320C64x_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci)
|
||||
void TMS320C64x_post_printer(csh ud, cs_insn *insn, SStream *insn_asm, MCInst *mci)
|
||||
{
|
||||
SStream ss;
|
||||
char *p, *p2, tmp[8];
|
||||
const char *op_str_ptr, *p2;
|
||||
char tmp[8] = { 0 };
|
||||
unsigned int unit = 0;
|
||||
int i;
|
||||
cs_tms320c64x *tms320c64x;
|
||||
@ -71,50 +61,56 @@ void TMS320C64x_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci)
|
||||
if (tms320c64x->condition.reg != TMS320C64X_REG_INVALID)
|
||||
SStream_concat(&ss, "[%c%s]|", (tms320c64x->condition.zero == 1) ? '!' : '|', cs_reg_name(ud, tms320c64x->condition.reg));
|
||||
|
||||
p = strchr(insn_asm, '\t');
|
||||
if (p != NULL)
|
||||
*p++ = '\0';
|
||||
// Sorry for all the fixes below. I don't have time to add more helper SStream functions.
|
||||
// Before that they messed around with the private buffer of th stream.
|
||||
// So it is better now. But still not effecient.
|
||||
op_str_ptr = strchr(SStream_rbuf(insn_asm), '\t');
|
||||
|
||||
SStream_concat0(&ss, insn_asm);
|
||||
if ((p != NULL) && (((p2 = strchr(p, '[')) != NULL) || ((p2 = strchr(p, '(')) != NULL))) {
|
||||
while ((p2 > p) && ((*p2 != 'a') && (*p2 != 'b')))
|
||||
if ((op_str_ptr != NULL) && (((p2 = strchr(op_str_ptr, '[')) != NULL) || ((p2 = strchr(op_str_ptr, '(')) != NULL))) {
|
||||
while ((p2 > op_str_ptr) && ((*p2 != 'a') && (*p2 != 'b')))
|
||||
p2--;
|
||||
if (p2 == p) {
|
||||
strcpy(insn_asm, "Invalid!");
|
||||
if (p2 == op_str_ptr) {
|
||||
SStream_Flush(insn_asm, NULL);
|
||||
SStream_concat0(insn_asm, "Invalid!");
|
||||
return;
|
||||
}
|
||||
if (*p2 == 'a')
|
||||
strcpy(tmp, "1T");
|
||||
strncpy(tmp, "1T", sizeof(tmp));
|
||||
else
|
||||
strcpy(tmp, "2T");
|
||||
strncpy(tmp, "2T", sizeof(tmp));
|
||||
} else {
|
||||
tmp[0] = '\0';
|
||||
}
|
||||
SStream mnem_post = { 0 };
|
||||
SStream_Init(&mnem_post);
|
||||
switch(tms320c64x->funit.unit) {
|
||||
case TMS320C64X_FUNIT_D:
|
||||
SStream_concat(&ss, ".D%s%u", tmp, tms320c64x->funit.side);
|
||||
SStream_concat(&mnem_post, ".D%s%u", tmp, tms320c64x->funit.side);
|
||||
break;
|
||||
case TMS320C64X_FUNIT_L:
|
||||
SStream_concat(&ss, ".L%s%u", tmp, tms320c64x->funit.side);
|
||||
SStream_concat(&mnem_post, ".L%s%u", tmp, tms320c64x->funit.side);
|
||||
break;
|
||||
case TMS320C64X_FUNIT_M:
|
||||
SStream_concat(&ss, ".M%s%u", tmp, tms320c64x->funit.side);
|
||||
SStream_concat(&mnem_post, ".M%s%u", tmp, tms320c64x->funit.side);
|
||||
break;
|
||||
case TMS320C64X_FUNIT_S:
|
||||
SStream_concat(&ss, ".S%s%u", tmp, tms320c64x->funit.side);
|
||||
SStream_concat(&mnem_post, ".S%s%u", tmp, tms320c64x->funit.side);
|
||||
break;
|
||||
}
|
||||
if (tms320c64x->funit.crosspath > 0)
|
||||
SStream_concat0(&ss, "X");
|
||||
SStream_concat0(&mnem_post, "X");
|
||||
|
||||
if (p != NULL)
|
||||
SStream_concat(&ss, "\t%s", p);
|
||||
if (op_str_ptr != NULL) {
|
||||
// There is an op_str
|
||||
SStream_concat1(&mnem_post, '\t');
|
||||
SStream_replc_str(insn_asm, '\t', SStream_rbuf(&mnem_post));
|
||||
}
|
||||
|
||||
if (tms320c64x->parallel != 0)
|
||||
SStream_concat0(&ss, "\t||");
|
||||
|
||||
/* insn_asm is a buffer from an SStream, so there should be enough space */
|
||||
strcpy(insn_asm, ss.buffer);
|
||||
SStream_concat0(insn_asm, "\t||");
|
||||
SStream_concat0(&ss, SStream_rbuf(insn_asm));
|
||||
SStream_Flush(insn_asm, NULL);
|
||||
SStream_concat0(insn_asm, SStream_rbuf(&ss));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,6 @@
|
||||
|
||||
void TMS320C64x_printInst(MCInst *MI, SStream *O, void *Info);
|
||||
|
||||
void TMS320C64x_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci);
|
||||
void TMS320C64x_post_printer(csh ud, cs_insn *insn, SStream *insn_asm, MCInst *mci);
|
||||
|
||||
#endif
|
||||
|
@ -766,13 +766,13 @@ static DecodeStatus DecodeRRInstruction(MCInst *Inst, unsigned Insn,
|
||||
status = DecodeRegisterClass(Inst, s2, &desc->OpInfo[1],
|
||||
Decoder);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
status = DecodeRegisterClass(Inst, s1, &desc->OpInfo[1],
|
||||
Decoder);
|
||||
}
|
||||
if (status != MCDisassembler_Success)
|
||||
return status;
|
||||
}
|
||||
if (status != MCDisassembler_Success)
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -277,8 +277,8 @@ static void printDisp24Imm(MCInst *MI, int OpNum, SStream *O)
|
||||
case TRICORE_JA_b:
|
||||
case TRICORE_JLA_b:
|
||||
// = {disp24[23:20], 7’b0000000, disp24[19:0], 1’b0};
|
||||
res = ((wrapping_u32(disp) & 0xf00000) << 28) |
|
||||
((wrapping_u32(disp) & 0xfffff) << 1);
|
||||
res = ((wrapping_u32(disp) & 0xf00000ULL) << 28) |
|
||||
((wrapping_u32(disp) & 0xfffffULL) << 1);
|
||||
break;
|
||||
case TRICORE_J_b:
|
||||
case TRICORE_JL_b:
|
||||
@ -346,7 +346,7 @@ static void printDisp8Imm(MCInst *MI, int OpNum, SStream *O)
|
||||
int64_t res = 0;
|
||||
switch (MCInst_getOpcode(MI)) {
|
||||
case TRICORE_CALL_sb:
|
||||
disp = DISP1(8);
|
||||
res = DISP1(8);
|
||||
break;
|
||||
case TRICORE_J_sb:
|
||||
case TRICORE_JNZ_sb:
|
||||
|
@ -459,9 +459,6 @@ static bool read_memoryimmediate(const uint8_t *code, size_t code_len, uint16_t
|
||||
|
||||
len = tmp;
|
||||
data[1] = get_varuint32(&code[len], code_len - len, &tmp);
|
||||
if (len == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (MI->flat_insn->detail) {
|
||||
MI->flat_insn->detail->wasm.operands[1].type = WASM_OP_VARUINT32;
|
||||
|
@ -582,8 +582,9 @@ static void printOperand(MCInst *MI, unsigned OpNo, SStream *O)
|
||||
int64_t imm = MCOperand_getImm(Op);
|
||||
uint8_t opsize = X86_immediate_size(MCInst_getOpcode(MI), &encsize);
|
||||
|
||||
if (opsize == 1) // print 1 byte immediate in positive form
|
||||
if (opsize == 1) { // print 1 byte immediate in positive form
|
||||
imm = imm & 0xff;
|
||||
}
|
||||
|
||||
switch(MI->flat_insn->id) {
|
||||
default:
|
||||
@ -598,9 +599,9 @@ static void printOperand(MCInst *MI, unsigned OpNo, SStream *O)
|
||||
switch(opsize) {
|
||||
default:
|
||||
break;
|
||||
case 1:
|
||||
imm &= 0xff;
|
||||
break;
|
||||
// case 1 cannot occur because above imm was ANDed with 0xff,
|
||||
// making it effectively always positive.
|
||||
// So this switch is never reached.
|
||||
case 2:
|
||||
imm &= 0xffff;
|
||||
break;
|
||||
|
@ -2246,7 +2246,7 @@ unsigned short X86_register_map(unsigned short id)
|
||||
|
||||
/// The post-printer function. Used to fixup flaws in the disassembly information
|
||||
/// of certain instructions.
|
||||
void X86_postprinter(csh handle, cs_insn *insn, char *mnem, MCInst *mci) {
|
||||
void X86_postprinter(csh handle, cs_insn *insn, SStream *mnem, MCInst *mci) {
|
||||
if (!insn || !insn->detail) {
|
||||
return;
|
||||
}
|
||||
|
@ -91,6 +91,6 @@ unsigned short X86_register_map(unsigned short id);
|
||||
|
||||
unsigned int find_insn(unsigned int id);
|
||||
|
||||
void X86_postprinter(csh handle, cs_insn *insn, char *mnem, MCInst *mci);
|
||||
void X86_postprinter(csh handle, cs_insn *insn, SStream *mnem, MCInst *mci);
|
||||
|
||||
#endif
|
||||
|
@ -16,11 +16,6 @@
|
||||
|
||||
#ifdef CAPSTONE_HAS_XCORE
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4996) // disable MSVC's warning on strcpy()
|
||||
#pragma warning(disable : 28719) // disable MSVC's warning on strcpy()
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -36,7 +31,7 @@
|
||||
|
||||
static const char *getRegisterName(unsigned RegNo);
|
||||
|
||||
void XCore_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci)
|
||||
void XCore_post_printer(csh ud, cs_insn *insn, SStream *insn_asm, MCInst *mci)
|
||||
{
|
||||
/*
|
||||
if (((cs_struct *)ud)->detail != CS_OPT_ON)
|
||||
@ -51,7 +46,7 @@ void XCore_insn_extract(MCInst *MI, const char *code)
|
||||
char *p, *p2;
|
||||
char tmp[128];
|
||||
|
||||
strcpy(tmp, code); // safe because code is way shorter than 128 bytes
|
||||
strncpy(tmp, code, sizeof(tmp) - 1); // safe because code is way shorter than 128 bytes
|
||||
|
||||
// find the first space
|
||||
p = strchr(tmp, ' ');
|
||||
@ -167,8 +162,10 @@ static void set_mem_access(MCInst *MI, bool status, int reg)
|
||||
} else {
|
||||
// the last op should be the memory base
|
||||
MI->flat_insn->detail->xcore.op_count--;
|
||||
uint8_t base = MI->flat_insn->detail->xcore.operands[MI->flat_insn->detail->xcore.op_count].reg;
|
||||
memset(&MI->flat_insn->detail->xcore.operands[MI->flat_insn->detail->xcore.op_count], 0, sizeof(cs_xcore_op));
|
||||
MI->flat_insn->detail->xcore.operands[MI->flat_insn->detail->xcore.op_count].type = XCORE_OP_MEM;
|
||||
MI->flat_insn->detail->xcore.operands[MI->flat_insn->detail->xcore.op_count].mem.base = (uint8_t)MI->flat_insn->detail->xcore.operands[MI->flat_insn->detail->xcore.op_count].reg;
|
||||
MI->flat_insn->detail->xcore.operands[MI->flat_insn->detail->xcore.op_count].mem.base = base;
|
||||
MI->flat_insn->detail->xcore.operands[MI->flat_insn->detail->xcore.op_count].mem.index = XCORE_REG_INVALID;
|
||||
MI->flat_insn->detail->xcore.operands[MI->flat_insn->detail->xcore.op_count].mem.disp = 0;
|
||||
if (reg > 0)
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
void XCore_printInst(MCInst *MI, SStream *O, void *Info);
|
||||
|
||||
void XCore_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci);
|
||||
void XCore_post_printer(csh ud, cs_insn *insn, SStream *insn_asm, MCInst *mci);
|
||||
|
||||
// extract details from assembly code @code
|
||||
void XCore_insn_extract(MCInst *MI, const char *code);
|
||||
|
@ -1129,8 +1129,8 @@ class Cs(object):
|
||||
status = _cs.cs_option(self.csh, opt_type, opt_value)
|
||||
if status != CS_ERR_OK:
|
||||
raise CsError(status)
|
||||
if opt_type == CS_OPT_DETAIL:
|
||||
self._detail = opt_value == CS_OPT_ON
|
||||
if opt_type == CS_OPT_DETAIL or opt_type == CS_OPT_DETAIL_REAL:
|
||||
self._detail = (opt_value & CS_OPT_ON) != 0
|
||||
elif opt_type == CS_OPT_SKIPDATA:
|
||||
self._skipdata = opt_value == CS_OPT_ON
|
||||
elif opt_type == CS_OPT_UNSIGNED:
|
||||
|
@ -21,6 +21,8 @@ ARMCC_UNDEF = 15
|
||||
ARMVCC_None = 0
|
||||
ARMVCC_Then = 1
|
||||
ARMVCC_Else = 2
|
||||
|
||||
ARM_PredBlockMaskInvalid = 0
|
||||
ARM_T = 0x8
|
||||
ARM_TT = 0x4
|
||||
ARM_TE = 0xc
|
||||
|
@ -1,6 +1,5 @@
|
||||
from . import CS_OP_INVALID, CS_OP_REG, CS_OP_IMM, CS_OP_FP, CS_OP_PRED, CS_OP_SPECIAL, CS_OP_MEM, CS_OP_MEM_REG, CS_OP_MEM_IMM, UINT16_MAX, UINT8_MAX
|
||||
# For Capstone Engine. AUTO-GENERATED FILE, DO NOT EDIT [hppa_const.py]
|
||||
HPPA_MAX_OPS = 5
|
||||
HPPA_STR_MODIFIER_LEN = 8
|
||||
HPPA_MAX_MODIFIERS_LEN = 5
|
||||
|
||||
|
@ -142,9 +142,6 @@ SH_OP_MEM_PCR = 8
|
||||
SH_OP_MEM_TBR_DISP = 9
|
||||
|
||||
SH_INS_DSP_INVALID = 0
|
||||
SH_INS_DSP_DOUBLE = 1
|
||||
SH_INS_DSP_SINGLE = 2
|
||||
SH_INS_DSP_PARALLEL = 3
|
||||
SH_INS_DSP_NOP = 1
|
||||
SH_INS_DSP_MOV = 2
|
||||
SH_INS_DSP_PSHL = 3
|
||||
|
@ -15,6 +15,7 @@ SYSTEMZ_CC_NL = 10
|
||||
SYSTEMZ_CC_LE = 11
|
||||
SYSTEMZ_CC_NH = 12
|
||||
SYSTEMZ_CC_NO = 13
|
||||
SYSTEMZ_CC_INVALID = 14
|
||||
SYSTEMZ_OP_INVALID = CS_OP_INVALID
|
||||
SYSTEMZ_OP_REG = CS_OP_REG
|
||||
SYSTEMZ_OP_IMM = CS_OP_IMM
|
||||
|
@ -4,7 +4,6 @@ TRICORE_OP_INVALID = CS_OP_INVALID
|
||||
TRICORE_OP_REG = CS_OP_REG
|
||||
TRICORE_OP_IMM = CS_OP_IMM
|
||||
TRICORE_OP_MEM = CS_OP_MEM
|
||||
TRICORE_OP_COUNT = 8
|
||||
|
||||
TRICORE_REG_INVALID = 0
|
||||
TRICORE_REG_FCX = 1
|
||||
|
64
cs.c
64
cs.c
@ -1,9 +1,7 @@
|
||||
/* Capstone Disassembly Engine */
|
||||
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2019 */
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4996) // disable MSVC's warning on strcpy()
|
||||
#pragma warning(disable:28719) // disable MSVC's warning on strcpy()
|
||||
#endif
|
||||
|
||||
#include "SStream.h"
|
||||
#if defined(CAPSTONE_HAS_OSXKERNEL)
|
||||
#include <Availability.h>
|
||||
#include <libkern/libkern.h>
|
||||
@ -866,35 +864,14 @@ static int str_replace(char *result, char *target, const char *str1, char *str2)
|
||||
}
|
||||
#endif
|
||||
|
||||
/// The asm string sometimes has a leading space or tab.
|
||||
/// Here we remove it.
|
||||
static void fixup_asm_string(char *asm_str) {
|
||||
if (!asm_str) {
|
||||
return;
|
||||
}
|
||||
int i = 0;
|
||||
int k = 0;
|
||||
bool text_reached = (asm_str[0] != ' ' && asm_str[0] != '\t');
|
||||
while (asm_str[i]) {
|
||||
if (!text_reached && (asm_str[i] == ' ' || asm_str[i] == '\t')) {
|
||||
++i;
|
||||
text_reached = true;
|
||||
continue;
|
||||
}
|
||||
asm_str[k] = asm_str[i];
|
||||
++k, ++i;
|
||||
}
|
||||
asm_str[k] = '\0';
|
||||
}
|
||||
|
||||
// fill insn with mnemonic & operands info
|
||||
static void fill_insn(struct cs_struct *handle, cs_insn *insn, char *buffer, MCInst *mci,
|
||||
static void fill_insn(struct cs_struct *handle, cs_insn *insn, SStream *OS, MCInst *mci,
|
||||
PostPrinter_t postprinter, const uint8_t *code)
|
||||
{
|
||||
#ifndef CAPSTONE_DIET
|
||||
char *sp, *mnem;
|
||||
char *sp;
|
||||
#endif
|
||||
fixup_asm_string(buffer);
|
||||
SStream_trimls(OS);
|
||||
uint16_t copy_size = MIN(sizeof(insn->bytes), insn->size);
|
||||
|
||||
// fill the instruction bytes.
|
||||
@ -909,23 +886,17 @@ static void fill_insn(struct cs_struct *handle, cs_insn *insn, char *buffer, MCI
|
||||
|
||||
// post printer handles some corner cases (hacky)
|
||||
if (postprinter)
|
||||
postprinter((csh)handle, insn, buffer, mci);
|
||||
postprinter((csh)handle, insn, OS, mci);
|
||||
|
||||
#ifndef CAPSTONE_DIET
|
||||
mnem = insn->mnemonic;
|
||||
// memset(mnem, 0, CS_MNEMONIC_SIZE);
|
||||
for (sp = buffer; *sp; sp++) {
|
||||
if (*sp == ' '|| *sp == '\t')
|
||||
break;
|
||||
memset(insn->mnemonic, '\0', sizeof(insn->mnemonic));
|
||||
memset(insn->op_str, '\0', sizeof(insn->op_str));
|
||||
SStream_extract_mnem_opstr(OS, insn->mnemonic, sizeof(insn->mnemonic), insn->op_str, sizeof(insn->op_str));
|
||||
for (sp = insn->mnemonic; *sp; sp++) {
|
||||
if (*sp == '|') // lock|rep prefix for x86
|
||||
*sp = ' ';
|
||||
// copy to @mnemonic
|
||||
*mnem = *sp;
|
||||
mnem++;
|
||||
}
|
||||
|
||||
*mnem = '\0';
|
||||
|
||||
// we might have customized mnemonic
|
||||
if (handle->mnem_list) {
|
||||
struct insn_mnem *tmp = handle->mnem_list;
|
||||
@ -944,17 +915,6 @@ static void fill_insn(struct cs_struct *handle, cs_insn *insn, char *buffer, MCI
|
||||
tmp = tmp->next;
|
||||
}
|
||||
}
|
||||
|
||||
// copy @op_str
|
||||
if (*sp) {
|
||||
// find the next non-space char
|
||||
sp++;
|
||||
for (; ((*sp == ' ') || (*sp == '\t')); sp++);
|
||||
strncpy(insn->op_str, sp, sizeof(insn->op_str) - 1);
|
||||
insn->op_str[sizeof(insn->op_str) - 1] = '\0';
|
||||
} else
|
||||
insn->op_str[0] = '\0';
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1279,7 +1239,7 @@ size_t CAPSTONE_API cs_disasm(csh ud, const uint8_t *buffer, size_t size, uint64
|
||||
handle->insn_id(handle, insn_cache, mci.Opcode);
|
||||
|
||||
handle->printer(&mci, &ss, handle->printer_info);
|
||||
fill_insn(handle, insn_cache, ss.buffer, &mci, handle->post_printer, buffer);
|
||||
fill_insn(handle, insn_cache, &ss, &mci, handle->post_printer, buffer);
|
||||
|
||||
// adjust for pseudo opcode (X86)
|
||||
if (handle->arch == CS_ARCH_X86 && insn_cache->id != X86_INS_VCMP)
|
||||
@ -1485,7 +1445,7 @@ bool CAPSTONE_API cs_disasm_iter(csh ud, const uint8_t **code, size_t *size,
|
||||
|
||||
handle->printer(&mci, &ss, handle->printer_info);
|
||||
|
||||
fill_insn(handle, insn, ss.buffer, &mci, handle->post_printer, *code);
|
||||
fill_insn(handle, insn, &ss, &mci, handle->post_printer, *code);
|
||||
|
||||
// adjust for pseudo opcode (X86)
|
||||
if (handle->arch == CS_ARCH_X86)
|
||||
|
@ -16,7 +16,7 @@ typedef void (*Printer_t)(MCInst *MI, SStream *OS, void *info);
|
||||
|
||||
// function to be called after Printer_t
|
||||
// this is the best time to gather insn's characteristics
|
||||
typedef void (*PostPrinter_t)(csh handle, cs_insn *, char *mnem, MCInst *mci);
|
||||
typedef void (*PostPrinter_t)(csh handle, cs_insn *, SStream *mnem, MCInst *mci);
|
||||
|
||||
typedef bool (*Disasm_t)(csh handle, const uint8_t *code, size_t code_len, MCInst *instr, uint16_t *size, uint64_t address, void *info);
|
||||
|
||||
|
@ -347,7 +347,6 @@ static void usage(char *prog)
|
||||
printf(" -a Print Capstone register alias (if any). Otherwise LLVM register names are emitted.\n");
|
||||
printf(" -s decode in SKIPDATA mode\n");
|
||||
printf(" -u show immediates as unsigned\n");
|
||||
printf(" -f Dev fuzzing: Disassembles <assembly-hexstring> to 0xffffffff.\n\n");
|
||||
printf(" -v show version & Capstone core build info\n\n");
|
||||
}
|
||||
|
||||
@ -439,53 +438,6 @@ static void print_details(csh handle, cs_arch arch, cs_mode md, cs_insn *ins)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static uint32_t read_le(uint8_t *buf, size_t size) {
|
||||
uint32_t res = 0;
|
||||
for (size_t i = 0, j = size - 1; i < size; ++i, --j) {
|
||||
res |= buf[i] << j * 8;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static void to_buf(uint32_t num, uint8_t *buf) {
|
||||
for (size_t i = 0, j = 3; i < 4; ++i, --j) {
|
||||
buf[i] = (num >> j) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
static void run_dev_fuzz(csh handle, uint8_t *bytes, uint32_t size) {
|
||||
uint8_t buf[4] = {0};
|
||||
uint32_t bytes_as_num = read_le(bytes, size);
|
||||
uint32_t address = 0xffffffff;
|
||||
|
||||
printf("Run dev fuzz\n");
|
||||
printf("Start: 0x%" PRIx32 "\n", bytes_as_num);
|
||||
printf("End: 0xffffffff\n"
|
||||
"Address: 0x%" PRIx32 "\n", address);
|
||||
|
||||
cs_insn *insn;
|
||||
while (true) {
|
||||
printf("\rProgress: 0x%08x\t\t", bytes_as_num);
|
||||
fflush(stdout);
|
||||
cs_disasm(handle, buf, 4, address, 0, &insn);
|
||||
if (insn && insn->detail)
|
||||
free(insn->detail);
|
||||
free(insn);
|
||||
bytes_as_num++;
|
||||
to_buf(bytes_as_num, buf);
|
||||
if (bytes_as_num == 0xffffffff) {
|
||||
printf("\rProgress: 0x%08x\t\t", bytes_as_num);
|
||||
fflush(stdout);
|
||||
cs_disasm(handle, (uint8_t*)&buf, 4, address, 0, &insn);
|
||||
if (insn && insn->detail)
|
||||
free(insn->detail);
|
||||
free(insn);
|
||||
printf("\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static cs_mode find_additional_modes(const char *input, cs_arch arch) {
|
||||
if (!input) {
|
||||
return 0;
|
||||
@ -541,7 +493,6 @@ int main(int argc, char **argv)
|
||||
bool skipdata = false;
|
||||
bool custom_reg_alias = false;
|
||||
bool set_real_detail = false;
|
||||
bool dev_fuzz = false;
|
||||
int args_left;
|
||||
|
||||
while ((c = getopt (argc, argv, "rasudhvf")) != -1) {
|
||||
@ -659,9 +610,6 @@ int main(int argc, char **argv)
|
||||
|
||||
printf("\n");
|
||||
return 0;
|
||||
case 'f':
|
||||
dev_fuzz = true;
|
||||
break;
|
||||
case 'h':
|
||||
usage(argv[0]);
|
||||
return 0;
|
||||
@ -745,13 +693,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
if (set_real_detail) {
|
||||
cs_option(handle, CS_OPT_DETAIL, CS_OPT_DETAIL_REAL);
|
||||
}
|
||||
|
||||
if (dev_fuzz) {
|
||||
run_dev_fuzz(handle, assembly, size);
|
||||
cs_close(&handle);
|
||||
return 0;
|
||||
cs_option(handle, CS_OPT_DETAIL, (CS_OPT_DETAIL_REAL | CS_OPT_ON));
|
||||
}
|
||||
|
||||
count = cs_disasm(handle, assembly, size, address, 0, &insn);
|
||||
|
@ -28,6 +28,7 @@ void print_insn_detail_aarch64(csh handle, cs_insn *ins)
|
||||
cs_aarch64_op *op = &(aarch64->operands[i]);
|
||||
switch(op->type) {
|
||||
default:
|
||||
printf("\t\tOperand type %" PRId32 " not handled\n", op->type);
|
||||
break;
|
||||
case AARCH64_OP_REG:
|
||||
printf("\t\toperands[%u].type: REG = %s%s\n", i, cs_reg_name(handle, op->reg), op->is_vreg ? " (vreg)" : "");
|
||||
|
@ -82,11 +82,12 @@ void print_insn_detail_arm(csh handle, cs_insn *ins)
|
||||
printf("\t\toperands[%u].type: MASK = %" PRIu8 "\n", i, op->sysop.msr_mask);
|
||||
break;
|
||||
case ARM_OP_BANKEDREG:
|
||||
// FIXME: Printing the name is currenliy not supported if the encodings overlap
|
||||
// FIXME: Printing the name is currently not supported if the encodings overlap
|
||||
// with system registers.
|
||||
printf("\t\toperands[%u].type: BANKEDREG = %" PRIu32 "\n", i, (uint32_t) op->sysop.reg.bankedreg);
|
||||
if (op->sysop.msr_mask != UINT8_MAX)
|
||||
printf("\t\toperands[%u].type: MASK = %" PRIu8 "\n", i, op->sysop.msr_mask);
|
||||
break;
|
||||
case ARM_OP_SPSR:
|
||||
case ARM_OP_CPSR: {
|
||||
const char type = op->type == ARM_OP_SPSR ? 'S' : 'C';
|
||||
|
@ -39,11 +39,7 @@ void print_insn_detail_systemz(csh handle, cs_insn *ins)
|
||||
printf("\t\t\toperands[%u].mem.index: REG = %s\n",
|
||||
i, cs_reg_name(handle, op->mem.index));
|
||||
if (op->mem.length != 0) {
|
||||
if (op->mem.am == SYSTEMZ_AM_BDL) {
|
||||
printf("\t\t\toperands[%u].mem.length: 0x%" PRIx64 "\n", i, op->mem.length);
|
||||
} else {
|
||||
printf("\t\t\toperands[%u].mem.length: 0x%" PRIx64 "\n", i, op->mem.length);
|
||||
}
|
||||
printf("\t\t\toperands[%u].mem.length: 0x%" PRIx64 "\n", i, op->mem.length);
|
||||
}
|
||||
printf("\t\t\toperands[%u].mem.disp: 0x%" PRIx64 "\n", i, op->mem.disp);
|
||||
switch(op->mem.am) {
|
||||
|
@ -240,6 +240,10 @@ void print_insn_detail_x86(csh ud, cs_mode mode, cs_insn *ins)
|
||||
printf("\timm_count: %u\n", count);
|
||||
for (i = 1; i < count + 1; i++) {
|
||||
int index = cs_op_index(ud, ins, X86_OP_IMM, i);
|
||||
if (index < 0) {
|
||||
printf("Operand was not found!\n");
|
||||
break;
|
||||
}
|
||||
printf("\t\timms[%u]: 0x%" PRIx64 "\n", i, x86->operands[index].imm);
|
||||
}
|
||||
}
|
||||
|
@ -338,7 +338,7 @@ Additionally, you can now choose between the alias details and the real details.
|
||||
If you always want the real instruction detail decoded (also for alias instructions),
|
||||
you can enable the option with
|
||||
```
|
||||
cs_option(handle, CS_OPT_DETAIL, CS_OPT_DETAIL_REAL);
|
||||
cs_option(handle, CS_OPT_DETAIL, CS_OPT_DETAIL_REAL | CS_OPT_ON);
|
||||
```
|
||||
|
||||
For the `cstool` you can enable it with the `-r` flag.
|
||||
|
@ -2852,7 +2852,7 @@ typedef struct {
|
||||
cs_ac_type mem_acc; ///< CGI memory access according to mayLoad and mayStore
|
||||
} aarch64_suppl_info;
|
||||
|
||||
#define MAX_AARCH64_OPS 8
|
||||
#define NUM_AARCH64_OPS 16
|
||||
|
||||
/// Instruction structure
|
||||
typedef struct cs_aarch64 {
|
||||
@ -2865,7 +2865,7 @@ typedef struct cs_aarch64 {
|
||||
/// or 0 when instruction has no operand.
|
||||
uint8_t op_count;
|
||||
|
||||
cs_aarch64_op operands[MAX_AARCH64_OPS]; ///< operands for this instruction.
|
||||
cs_aarch64_op operands[NUM_AARCH64_OPS]; ///< operands for this instruction.
|
||||
} cs_aarch64;
|
||||
|
||||
/// AArch64 instruction
|
||||
|
@ -19,7 +19,7 @@ extern "C" {
|
||||
#pragma warning(disable : 4201)
|
||||
#endif
|
||||
|
||||
#define MAX_ALPHA_OPS 3
|
||||
#define NUM_ALPHA_OPS 3
|
||||
|
||||
//> Operand type for instruction's operands
|
||||
typedef enum alpha_op_type {
|
||||
@ -43,7 +43,7 @@ typedef struct cs_alpha {
|
||||
// Number of operands of this instruction,
|
||||
// or 0 when instruction has no operand.
|
||||
uint8_t op_count;
|
||||
cs_alpha_op operands[MAX_ALPHA_OPS]; // operands for this instruction.
|
||||
cs_alpha_op operands[NUM_ALPHA_OPS]; // operands for this instruction.
|
||||
} cs_alpha;
|
||||
|
||||
|
||||
|
@ -125,6 +125,7 @@ typedef enum VPTCodes {
|
||||
/// Txy = xy10
|
||||
/// Txyz = xyz1
|
||||
typedef enum PredBlockMask {
|
||||
ARM_PredBlockMaskInvalid = 0,
|
||||
ARM_T = 0x8, // 0b1000
|
||||
ARM_TT = 0x4, // 0b0100
|
||||
ARM_TE = 0xc, // 0b1100
|
||||
@ -890,7 +891,7 @@ typedef struct cs_arm_op {
|
||||
int8_t neon_lane;
|
||||
} cs_arm_op;
|
||||
|
||||
#define MAX_ARM_OPS 36
|
||||
#define NUM_ARM_OPS 36
|
||||
|
||||
/// Instruction structure
|
||||
typedef struct cs_arm {
|
||||
@ -910,7 +911,7 @@ typedef struct cs_arm {
|
||||
/// or 0 when instruction has no operand.
|
||||
uint8_t op_count;
|
||||
|
||||
cs_arm_op operands[MAX_ARM_OPS]; ///< operands for this instruction.
|
||||
cs_arm_op operands[NUM_ARM_OPS]; ///< operands for this instruction.
|
||||
} cs_arm;
|
||||
|
||||
/// ARM instruction
|
||||
|
@ -8,7 +8,7 @@ extern "C" {
|
||||
#include "cs_operand.h"
|
||||
#include "platform.h"
|
||||
|
||||
#define HPPA_MAX_OPS 5
|
||||
#define NUM_HPPA_OPS 5
|
||||
#define HPPA_STR_MODIFIER_LEN 8
|
||||
#define HPPA_MAX_MODIFIERS_LEN 5
|
||||
|
||||
@ -492,7 +492,7 @@ typedef struct cs_hppa {
|
||||
// Number of operands of this instruction,
|
||||
// or 0 when instruction has no operand.
|
||||
uint8_t op_count;
|
||||
cs_hppa_op operands[HPPA_MAX_OPS]; ///< operands for hppa instruction.
|
||||
cs_hppa_op operands[NUM_HPPA_OPS]; ///< operands for hppa instruction.
|
||||
} cs_hppa;
|
||||
|
||||
/// HPPA modifiers type. Can be string (most of them) or int (uid, sop)
|
||||
|
@ -177,6 +177,8 @@ typedef struct {
|
||||
memory_access; ///< Memory access (none/read/write/read+write)
|
||||
} loongarch_suppl_info;
|
||||
|
||||
#define NUM_LOONGARCH_OPS 8
|
||||
|
||||
/// Instruction structure
|
||||
typedef struct cs_loongarch {
|
||||
/// The instruction format. Can be use to determine the bit encoding of the instruction.
|
||||
@ -185,7 +187,7 @@ typedef struct cs_loongarch {
|
||||
/// Number of operands of this instruction,
|
||||
/// or 0 when instruction has no operand.
|
||||
uint8_t op_count;
|
||||
cs_loongarch_op operands[8]; ///< operands for this instruction.
|
||||
cs_loongarch_op operands[NUM_LOONGARCH_OPS]; ///< operands for this instruction.
|
||||
} cs_loongarch;
|
||||
|
||||
/// LoongArch registers
|
||||
|
@ -696,12 +696,14 @@ typedef struct cs_mips_op {
|
||||
uint8_t access;
|
||||
} cs_mips_op;
|
||||
|
||||
#define NUM_MIPS_OPS 10
|
||||
|
||||
/// Instruction structure
|
||||
typedef struct cs_mips {
|
||||
/// Number of operands of this instruction,
|
||||
/// or 0 when instruction has no operand.
|
||||
uint8_t op_count;
|
||||
cs_mips_op operands[10]; ///< operands for this instruction.
|
||||
cs_mips_op operands[NUM_MIPS_OPS]; ///< operands for this instruction.
|
||||
} cs_mips;
|
||||
|
||||
/// MIPS instruction
|
||||
|
@ -49,6 +49,8 @@ typedef struct cs_riscv_op {
|
||||
uint8_t access; ///< How is this operand accessed? (READ, WRITE or READ|WRITE)
|
||||
} cs_riscv_op;
|
||||
|
||||
#define NUM_RISCV_OPS 8
|
||||
|
||||
// Instruction structure
|
||||
typedef struct cs_riscv {
|
||||
// Does this instruction need effective address or not.
|
||||
@ -56,7 +58,7 @@ typedef struct cs_riscv {
|
||||
// Number of operands of this instruction,
|
||||
// or 0 when instruction has no operand.
|
||||
uint8_t op_count;
|
||||
cs_riscv_op operands[8]; // operands for this instruction.
|
||||
cs_riscv_op operands[NUM_RISCV_OPS]; // operands for this instruction.
|
||||
} cs_riscv;
|
||||
|
||||
//> RISCV registers
|
||||
|
@ -182,15 +182,8 @@ typedef struct sh_op_mem {
|
||||
uint32_t disp; /// <= displacement
|
||||
} sh_op_mem;
|
||||
|
||||
// SH-DSP instcutions define
|
||||
typedef enum sh_dsp_insn_type {
|
||||
SH_INS_DSP_INVALID,
|
||||
SH_INS_DSP_DOUBLE,
|
||||
SH_INS_DSP_SINGLE,
|
||||
SH_INS_DSP_PARALLEL,
|
||||
} sh_dsp_insn_type;
|
||||
|
||||
typedef enum sh_dsp_insn {
|
||||
SH_INS_DSP_INVALID = 0,
|
||||
SH_INS_DSP_NOP = 1,
|
||||
SH_INS_DSP_MOV,
|
||||
SH_INS_DSP_PSHL,
|
||||
|
@ -47,13 +47,13 @@ typedef struct cs_tricore_op {
|
||||
uint8_t access; ///< How is this operand accessed? (READ, WRITE or READ|WRITE)
|
||||
} cs_tricore_op;
|
||||
|
||||
#define TRICORE_OP_COUNT 8
|
||||
#define NUM_TRICORE_OPS 8
|
||||
|
||||
/// Instruction structure
|
||||
typedef struct cs_tricore {
|
||||
uint8_t op_count; ///< number of operands of this instruction.
|
||||
cs_tricore_op
|
||||
operands[TRICORE_OP_COUNT]; ///< operands for this instruction.
|
||||
operands[NUM_TRICORE_OPS]; ///< operands for this instruction.
|
||||
/// TODO: Mark the modified flags register in td files and regenerate inc files
|
||||
bool update_flags; ///< whether the flags register is updated.
|
||||
} cs_tricore;
|
||||
|
@ -37,7 +37,7 @@ typedef enum aarch64_op_type_upper {
|
||||
AARCH64_OP_SYSALIASIII, // Comment
|
||||
} aarch64_op_type_upper;
|
||||
|
||||
#define MAX_AARCH64_OPS 8
|
||||
#define NUM_AARCH64_OPS 8
|
||||
|
||||
/// Instruction structure
|
||||
typedef struct cs_aarch64 {
|
||||
@ -50,7 +50,7 @@ typedef struct cs_aarch64 {
|
||||
/// or 0 when instruction has no operand.
|
||||
uint8_t op_count;
|
||||
|
||||
cs_aarch64_op operands[MAX_AARCH64_OPS]; ///< operands for this instruction.
|
||||
cs_aarch64_op operands[NUM_AARCH64_OPS]; ///< operands for this instruction.
|
||||
} cs_aarch64;
|
||||
|
||||
#endif
|
||||
|
@ -61,17 +61,18 @@ char *test_input_stringify(const TestInput *test_input, const char *postfix)
|
||||
char *byte_seq =
|
||||
byte_seq_to_str(test_input->bytes, test_input->bytes_count);
|
||||
if (!msg) {
|
||||
cs_mem_free(byte_seq);
|
||||
return NULL;
|
||||
}
|
||||
char opt_seq[128] = { 0 };
|
||||
append_to_str(opt_seq, sizeof(opt_seq), "[");
|
||||
str_append_no_realloc(opt_seq, sizeof(opt_seq), "[");
|
||||
for (size_t i = 0; i < test_input->options_count; ++i) {
|
||||
append_to_str(opt_seq, sizeof(opt_seq), test_input->options[i]);
|
||||
str_append_no_realloc(opt_seq, sizeof(opt_seq), test_input->options[i]);
|
||||
if (i < test_input->options_count - 1) {
|
||||
append_to_str(opt_seq, sizeof(opt_seq), ", ");
|
||||
str_append_no_realloc(opt_seq, sizeof(opt_seq), ", ");
|
||||
}
|
||||
}
|
||||
append_to_str(opt_seq, sizeof(opt_seq), "]");
|
||||
str_append_no_realloc(opt_seq, sizeof(opt_seq), "]");
|
||||
cs_snprintf(msg, msg_len,
|
||||
"%sTestInput { arch: %s, options: %s, addr: 0x%" PRIx64
|
||||
", bytes: %s }",
|
||||
@ -210,12 +211,12 @@ void test_expected_compare(csh *handle, TestExpected *expected, cs_insn *insns,
|
||||
// Either all in op_str or split in mnemonic and op_str
|
||||
char asm_text[256] = { 0 };
|
||||
if (insns[i].mnemonic[0] != '\0') {
|
||||
append_to_str(asm_text, sizeof(asm_text),
|
||||
str_append_no_realloc(asm_text, sizeof(asm_text),
|
||||
insns[i].mnemonic);
|
||||
append_to_str(asm_text, sizeof(asm_text), " ");
|
||||
str_append_no_realloc(asm_text, sizeof(asm_text), " ");
|
||||
}
|
||||
if (insns[i].op_str[0] != '\0') {
|
||||
append_to_str(asm_text, sizeof(asm_text),
|
||||
str_append_no_realloc(asm_text, sizeof(asm_text),
|
||||
insns[i].op_str);
|
||||
}
|
||||
if (!compare_asm_text(asm_text, expec_data->asm_text,
|
||||
|
@ -79,7 +79,7 @@ TestDetailX86 *test_detail_x86_clone(TestDetailX86 *detail)
|
||||
clone->eflags = detail->eflags ? cs_mem_calloc(sizeof(char *),
|
||||
detail->eflags_count) :
|
||||
NULL;
|
||||
for (size_t i = 0; i < detail->eflags_count; ++i) {
|
||||
for (size_t i = 0; clone->eflags && i < detail->eflags_count; ++i) {
|
||||
clone->eflags[i] =
|
||||
detail->eflags[i] ? strdup(detail->eflags[i]) : NULL;
|
||||
}
|
||||
@ -89,7 +89,7 @@ TestDetailX86 *test_detail_x86_clone(TestDetailX86 *detail)
|
||||
detail->fpu_flags ?
|
||||
cs_mem_calloc(sizeof(char *), detail->fpu_flags_count) :
|
||||
NULL;
|
||||
for (size_t i = 0; i < detail->fpu_flags_count; ++i) {
|
||||
for (size_t i = 0; clone->fpu_flags && i < detail->fpu_flags_count; ++i) {
|
||||
clone->fpu_flags[i] = detail->fpu_flags[i] ?
|
||||
strdup(detail->fpu_flags[i]) :
|
||||
NULL;
|
||||
|
@ -175,13 +175,7 @@ static bool open_cs_handle(UnitTestState *ustate)
|
||||
} else {
|
||||
ustate->arch_bits = 32;
|
||||
}
|
||||
if (err != CS_ERR_OK) {
|
||||
goto option_error;
|
||||
}
|
||||
|
||||
if (err != CS_ERR_OK) {
|
||||
goto option_error;
|
||||
}
|
||||
for (size_t i = 0; i < options_set; ++i) {
|
||||
err = cs_option(ustate->handle, options[i].type,
|
||||
options[i].val);
|
||||
@ -299,6 +293,8 @@ static void eval_test_cases(TestFile **test_files, TestRunStats *stats)
|
||||
// Use private function here, because the API takes only constant tables.
|
||||
int failed_tests = _cmocka_run_group_tests(
|
||||
"All test cases", utest_table, stats->tc_total, NULL, NULL);
|
||||
assert(failed_tests >= 0 && "Faulty return value");
|
||||
|
||||
for (size_t i = 0; i < stats->tc_total; ++i) {
|
||||
UnitTestState *ustate = utest_table[i].initial_state;
|
||||
if (!ustate) {
|
||||
|
@ -401,7 +401,11 @@ unsigned int platform_len(void) {
|
||||
|
||||
// get platform entry encoded n (first byte for input data of OSS fuzz)
|
||||
unsigned int get_platform_entry(uint8_t n) {
|
||||
return n % platform_len();
|
||||
unsigned len = platform_len();
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
return n % len;
|
||||
}
|
||||
|
||||
// get cstoolname from encoded n (first byte for input data of OSS fuzz)
|
||||
|
@ -4957,3 +4957,77 @@ test_cases:
|
||||
expected:
|
||||
insns:
|
||||
- asm_text: "jalrc $t9"
|
||||
|
||||
-
|
||||
input:
|
||||
name: "issue 2471 -- max operands overflow"
|
||||
bytes: [ 0xff, 0x00, 0x08, 0xc0 ]
|
||||
arch: "CS_ARCH_AARCH64"
|
||||
options: [ CS_OPT_DETAIL, CS_OPT_DETAIL_REAL ]
|
||||
address: 0x0
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "zero {za}"
|
||||
is_alias: 1
|
||||
details:
|
||||
aarch64:
|
||||
operands:
|
||||
-
|
||||
type: AARCH64_OP_SME
|
||||
sme:
|
||||
type: AARCH64_SME_OP_TILE
|
||||
tile: za0.d
|
||||
access: CS_AC_READ
|
||||
vas: AARCH64LAYOUT_VL_D
|
||||
-
|
||||
type: AARCH64_OP_SME
|
||||
sme:
|
||||
type: AARCH64_SME_OP_TILE
|
||||
tile: za1.d
|
||||
access: CS_AC_READ
|
||||
vas: AARCH64LAYOUT_VL_D
|
||||
-
|
||||
type: AARCH64_OP_SME
|
||||
sme:
|
||||
type: AARCH64_SME_OP_TILE
|
||||
tile: za2.d
|
||||
access: CS_AC_READ
|
||||
vas: AARCH64LAYOUT_VL_D
|
||||
-
|
||||
type: AARCH64_OP_SME
|
||||
sme:
|
||||
type: AARCH64_SME_OP_TILE
|
||||
tile: za3.d
|
||||
access: CS_AC_READ
|
||||
vas: AARCH64LAYOUT_VL_D
|
||||
-
|
||||
type: AARCH64_OP_SME
|
||||
sme:
|
||||
type: AARCH64_SME_OP_TILE
|
||||
tile: za4.d
|
||||
access: CS_AC_READ
|
||||
vas: AARCH64LAYOUT_VL_D
|
||||
-
|
||||
type: AARCH64_OP_SME
|
||||
sme:
|
||||
type: AARCH64_SME_OP_TILE
|
||||
tile: za5.d
|
||||
access: CS_AC_READ
|
||||
vas: AARCH64LAYOUT_VL_D
|
||||
-
|
||||
type: AARCH64_OP_SME
|
||||
sme:
|
||||
type: AARCH64_SME_OP_TILE
|
||||
tile: za6.d
|
||||
access: CS_AC_READ
|
||||
vas: AARCH64LAYOUT_VL_D
|
||||
-
|
||||
type: AARCH64_OP_SME
|
||||
sme:
|
||||
type: AARCH64_SME_OP_TILE
|
||||
tile: za7.d
|
||||
access: CS_AC_READ
|
||||
vas: AARCH64LAYOUT_VL_D
|
||||
regs_read: [ za0.d, za1.d, za2.d, za3.d, za4.d, za5.d, za6.d, za7.d ]
|
||||
groups: [ HasSME ]
|
||||
|
@ -1,14 +1,12 @@
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
# Old integration tests.
|
||||
if (CAPSTONE_BUILD_LEGACY_TESTS)
|
||||
enable_testing()
|
||||
set(UNIT_TEST_SOURCES sstream.c)
|
||||
enable_testing()
|
||||
set(UNIT_TEST_SOURCES sstream.c utils.c)
|
||||
include_directories(include)
|
||||
|
||||
foreach(TSRC ${UNIT_TEST_SOURCES})
|
||||
string(REGEX REPLACE ".c$" "" TBIN ${TSRC})
|
||||
add_executable(${TBIN} "${TESTS_UNIT_DIR}/${TSRC}")
|
||||
target_link_libraries(${TBIN} PRIVATE capstone)
|
||||
add_test(NAME "unit_${TBIN}" COMMAND ${TBIN})
|
||||
endforeach()
|
||||
endif()
|
||||
foreach(TSRC ${UNIT_TEST_SOURCES})
|
||||
string(REGEX REPLACE ".c$" "" TBIN ${TSRC})
|
||||
add_executable(${TBIN} "${TESTS_UNIT_DIR}/${TSRC}")
|
||||
target_link_libraries(${TBIN} PRIVATE capstone)
|
||||
add_test(NAME "unit_${TBIN}" COMMAND ${TBIN})
|
||||
endforeach()
|
||||
|
44
tests/unit/include/unit_test.h
Normal file
44
tests/unit/include/unit_test.h
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright © 2024 Rot127 <unisono@quyllur.org>
|
||||
// SPDX-License-Identifier: BSD-3
|
||||
|
||||
#define CHECK_OS_EQUAL_RET_FALSE(OS, str) \
|
||||
do { \
|
||||
if (strcmp(OS.buffer, str) != 0) { \
|
||||
printf("OS.buffer != str\n"); \
|
||||
printf("OS.buffer: %s\n", OS.buffer); \
|
||||
printf("str : %s\n", str); \
|
||||
return false; \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#define CHECK_STR_EQUAL_RET_FALSE(a, b) \
|
||||
do { \
|
||||
if (strcmp(a, b) != 0) { \
|
||||
printf("%s != %s\n", a, b); \
|
||||
return false; \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#define CHECK_NULL_RET_FALSE(ptr) \
|
||||
do { \
|
||||
if (ptr != NULL) { \
|
||||
printf(#ptr " is not NULL\n"); \
|
||||
return false; \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#define CHECK_PTR_EQUAL_RET_FALSE(a, b) \
|
||||
do { \
|
||||
if (a != b) { \
|
||||
printf("%p != %p\n", a, b); \
|
||||
return false; \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#define CHECK_INT_EQUAL_RET_FALSE(a, b) \
|
||||
do { \
|
||||
if (a != b) { \
|
||||
printf("%" PRId32 " != %" PRId32 "\n", a, b); \
|
||||
return false; \
|
||||
} \
|
||||
} while (0);
|
@ -1,21 +1,12 @@
|
||||
// Copyright © 2024 Rot127 <unisono@quyllur.org>
|
||||
// SPDX-License-Identifier: BSD-3
|
||||
|
||||
#include "unit_test.h"
|
||||
#include "../SStream.h"
|
||||
#include "../utils.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define CHECK_EQUAL_RET_FALSE(OS, str) \
|
||||
do { \
|
||||
if (strcmp(OS.buffer, str) != 0) { \
|
||||
printf("OS.buffer != str\n"); \
|
||||
printf("OS.buffer: %s\n", OS.buffer); \
|
||||
printf("str : %s\n", str); \
|
||||
return false; \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
static void overflow_SStream_concat0(SStream *OS, bool *returned_in_time)
|
||||
{
|
||||
char buf[SSTREAM_BUF_LEN + 1] = { 0 };
|
||||
@ -74,22 +65,22 @@ static bool test_markup_os()
|
||||
SStream OS = { 0 };
|
||||
SStream_Init(&OS);
|
||||
SStream_concat0(&OS, "0");
|
||||
CHECK_EQUAL_RET_FALSE(OS, "0");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "0");
|
||||
OS.markup_stream = true;
|
||||
printUInt64(&OS, 0);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "00");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "00");
|
||||
markup_OS(&OS, Markup_Immediate);
|
||||
printUInt64(&OS, 0);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "00<imm:0>");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "00<imm:0>");
|
||||
markup_OS(&OS, Markup_Memory);
|
||||
printUInt32(&OS, 0);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "00<imm:0><mem:0>");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "00<imm:0><mem:0>");
|
||||
markup_OS(&OS, Markup_Target);
|
||||
printUInt32(&OS, 0);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "00<imm:0><mem:0><tar:0>");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "00<imm:0><mem:0><tar:0>");
|
||||
markup_OS(&OS, Markup_Register);
|
||||
SStream_concat0(&OS, "r19");
|
||||
CHECK_EQUAL_RET_FALSE(OS, "00<imm:0><mem:0><tar:0><reg:r19>");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "00<imm:0><mem:0><tar:0><reg:r19>");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -100,27 +91,27 @@ bool test_printint8()
|
||||
SStream OS = { 0 };
|
||||
SStream_Init(&OS);
|
||||
printInt8(&OS, HEX_THRESHOLD + 1);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "0xa");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "0xa");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt8(&OS, HEX_THRESHOLD);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "9");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "9");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt8(&OS, -(HEX_THRESHOLD + 1));
|
||||
CHECK_EQUAL_RET_FALSE(OS, "-0xa");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "-0xa");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt8(&OS, -HEX_THRESHOLD);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "-9");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "-9");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt8(&OS, INT8_MAX);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "0x7f");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "0x7f");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt8(&OS, INT8_MIN);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "-0x80");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "-0x80");
|
||||
SStream_Flush(&OS, NULL);
|
||||
return true;
|
||||
}
|
||||
@ -132,27 +123,27 @@ bool test_printint16()
|
||||
SStream OS = { 0 };
|
||||
SStream_Init(&OS);
|
||||
printInt16(&OS, HEX_THRESHOLD + 1);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "0xa");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "0xa");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt16(&OS, HEX_THRESHOLD);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "9");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "9");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt16(&OS, -(HEX_THRESHOLD + 1));
|
||||
CHECK_EQUAL_RET_FALSE(OS, "-0xa");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "-0xa");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt16(&OS, -HEX_THRESHOLD);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "-9");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "-9");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt16(&OS, INT16_MAX);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "0x7fff");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "0x7fff");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt16(&OS, INT16_MIN);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "-0x8000");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "-0x8000");
|
||||
SStream_Flush(&OS, NULL);
|
||||
return true;
|
||||
}
|
||||
@ -164,27 +155,27 @@ bool test_printint32()
|
||||
SStream OS = { 0 };
|
||||
SStream_Init(&OS);
|
||||
printInt32(&OS, HEX_THRESHOLD + 1);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "0xa");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "0xa");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt32(&OS, HEX_THRESHOLD);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "9");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "9");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt32(&OS, -(HEX_THRESHOLD + 1));
|
||||
CHECK_EQUAL_RET_FALSE(OS, "-0xa");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "-0xa");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt32(&OS, -HEX_THRESHOLD);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "-9");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "-9");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt32(&OS, INT32_MAX);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "0x7fffffff");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "0x7fffffff");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt32(&OS, INT32_MIN);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "-0x80000000");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "-0x80000000");
|
||||
SStream_Flush(&OS, NULL);
|
||||
return true;
|
||||
}
|
||||
@ -196,27 +187,27 @@ bool test_printint64()
|
||||
SStream OS = { 0 };
|
||||
SStream_Init(&OS);
|
||||
printInt64(&OS, HEX_THRESHOLD + 1);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "0xa");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "0xa");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt64(&OS, HEX_THRESHOLD);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "9");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "9");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt64(&OS, -(HEX_THRESHOLD + 1));
|
||||
CHECK_EQUAL_RET_FALSE(OS, "-0xa");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "-0xa");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt64(&OS, -HEX_THRESHOLD);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "-9");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "-9");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt64(&OS, INT64_MAX);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "0x7fffffffffffffff");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "0x7fffffffffffffff");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt64(&OS, INT64_MIN);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "-0x8000000000000000");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "-0x8000000000000000");
|
||||
SStream_Flush(&OS, NULL);
|
||||
return true;
|
||||
}
|
||||
@ -228,27 +219,27 @@ bool test_printint32_bang()
|
||||
SStream OS = { 0 };
|
||||
SStream_Init(&OS);
|
||||
printInt32Bang(&OS, HEX_THRESHOLD + 1);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "#0xa");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "#0xa");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt32Bang(&OS, HEX_THRESHOLD);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "#9");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "#9");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt32Bang(&OS, -(HEX_THRESHOLD + 1));
|
||||
CHECK_EQUAL_RET_FALSE(OS, "#-0xa");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "#-0xa");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt32Bang(&OS, -HEX_THRESHOLD);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "#-9");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "#-9");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt32Bang(&OS, INT32_MAX);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "#0x7fffffff");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "#0x7fffffff");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt32Bang(&OS, INT32_MIN);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "#-0x80000000");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "#-0x80000000");
|
||||
SStream_Flush(&OS, NULL);
|
||||
return true;
|
||||
}
|
||||
@ -260,27 +251,27 @@ bool test_printint64_bang()
|
||||
SStream OS = { 0 };
|
||||
SStream_Init(&OS);
|
||||
printInt64Bang(&OS, HEX_THRESHOLD + 1);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "#0xa");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "#0xa");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt64Bang(&OS, HEX_THRESHOLD);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "#9");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "#9");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt64Bang(&OS, -(HEX_THRESHOLD + 1));
|
||||
CHECK_EQUAL_RET_FALSE(OS, "#-0xa");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "#-0xa");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt64Bang(&OS, -HEX_THRESHOLD);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "#-9");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "#-9");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt64Bang(&OS, INT64_MAX);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "#0x7fffffffffffffff");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "#0x7fffffffffffffff");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printInt64Bang(&OS, INT64_MIN);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "#-0x8000000000000000");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "#-0x8000000000000000");
|
||||
SStream_Flush(&OS, NULL);
|
||||
return true;
|
||||
}
|
||||
@ -292,15 +283,15 @@ bool test_printuint32_bang()
|
||||
SStream OS = { 0 };
|
||||
SStream_Init(&OS);
|
||||
printUInt32Bang(&OS, HEX_THRESHOLD + 1);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "#0xa");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "#0xa");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printUInt32Bang(&OS, HEX_THRESHOLD);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "#9");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "#9");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printUInt32Bang(&OS, UINT32_MAX);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "#0xffffffff");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "#0xffffffff");
|
||||
SStream_Flush(&OS, NULL);
|
||||
return true;
|
||||
}
|
||||
@ -312,19 +303,211 @@ bool test_printuint64_bang()
|
||||
SStream OS = { 0 };
|
||||
SStream_Init(&OS);
|
||||
printUInt64Bang(&OS, HEX_THRESHOLD + 1);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "#0xa");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "#0xa");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printUInt64Bang(&OS, HEX_THRESHOLD);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "#9");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "#9");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
printUInt64Bang(&OS, UINT64_MAX);
|
||||
CHECK_EQUAL_RET_FALSE(OS, "#0xffffffffffffffff");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "#0xffffffffffffffff");
|
||||
SStream_Flush(&OS, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_trimls() {
|
||||
printf("Test test_replc\n");
|
||||
|
||||
SStream OS = { 0 };
|
||||
SStream_Init(&OS);
|
||||
SStream_concat0(&OS, "AAA");
|
||||
SStream_trimls(&OS);
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "AAA");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
SStream_concat0(&OS, "\t AAA");
|
||||
SStream_trimls(&OS);
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "AAA");
|
||||
|
||||
// Don't remove middle tabs and spaces
|
||||
SStream_concat0(&OS, "\t AAA");
|
||||
SStream_trimls(&OS);
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "AAA\t AAA");
|
||||
SStream_Flush(&OS, NULL);
|
||||
|
||||
// Test do nothing
|
||||
SStream_trimls(&OS);
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "");
|
||||
|
||||
// Everywhere tabs
|
||||
char cmp_buf[SSTREAM_BUF_LEN] = { 0 };
|
||||
memset(cmp_buf, '\t', sizeof(cmp_buf) - 1);
|
||||
SStream_trimls(&OS);
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "");
|
||||
CHECK_INT_EQUAL_RET_FALSE(OS.index, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_copy_mnem_opstr() {
|
||||
printf("Test test_copy_mnem_opstr\n");
|
||||
|
||||
SStream OS = { 0 };
|
||||
SStream_Init(&OS);
|
||||
SStream_concat0(&OS, "AAA\tBBBB");
|
||||
|
||||
char mnem_1[1] = { 0 };
|
||||
char opstr_1[1] = { 0 };
|
||||
SStream_extract_mnem_opstr(&OS, mnem_1, sizeof(mnem_1), opstr_1, sizeof(opstr_1));
|
||||
CHECK_STR_EQUAL_RET_FALSE(mnem_1, "");
|
||||
CHECK_STR_EQUAL_RET_FALSE(opstr_1, "");
|
||||
|
||||
char mnem_3[3] = { 0 };
|
||||
char opstr_3[3] = { 0 };
|
||||
SStream_extract_mnem_opstr(&OS, mnem_3, sizeof(mnem_3), opstr_3, sizeof(opstr_3));
|
||||
CHECK_STR_EQUAL_RET_FALSE(mnem_3, "AA");
|
||||
CHECK_STR_EQUAL_RET_FALSE(opstr_3, "BB");
|
||||
|
||||
char mnem_4[4] = { 0 };
|
||||
char opstr_4[4] = { 0 };
|
||||
SStream_extract_mnem_opstr(&OS, mnem_4, sizeof(mnem_4), opstr_4, sizeof(opstr_4));
|
||||
CHECK_STR_EQUAL_RET_FALSE(mnem_4, "AAA");
|
||||
CHECK_STR_EQUAL_RET_FALSE(opstr_4, "BBB");
|
||||
|
||||
char mnem_5[5] = { 0 };
|
||||
char opstr_5[5] = { 0 };
|
||||
SStream_extract_mnem_opstr(&OS, mnem_5, sizeof(mnem_5), opstr_5, sizeof(opstr_5));
|
||||
CHECK_STR_EQUAL_RET_FALSE(mnem_5, "AAA");
|
||||
CHECK_STR_EQUAL_RET_FALSE(opstr_5, "BBBB");
|
||||
|
||||
// No mnemonic
|
||||
char mnem_9[9] = { 0 };
|
||||
char opstr_9[9] = { 0 };
|
||||
SStream_Flush(&OS, NULL);
|
||||
SStream_concat0(&OS, " AAA\tBBBB");
|
||||
SStream_extract_mnem_opstr(&OS, mnem_9, sizeof(mnem_9), opstr_9, sizeof(opstr_9));
|
||||
CHECK_STR_EQUAL_RET_FALSE(mnem_9, "");
|
||||
CHECK_STR_EQUAL_RET_FALSE(opstr_9, "AAA\tBBBB");
|
||||
|
||||
// No opstr
|
||||
char mnem_6[6] = { 0 };
|
||||
char opstr_6[6] = { 0 };
|
||||
SStream_Flush(&OS, NULL);
|
||||
SStream_concat0(&OS, "AAA \t");
|
||||
SStream_extract_mnem_opstr(&OS, mnem_6, sizeof(mnem_6), opstr_6, sizeof(opstr_6));
|
||||
CHECK_STR_EQUAL_RET_FALSE(mnem_6, "AAA");
|
||||
CHECK_STR_EQUAL_RET_FALSE(opstr_6, "");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_replc()
|
||||
{
|
||||
printf("Test test_replc\n");
|
||||
|
||||
SStream OS = { 0 };
|
||||
SStream_Init(&OS);
|
||||
char cmp_buf[SSTREAM_BUF_LEN] = { 0 };
|
||||
memset(cmp_buf, 'A', sizeof(cmp_buf) - 1);
|
||||
cmp_buf[100] = 'C';
|
||||
SStream_concat0(&OS, cmp_buf);
|
||||
|
||||
cmp_buf[0] = 'B';
|
||||
const char *next = SStream_replc(&OS, 'A', 'B');
|
||||
CHECK_PTR_EQUAL_RET_FALSE(SStream_rbuf(&OS) + 1, next);
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, cmp_buf);
|
||||
|
||||
cmp_buf[1] = 'B';
|
||||
next = SStream_replc(&OS, 'A', 'B');
|
||||
CHECK_PTR_EQUAL_RET_FALSE(SStream_rbuf(&OS) + 2, next);
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, cmp_buf);
|
||||
|
||||
cmp_buf[100] = 'A'; // Replace the C from before
|
||||
next = SStream_replc(&OS, 'C', 'A');
|
||||
CHECK_PTR_EQUAL_RET_FALSE(SStream_rbuf(&OS) + 101, next);
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, cmp_buf);
|
||||
|
||||
// X doesn't exist
|
||||
next = SStream_replc(&OS, 'X', 'A');
|
||||
CHECK_NULL_RET_FALSE(next);
|
||||
|
||||
// Replacing \0 byte is forbidden.
|
||||
next = SStream_replc(&OS, '\0', 'A');
|
||||
CHECK_NULL_RET_FALSE(next);
|
||||
|
||||
// But replacing any \0 byte is allowed.
|
||||
SStream_Flush(&OS, NULL);
|
||||
next = SStream_replc(&OS, '\0', 'A');
|
||||
CHECK_PTR_EQUAL_RET_FALSE(SStream_rbuf(&OS) + 1, next);
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "A");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool test_replc_str()
|
||||
{
|
||||
printf("Test test_replc_str\n");
|
||||
|
||||
SStream OS = { 0 };
|
||||
SStream_Init(&OS);
|
||||
|
||||
SStream_replc_str(&OS, 'A', "REPLACED");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "");
|
||||
CHECK_INT_EQUAL_RET_FALSE(OS.index, 0);
|
||||
|
||||
SStream_replc_str(&OS, '\0', "REPLACED");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "REPLACED");
|
||||
CHECK_INT_EQUAL_RET_FALSE(OS.index, 8);
|
||||
|
||||
SStream_Flush(&OS, NULL);
|
||||
SStream_concat0(&OS, "\tA--X");
|
||||
SStream_replc_str(&OS, 'A', "REPLACED");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "\tREPLACED--X");
|
||||
CHECK_INT_EQUAL_RET_FALSE(OS.index, 12);
|
||||
SStream_replc_str(&OS, 'X', "REPLACED");
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "\tREPLACED--REPLACED");
|
||||
CHECK_INT_EQUAL_RET_FALSE(OS.index, 19);
|
||||
|
||||
/// Too big strings are ignored.
|
||||
char repl[SSTREAM_BUF_LEN] = { 0 };
|
||||
memset(repl, 'A', sizeof(repl) - 1);
|
||||
SStream_Flush(&OS, NULL);
|
||||
SStream_concat0(&OS, "\tA--");
|
||||
SStream_replc_str(&OS, 'A', repl);
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "\tA--");
|
||||
CHECK_INT_EQUAL_RET_FALSE(OS.index, 4);
|
||||
|
||||
/// Last null byte is not replaced.
|
||||
memset(repl, 'A', sizeof(repl) - 1);
|
||||
SStream_Flush(&OS, NULL);
|
||||
SStream_concat0(&OS, repl);
|
||||
SStream_replc_str(&OS, '\0', repl);
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, repl);
|
||||
CHECK_INT_EQUAL_RET_FALSE(OS.index, 511);
|
||||
|
||||
/// Last char is replaced.
|
||||
memset(repl, 'A', sizeof(repl) - 1);
|
||||
repl[sizeof(repl) - 2] = 'X';
|
||||
SStream_Flush(&OS, NULL);
|
||||
SStream_concat0(&OS, repl);
|
||||
SStream_replc_str(&OS, 'X', "Y");
|
||||
repl[sizeof(repl) - 2] = 'Y';
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, repl);
|
||||
CHECK_INT_EQUAL_RET_FALSE(OS.index, 511);
|
||||
|
||||
// Possible overflow
|
||||
char too_long[SSTREAM_BUF_LEN + 10] = { 0 };
|
||||
memset(too_long, 'A', sizeof(too_long) - 1);
|
||||
SStream_Flush(&OS, NULL);
|
||||
SStream_concat0(&OS, "\tA--");
|
||||
SStream_replc_str(&OS, 'A', too_long);
|
||||
CHECK_OS_EQUAL_RET_FALSE(OS, "\tA--");
|
||||
CHECK_INT_EQUAL_RET_FALSE(OS.index, 4);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
bool result = true;
|
||||
@ -338,6 +521,10 @@ int main()
|
||||
result &= test_printint64_bang();
|
||||
result &= test_printuint32_bang();
|
||||
result &= test_printuint64_bang();
|
||||
result &= test_replc();
|
||||
result &= test_replc_str();
|
||||
result &= test_copy_mnem_opstr();
|
||||
result &= test_trimls();
|
||||
if (result) {
|
||||
printf("All tests passed.\n");
|
||||
} else {
|
||||
|
76
tests/unit/utils.c
Normal file
76
tests/unit/utils.c
Normal file
@ -0,0 +1,76 @@
|
||||
// Copyright © 2024 Rot127 <unisono@quyllur.org>
|
||||
// SPDX-License-Identifier: BSD-3
|
||||
|
||||
#include "unit_test.h"
|
||||
#include "../utils.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static bool test_str_append_no_realloc()
|
||||
{
|
||||
printf("Test test_str_append_no_realloc\n");
|
||||
|
||||
char str_a[] = "AAAA\0\0\0\0\0";
|
||||
char str_b[] = "BBBB";
|
||||
char str_c[] = "\0\0\0\0\0";
|
||||
|
||||
CHECK_NULL_RET_FALSE(str_append(NULL, NULL));
|
||||
CHECK_NULL_RET_FALSE(str_append(str_a, NULL));
|
||||
CHECK_NULL_RET_FALSE(str_append(NULL, str_b));
|
||||
|
||||
str_append_no_realloc(str_a, sizeof(str_a), str_c);
|
||||
CHECK_STR_EQUAL_RET_FALSE(str_a, "AAAA");
|
||||
|
||||
str_append_no_realloc(str_a, sizeof(str_a), str_b);
|
||||
CHECK_STR_EQUAL_RET_FALSE(str_a, "AAAABBBB");
|
||||
|
||||
str_append_no_realloc(str_c, sizeof(str_c), str_b);
|
||||
CHECK_STR_EQUAL_RET_FALSE(str_c, "BBBB");
|
||||
|
||||
str_append_no_realloc(str_b, sizeof(str_b), str_c);
|
||||
CHECK_STR_EQUAL_RET_FALSE(str_b, "BBBB");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool test_str_append()
|
||||
{
|
||||
printf("Test test_str_append\n");
|
||||
char *str_a = NULL;
|
||||
char *str_b = NULL;
|
||||
CHECK_NULL_RET_FALSE(str_append(str_a, str_b));
|
||||
|
||||
str_a = calloc(5, sizeof(char));
|
||||
memcpy(str_a, "AAAA", 5);
|
||||
CHECK_NULL_RET_FALSE(str_append(str_a, str_b));
|
||||
|
||||
str_b = calloc(5, sizeof(char));
|
||||
str_a = str_append(str_a, str_b);
|
||||
CHECK_STR_EQUAL_RET_FALSE(str_a, "AAAA");
|
||||
|
||||
memcpy(str_b, "BBBB", 5);
|
||||
str_a = str_append(str_a, str_b);
|
||||
CHECK_STR_EQUAL_RET_FALSE(str_a, "AAAABBBB");
|
||||
|
||||
memset(str_a, 0, strlen(str_a) + 1);
|
||||
str_a = str_append(str_a, str_b);
|
||||
CHECK_STR_EQUAL_RET_FALSE(str_a, "BBBB");
|
||||
free(str_a);
|
||||
free(str_b);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
bool result = true;
|
||||
result &= test_str_append();
|
||||
result &= test_str_append_no_realloc();
|
||||
|
||||
if (result) {
|
||||
printf("All tests passed.\n");
|
||||
} else {
|
||||
printf("Some tests failed.\n");
|
||||
}
|
||||
return result ? 0 : -1;
|
||||
}
|
23
utils.c
23
utils.c
@ -181,36 +181,37 @@ void append_to_str_lower(char *str, size_t str_size, const char *src) {
|
||||
str[i] = '\0';
|
||||
}
|
||||
|
||||
/// @brief Appends the string @p src to the string @p str. @p src is put to lower case.
|
||||
/// @param str The string to append to.
|
||||
/// @param str_buf_size Size of buffer @p str.
|
||||
/// @brief Appends the string @p src to the string @p dest.
|
||||
/// @p dest is can be a stack allocated buffer.
|
||||
///
|
||||
/// @param dest The string to append to.
|
||||
/// @param dest_buf_size Size of buffer @p str.
|
||||
/// @param src The string to append.
|
||||
/// Does nothing if any of the given strings is NULL.
|
||||
void append_to_str(char *str, size_t str_buf_size, const char *src) {
|
||||
if (!str || !src) {
|
||||
void str_append_no_realloc(char *dest, size_t dest_buf_size, const char *src) {
|
||||
if (!dest || !src) {
|
||||
return;
|
||||
}
|
||||
if (strlen(str) + strlen(src) + 1 > str_buf_size) {
|
||||
assert("str_size does not match actual string length." && 0);
|
||||
if (strlen(dest) + strlen(src) + 1 > dest_buf_size) {
|
||||
printf("str_size does not match actual string length.\n");
|
||||
return;
|
||||
}
|
||||
strncat(str, src, str_buf_size);
|
||||
strncat(dest, src, dest_buf_size - strlen(dest));
|
||||
}
|
||||
|
||||
|
||||
/// Allocates memory of strlen(str_a) + strlen(str_b) + 1 chars
|
||||
/// and copies all strings into it as str_a + str_b
|
||||
/// str_a is passed to realloc and should not be used afterwards.
|
||||
/// Returns the result.
|
||||
/// Returns the concatenated string.
|
||||
/// Returns NULL in case of failure.
|
||||
char *str_append(char *str_a, const char *str_b) {
|
||||
if (!str_a || !str_b) {
|
||||
return NULL;
|
||||
}
|
||||
assert(str_a && str_b);
|
||||
size_t asize = strlen(str_a) + strlen(str_b) + 1;
|
||||
str_a = realloc(str_a, asize);
|
||||
strncat(str_a, str_b, asize);
|
||||
strncat(str_a, str_b, asize - strlen(str_a));
|
||||
return str_a;
|
||||
}
|
||||
|
||||
|
2
utils.h
2
utils.h
@ -44,7 +44,7 @@ uint64_t readBytes48(MCInst *MI, const uint8_t *Bytes);
|
||||
uint64_t readBytes64(MCInst *MI, const uint8_t *Bytes);
|
||||
|
||||
void append_to_str_lower(char *str, size_t str_size, const char *src);
|
||||
void append_to_str(char *str, size_t str_buf_size, const char *src);
|
||||
void str_append_no_realloc(char *str, size_t str_buf_size, const char *src);
|
||||
char *str_append(char *str_a, const char *str_b);
|
||||
static inline bool strings_match(const char *str0, const char *str1) { return strcmp(str0, str1) == 0; }
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user