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:
Rot127 2024-09-18 13:19:42 +00:00 committed by GitHub
parent af1ed2fb3d
commit 3a2cd3c331
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
70 changed files with 843 additions and 405 deletions

View File

@ -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.

View File

@ -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;

View File

@ -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.

View File

@ -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);

View File

@ -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);
}

View File

@ -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)

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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.

View File

@ -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(">"));
}

View File

@ -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);

View File

@ -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!"); */ \

View File

@ -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");

View File

@ -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;

View File

@ -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;

View File

@ -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) {

View File

@ -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);

View File

@ -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!");

View File

@ -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);\

View File

@ -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) {

View File

@ -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)
}

View File

@ -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);

View File

@ -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;

View File

@ -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));
}
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -277,8 +277,8 @@ static void printDisp24Imm(MCInst *MI, int OpNum, SStream *O)
case TRICORE_JA_b:
case TRICORE_JLA_b:
// = {disp24[23:20], 7b0000000, disp24[19:0], 1b0};
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:

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
View File

@ -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)

View File

@ -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);

View File

@ -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);

View File

@ -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)" : "");

View File

@ -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';

View File

@ -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) {

View File

@ -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);
}
}

View File

@ -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.

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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;

View File

@ -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

View File

@ -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,

View File

@ -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;

View File

@ -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) {

View File

@ -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)

View File

@ -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 ]

View File

@ -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()

View 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);

View File

@ -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
View 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
View File

@ -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;
}

View File

@ -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; }