static int _append_imm(char *arg, uint32_t imm) { const char *start = arg; if(imm > 0x1000) { *arg++ = '0'; *arg++ = 'x'; arg += _utoa(imm, arg, 16); } else { arg += _utoa(imm, arg, 10); } return arg - start; }
static void _fmtp(struct fmtctx *ctx, char c, va_list *va) { void *p = va_arg(*va, void *); (void)c; ctx->state |= ST_ZEROPAD; PACKWID(ctx, sizeof(void*) * 2); _utoa(ctx, 16, (unsigned long)p); }
static void _fmtd(struct fmtctx *ctx, char c, va_list *va) { int n = va_arg(*va, int); (void)c; if (n < 0) { ctx->state |= ST_NEGATIVE; n = -n; } _utoa(ctx, 10, n); }
char *itoa (int value, char *str, int base) { char *ptr = str; if (base == 10 && value < 0) { *(str++) = '-'; value = -value; } _utoa (value, str, base, _utoa_digits); return ptr; }
/* * See header for comments */ void itoae(uint8_t *p_buf, int value, int dpp, int min_len, uint8_t fill_char) { //-- if the value is negative, put the minus sign at the beginning, // and make the value positive if(value < 0) { *p_buf++ = '-'; value = -value; } //-- perform "regular" itoa call _utoa(p_buf, value, 10); size_t len = strlen(p_buf); //-- if we need to add leading zeros for decimal point, do it len = _add_leading(p_buf, len, (dpp + 1), '0'); //-- if we need to fill chars in the beginning, do it len = _add_leading(p_buf, len, min_len, fill_char); //-- if we need to put decimal point, do this if (dpp > 0){ int i; for (i = 0; i < (dpp + 1/*null-terminate*/); i++){ p_buf[len - i + 1] = p_buf[len - i]; } p_buf[len - dpp] = '.'; //-- since we've added a dot, length has just increased by 1 len += 1; //-- put zeros around dot if necessary for (i = len - dpp - 1 - 1; i < len; i++){ if (p_buf[i] == fill_char){ p_buf[i] = '0'; } else if (p_buf[i] != '.'){ break; } } } }
static void _fmtu(struct fmtctx *ctx, char c, va_list *va) { unsigned int n = va_arg(*va, unsigned int); _utoa(ctx, c == 'u' ? 10 : (c == 'o' ? 8 : 16), n); }
int darm_str(const darm_t *d, darm_str_t *str) { if(d->instr == I_INVLD || d->instr >= ARRAYSIZE(darm_mnemonics)) { return -1; } // the format string index uint32_t idx = 0; // the offset in the format string uint32_t off = 0; // argument index uint32_t arg = 0; // pointers to the arguments char *args[] = { str->arg[0], str->arg[1], str->arg[2], str->arg[3], str->arg[4], str->arg[5], }; // ptr to the output mnemonic char *mnemonic = str->mnemonic; APPEND(mnemonic, darm_mnemonic_name(d->instr)); char *shift = str->shift; const char **ptrs = armv7_format_strings[d->instr]; if(ptrs[0] == NULL) return -1; for (char ch; (ch = ptrs[idx][off]) != 0; off++) { switch (ch) { case 's': if(d->S == B_SET) { *mnemonic++ = 'S'; } continue; case 'c': APPEND(mnemonic, darm_condition_name(d->cond, 1)); continue; case 'd': if(d->Rd == R_INVLD) break; APPEND(args[arg], darm_register_name(d->Rd)); arg++; continue; case 'n': if(d->Rn == R_INVLD) break; APPEND(args[arg], darm_register_name(d->Rn)); arg++; continue; case 'm': if(d->Rm == R_INVLD) break; APPEND(args[arg], darm_register_name(d->Rm)); arg++; continue; case 'a': if(d->Ra == R_INVLD) break; APPEND(args[arg], darm_register_name(d->Ra)); arg++; continue; case 't': if(d->Rt == R_INVLD) break; APPEND(args[arg], darm_register_name(d->Rt)); arg++; continue; case '2': // first check if Rt2 is actually set if(d->Rt2 != R_INVLD) { APPEND(args[arg], darm_register_name(d->Rt2)); arg++; continue; } // for some instructions, Rt2 = Rt + 1 else if(d->Rt != R_INVLD) { APPEND(args[arg], darm_register_name(d->Rt + 1)); arg++; continue; } break; case 'h': if(d->RdHi == R_INVLD) break; APPEND(args[arg], darm_register_name(d->RdHi)); arg++; continue; case 'l': if(d->RdLo == R_INVLD) break; APPEND(args[arg], darm_register_name(d->RdLo)); arg++; continue; case 'i': // check if an immediate has been set if(d->I != B_SET) break; *args[arg]++ = '#'; args[arg] += _append_imm(args[arg], d->imm); arg++; continue; case 'S': // is there even a shift? if(d->shift_type == S_INVLD) continue; if(d->P == B_SET) { // we're still inside the memory address shift = args[arg] - 1; *shift++ = ','; *shift++ = ' '; } if(d->Rs == R_INVLD) { const char *type; uint32_t imm; if(darm_immshift_decode(d, &type, &imm) == 0) { switch (d->instr) { case I_LSL: case I_LSR: case I_ASR: case I_ROR: case I_RRX: break; default: APPEND(shift, type); *shift++ = ' '; } *shift++ = '#'; shift += _utoa(imm, shift, 10); } else if(d->P == B_SET) { // we're still in the memory address, but there was // no shift, so we have to revert the shift pointer so // it will write a closing bracket again shift -= 2; } } else { APPEND(shift, darm_shift_type_name(d->shift_type)); *shift++ = ' '; APPEND(shift, darm_register_name(d->Rs)); } if(d->P == B_SET) { // close the memory address *shift++ = ']'; // reset shift args[arg] = shift; shift = str->shift; } continue; case '!': if(d->W == B_SET) { *args[arg-1]++ = '!'; } continue; case 'e': args[arg] += _utoa(d->E, args[arg], 10); continue; case 'x': if(d->M == B_SET) { *mnemonic++ = 'x'; } continue; case 'X': // if the flags are not set, then this instruction doesn't take // the (B|T)(B|T) postfix if(d->N == B_INVLD || d->M == B_INVLD) break; *mnemonic++ = d->N == B_SET ? 'T' : 'B'; *mnemonic++ = d->M == B_SET ? 'T' : 'B'; continue; case 'R': if(d->R == B_SET) { *mnemonic++ = 'R'; } continue; case 'T': APPEND(mnemonic, d->T == B_SET ? "TB" : "BT"); continue; case 'r': if(d->reglist != 0) { args[arg] += darm_reglist(d->reglist, args[arg]); } else { *args[arg]++ = '{'; APPEND(args[arg], darm_register_name(d->Rt)); *args[arg]++ = '}'; } continue; case 'L': *args[arg]++ = '#'; args[arg] += _utoa(d->lsb, args[arg], 10); arg++; continue; case 'w': *args[arg]++ = '#'; args[arg] += _utoa(d->width, args[arg], 10); arg++; continue; case 'o': *args[arg]++ = '#'; args[arg] += _utoa(d->option, args[arg], 10); arg++; continue; case 'B': *args[arg]++ = '['; APPEND(args[arg], darm_register_name(d->Rn)); // if post-indexed or the index is not even set, then we close // the memory address if(d->P != B_SET) { *args[arg++]++ = ']'; } else { *args[arg]++ = ','; *args[arg]++ = ' '; } continue; case 'O': // if the Rm operand is set, then this is about the Rm operand, // otherwise it's about the immediate if(d->Rm != R_INVLD) { // negative offset if(d->U == B_UNSET) { *args[arg]++ = '-'; } APPEND(args[arg], darm_register_name(d->Rm)); // if post-indexed this was a stand-alone operator one if(d->P == B_UNSET) { arg++; } } // if there's an immediate, append it else if(d->imm != 0) { // negative offset? APPEND(args[arg], d->U == B_UNSET ? "#-" : "#"); args[arg] += _append_imm(args[arg], d->imm); } else { // there's no immediate, so we have to remove the ", " which // was introduced by the base register of the memory address args[arg] -= 2; } // if pre-indexed, close the memory address, but don't increase // arg so we can alter it in the shift handler if(d->P == B_SET) { *args[arg]++ = ']'; // if pre-indexed and write-back, then add an exclamation mark if(d->W == B_SET) { *args[arg]++ = '!'; } } continue; case 'b': // BLX first checks for branch and only then for the conditional // version which takes the Rm as operand, so let's see if the // branch stuff has been initialized yet if(d->instr == I_BLX && d->H == B_INVLD) break; // check whether the immediate is negative int32_t imm = d->imm; if(imm < 0 && imm >= -0x1000) { APPEND(args[arg], "#+-"); imm = -imm; } else if(d->U == B_UNSET) { APPEND(args[arg], "#+-"); } else { APPEND(args[arg], "#+"); } args[arg] += _append_imm(args[arg], imm); continue; case 'M': *args[arg]++ = '['; APPEND(args[arg], darm_register_name(d->Rn)); // if the Rm operand is defined, then we use that optionally with // a shift, otherwise there might be an immediate value as offset if(d->Rm != R_INVLD) { APPEND(args[arg], ", "); APPEND(args[arg], darm_register_name(d->Rm)); const char *type; uint32_t imm; if(darm_immshift_decode(d, &type, &imm) == 0) { APPEND(args[arg], ", "); APPEND(args[arg], type); APPEND(args[arg], " #"); args[arg] += _utoa(imm, args[arg], 10); } } else if(d->imm != 0) { APPEND(args[arg], ", "); // negative offset? APPEND(args[arg], d->U == B_UNSET ? "#-" : "#"); args[arg] += _append_imm(args[arg], d->imm); } *args[arg]++ = ']'; // if index is true and write-back is true, then we add an // exclamation mark if(d->P == B_SET && d->W == B_SET) { *args[arg]++ = '!'; } continue; case 'A': if(d->rotate != 0) { APPEND(args[arg], "ROR #"); args[arg] += _utoa(d->rotate, args[arg], 10); } continue; case 'C': args[arg] += _utoa(d->coproc, args[arg], 10); arg++; continue; case 'p': args[arg] += _utoa(d->opc1, args[arg], 10); arg++; continue; case 'P': args[arg] += _utoa(d->opc2, args[arg], 10); arg++; continue; case 'N': APPEND(args[arg], "cr"); args[arg] += _utoa(d->CRn, args[arg], 10); arg++; continue; case 'J': APPEND(args[arg], "cr"); args[arg] += _utoa(d->CRm, args[arg], 10); arg++; continue; case 'I': APPEND(args[arg], "cr"); args[arg] += _utoa(d->CRd, args[arg], 10); arg++; continue; default: return -1; } if(ptrs[++idx] == NULL || idx == 3) return -1; off--; } *mnemonic = *shift = 0; *args[0] = *args[1] = *args[2] = *args[3] = *args[4] = *args[5] = 0; char *instr = str->total; APPEND(instr, str->mnemonic); for (int i = 0; i < 6 && args[i] != str->arg[i]; i++) { if(i != 0) *instr++ = ','; *instr++ = ' '; APPEND(instr, str->arg[i]); } if(shift != str->shift) { *instr++ = ','; *instr++ = ' '; APPEND(instr, str->shift); } *instr = 0; return 0; }