Repository: capstone-engine/capstone (C)

Issue:
CS_OPT_UNSIGNED ignored in AArch64
<!-- This template is meant for GENERAL bug reports.
For bugs regarding incorrect disassembly,
please use the "Bug report - Incorrect disassembly" template.

Please be as descriptive as possible
-->

### Work environment

<!-- Filling this table is mandatory -->

| Questions                                | Answers
|------------------------------------------|--------------------
| System Capstone runs on OS/arch/bits     | Debianx86
| Capstone module affected                 | aarch64 etc.
| Source of Capstone                       | `git clone`
| Version/git commit                       | efc0ba4477e5140955e249812b1565833320f34c

<!-- OTHER BUGS -->

### Expected behavior

CS_OPT_UNSIGNED should work. Grepping code, only x86 and m680x code check the imm_unsigned flag.

### Actual behavior

```shell
# cstool of `next` branch
$ ./cstool -u -d aarch64 20f05ff8
 0  20 f0 5f f8  ldur   x0, [x1, #-1]
        ID: 710 (ldur)
        op_count: 2
                operands[0].type: REG = x0
                operands[0].access: WRITE
                operands[1].type: MEM
                        operands[1].mem.base: REG = x1
                        operands[1].mem.disp: 0xffffffff
                operands[1].access: READ
        Registers read: x1
        Registers modified: x0
# cstool v4.0.2
$ cstool -u -d  arm64 20f05ff8
 0  20 f0 5f f8  ldur   x0, [x1, #0xffffffffffffffff]
        ID: 174 (ldur)
        op_count: 2
                operands[0].type: REG = x0
                operands[0].access: WRITE
                operands[1].type: MEM
                        operands[1].mem.base: REG = x1
                        operands[1].mem.disp: 0xffffffff
                operands[1].access: READ
        Registers read: x1
        Registers modified: x0
$ cstool -d  arm64 20f05ff8
 0  20 f0 5f f8  ldur   x0, [x1, #-1]
        ID: 174 (ldur)
        op_count: 2
                operands[0].type: REG = x0
                operands[0].access: WRITE
                operands[1].type: MEM
                        operands[1].mem.base: REG = x1
                        operands[1].mem.disp: 0xffffffff
                operands[1].access: READ
        Registers read: x1
        Registers modified: x0
```

### Steps to reproduce the behavior

- Shown above

<!-- ADDITIONAL CONTEXT -->

### Additional Logs, screenshots, source code,  configuration dump, ...

Drag and drop zip archives containing the Additional info here, don't use external services or link.
Screenshots can be directly dropped here.




Fix (patch):
diff --git a/SStream.c b/SStream.c
index b18cd4715e..2a090465fc 100644
--- a/SStream.c
+++ b/SStream.c
@@ -26,6 +26,13 @@ void SStream_Init(SStream *ss)
 	ss->is_closed = false;
 	ss->markup_stream = false;
 	ss->prefixed_by_markup = false;
+	ss->unsigned_num = false;
+}
+
+void SStream_opt_unum(SStream *ss, bool print_unsigned_numbers)
+{
+	assert(ss);
+	ss->unsigned_num = print_unsigned_numbers;
 }
 
 /// Returns the a pointer to the internal string buffer of the stream.
@@ -224,6 +231,10 @@ void SStream_concat(SStream *ss, const char *fmt, ...)
 void printInt64Bang(SStream *ss, int64_t val)
 {
 	assert(ss);
+	if (ss->unsigned_num) {
+		printUInt64Bang(ss, val);
+		return;
+	}
 	SSTREAM_RETURN_IF_CLOSED(ss);
 	SStream_concat1(ss, '#');
 	printInt64(ss, val);
@@ -241,6 +252,10 @@ void printUInt64Bang(SStream *ss, uint64_t val)
 void printInt64(SStream *ss, int64_t val)
 {
 	assert(ss);
+	if (ss->unsigned_num) {
+		printUInt64(ss, val);
+		return;
+	}
 	SSTREAM_RETURN_IF_CLOSED(ss);
 	if (val >= 0) {
 		if (val > HEX_THRESHOLD)
@@ -286,14 +301,40 @@ void printInt32BangDec(SStream *ss, int32_t val)
 void printInt32Bang(SStream *ss, int32_t val)
 {
 	assert(ss);
+	if (ss->unsigned_num) {
+		printUInt32Bang(ss, val);
+		return;
+	}
 	SSTREAM_RETURN_IF_CLOSED(ss);
 	SStream_concat1(ss, '#');
 	printInt32(ss, val);
 }
 
+void printUInt8(SStream *ss, uint8_t val)
+{
+	assert(ss);
+	if (val > HEX_THRESHOLD)
+		SStream_concat(ss, "0x%"PRIx8, val);
+	else
+		SStream_concat(ss, "%"PRIu8, val);
+}
+
+void printUInt16(SStream *ss, uint16_t val)
+{
+	assert(ss);
+	if (val > HEX_THRESHOLD)
+		SStream_concat(ss, "0x%"PRIx16, val);
+	else
+		SStream_concat(ss, "%"PRIu16, val);
+}
+
 void printInt8(SStream *ss, int8_t val)
 {
 	assert(ss);
+	if (ss->unsigned_num) {
+		printUInt8(ss, val);
+		return;
+	}
 	SSTREAM_RETURN_IF_CLOSED(ss);
 	if (val >= 0) {
 		if (val > HEX_THRESHOLD)
@@ -314,6 +355,10 @@ void printInt8(SStream *ss, int8_t val)
 void printInt16(SStream *ss, int16_t val)
 {
 	assert(ss);
+	if (ss->unsigned_num) {
+		printUInt16(ss, val);
+		return;
+	}
 	SSTREAM_RETURN_IF_CLOSED(ss);
 	if (val >= 0) {
 		if (val > HEX_THRESHOLD)
@@ -334,6 +379,10 @@ void printInt16(SStream *ss, int16_t val)
 void printInt16HexOffset(SStream *ss, int16_t val)
 {
 	assert(ss);
+	if (ss->unsigned_num) {
+		printUInt16(ss, val);
+		return;
+	}
 	SSTREAM_RETURN_IF_CLOSED(ss);
 	if (val >= 0) {
 		SStream_concat(ss, "+0x%" PRIx16, val);
@@ -350,6 +399,10 @@ void printInt16HexOffset(SStream *ss, int16_t val)
 void printInt32(SStream *ss, int32_t val)
 {
 	assert(ss);
+	if (ss->unsigned_num) {
+		printUInt32(ss, val);
+		return;
+	}
 	SSTREAM_RETURN_IF_CLOSED(ss);
 	if (val >= 0) {
 		if (val > HEX_THRESHOLD)
@@ -371,6 +424,10 @@ void printInt32(SStream *ss, int32_t val)
 void printInt32HexOffset(SStream *ss, int32_t val)
 {
 	assert(ss);
+	if (ss->unsigned_num) {
+		printUInt32(ss, val);
+		return;
+	}
 	SSTREAM_RETURN_IF_CLOSED(ss);
 	if (val >= 0) {
 		SStream_concat(ss, "+0x%" PRIx32, val);
diff --git a/SStream.h b/SStream.h
index 5ed98f82bc..614e42f135 100644
--- a/SStream.h
+++ b/SStream.h
@@ -22,6 +22,7 @@ typedef struct SStream {
 	bool is_closed;
 	bool markup_stream; ///< If true, markups to the stream are allowed.
 	bool prefixed_by_markup; ///< Set after the stream wrote a markup for an operand.
+	bool unsigned_num; ///< Print all numbers as unsigned. Set with CS_OPT_UNSIGNED.
 } SStream;
 
 #define SSTREAM_OVERFLOW_CHECK(OS, len) \
@@ -39,6 +40,7 @@ do { \
 } while(0)
 
 void SStream_Init(SStream *ss);
+void SStream_opt_unum(SStream *ss, bool print_unsigned_numbers);
 
 const char *SStream_replc(const SStream *ss, char elem, char repl);
 
@@ -81,6 +83,8 @@ void printInt32HexOffset(SStream *ss, int32_t val);
 
 void printUInt32Bang(SStream *O, uint32_t val);
 
+void printUInt8(SStream *ss, uint8_t val);
+void printUInt16(SStream *ss, uint16_t val);
 void printUInt32(SStream *O, uint32_t val);
 
 // print number in decimal mode
diff --git a/cs.c b/cs.c
index b5c055e580..217d155cbc 100644
--- a/cs.c
+++ b/cs.c
@@ -1289,6 +1289,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);
 
+			SStream_opt_unum(&ss, handle->imm_unsigned);
 			handle->printer(&mci, &ss, handle->printer_info);
 			fill_insn(handle, insn_cache, &ss, &mci, handle->post_printer, buffer);
 
@@ -1494,6 +1495,7 @@ bool CAPSTONE_API cs_disasm_iter(csh ud, const uint8_t **code, size_t *size,
 		// map internal instruction opcode to public insn ID
 		handle->insn_id(handle, insn, mci.Opcode);
 
+		SStream_opt_unum(&ss, handle->imm_unsigned);
 		handle->printer(&mci, &ss, handle->printer_info);
 
 		fill_insn(handle, insn, &ss, &mci, handle->post_printer, *code);