ROSE  0.9.9.109
unparseArmAsm.C
1 #include "sage3basic.h"
2 #include "stringify.h"
3 #include "AsmUnparser_compat.h"
4 #include "Registers.h"
5 #include "Diagnostics.h"
6 
7 using namespace Rose;
8 using namespace Diagnostics;
9 using namespace BinaryAnalysis;
10 
11 static std::string unparseArmRegister(SgAsmRegisterReferenceExpression *reg, const RegisterDictionary *registers) {
12  RegisterDescriptor rdesc = reg->get_descriptor();
13  if (!registers)
15 
16  std::string name = registers->lookup(rdesc);
17  if (name.empty()) {
18  SgAsmInstruction *insn = SageInterface::getEnclosingNode<SgAsmInstruction>(reg);
19  name = AsmUnparser::invalid_register(insn, rdesc, registers);
20  }
21 
22  if (SgAsmDirectRegisterExpression *dre = isSgAsmDirectRegisterExpression(reg)) {
23  /* Add mask letters to program status registers */
24  if (rdesc.get_major()==arm_regclass_psr && dre->get_psr_mask()!=0) {
25  name += "_";
26  if (dre->get_psr_mask() & 1) name += "c";
27  if (dre->get_psr_mask() & 2) name += "x";
28  if (dre->get_psr_mask() & 4) name += "s";
29  if (dre->get_psr_mask() & 8) name += "f";
30  }
31  }
32 
33  return name;
34 }
35 
36 static std::string unparseArmCondition(ArmInstructionCondition cond) { // Unparse as used for mnemonics
37 #ifndef _MSC_VER
38  std::string retval = stringifyArmInstructionCondition(cond, "arm_cond_");
39 #else
40  ROSE_ASSERT(false);
41  std::string retval ="";
42 #endif
43 
44  ASSERT_require(retval[0]!='(');
45  return retval;
46 }
47 
48 static std::string unparseArmSign(ArmSignForExpressionUnparsing sign) {
49  switch (sign) {
50  case arm_sign_none: return "";
51  case arm_sign_plus: return "+";
52  case arm_sign_minus: return "-";
53  default: {
54  ASSERT_not_reachable("invalid ARM sign for expression unparsing: " + stringifyArmSignForExpressionUnparsing(sign));
55  // DQ (11/28/2009): MSVC warns about a path that does not have a return stmt.
56  return "error in unparseArmSign";
57  }
58  }
59 }
60 
61 /* Helper function for unparseArmExpression(SgAsmExpression*)
62  *
63  * If this function is called for an EXPR node that cannot appear at the top of an ARM instruction operand tree then the node
64  * might create two strings: the primary expression return value and an additional string returned through the SUFFIX
65  * argument. What to do with the additional string depends on layers higher up in the call stack.
66  *
67  * The sign will be prepended to the result if EXPR is a value expression of some sort. */
68 static std::string unparseArmExpression(SgAsmExpression* expr, const AsmUnparser::LabelMap *labels,
69  const RegisterDictionary *registers,
70  ArmSignForExpressionUnparsing sign, std::string *suffix=NULL)
71 {
72  std::string result, extra;
73  if (!isSgAsmValueExpression(expr)) {
74  result += unparseArmSign(sign);
75  }
76  switch (expr->variantT()) {
77  case V_SgAsmBinaryMultiply:
78  ASSERT_require(isSgAsmIntegerValueExpression(isSgAsmBinaryExpression(expr)->get_rhs()));
79  result = unparseArmExpression(isSgAsmBinaryExpression(expr)->get_lhs(), labels, registers, arm_sign_none) + "*" +
80  StringUtility::numberToString(isSgAsmIntegerValueExpression(isSgAsmBinaryExpression(expr)->get_rhs()));
81  break;
82  case V_SgAsmBinaryLsl:
83  result = unparseArmExpression(isSgAsmBinaryExpression(expr)->get_lhs(), labels, registers, arm_sign_none) + ", lsl " +
84  unparseArmExpression(isSgAsmBinaryExpression(expr)->get_rhs(), labels, registers, arm_sign_none);
85  break;
86  case V_SgAsmBinaryLsr:
87  result = unparseArmExpression(isSgAsmBinaryExpression(expr)->get_lhs(), labels, registers, arm_sign_none) + ", lsr " +
88  unparseArmExpression(isSgAsmBinaryExpression(expr)->get_rhs(), labels, registers, arm_sign_none);
89  break;
90  case V_SgAsmBinaryAsr:
91  result = unparseArmExpression(isSgAsmBinaryExpression(expr)->get_lhs(), labels, registers, arm_sign_none) + ", asr " +
92  unparseArmExpression(isSgAsmBinaryExpression(expr)->get_rhs(), labels, registers, arm_sign_none);
93  break;
94  case V_SgAsmBinaryRor:
95  result = unparseArmExpression(isSgAsmBinaryExpression(expr)->get_lhs(), labels, registers, arm_sign_none) + ", ror " +
96  unparseArmExpression(isSgAsmBinaryExpression(expr)->get_rhs(), labels, registers, arm_sign_none);
97  break;
98  case V_SgAsmUnaryRrx:
99  result = unparseArmExpression(isSgAsmUnaryExpression(expr)->get_operand(), labels, registers, arm_sign_none) +
100  ", rrx";
101  break;
102  case V_SgAsmUnaryArmSpecialRegisterList:
103  result += unparseArmExpression(isSgAsmUnaryExpression(expr)->get_operand(), labels, registers, arm_sign_none) + "^";
104  break;
105  case V_SgAsmExprListExp: {
106  SgAsmExprListExp* el = isSgAsmExprListExp(expr);
107  const std::vector<SgAsmExpression*>& exprs = el->get_expressions();
108  result += "{";
109  for (size_t i = 0; i < exprs.size(); ++i) {
110  if (i != 0) result += ", ";
111  result += unparseArmExpression(exprs[i], labels, registers, arm_sign_none);
112  }
113  result += "}";
114  break;
115  }
116 
117 
118  case V_SgAsmBinaryAdd: {
119  /* This node cannot appear at the top of an ARM instruction operand tree */
120  SgAsmBinaryExpression *e = isSgAsmBinaryExpression(expr);
121  result += unparseArmExpression(e->get_lhs(), labels, registers, arm_sign_none) + ", " +
122  unparseArmExpression(e->get_rhs(), labels, registers, arm_sign_plus);
123  break;
124  }
125 
126  case V_SgAsmBinarySubtract: {
127  /* This node cannot appear at the top of an ARM instruction operand tree */
128  SgAsmBinaryExpression *e = isSgAsmBinaryExpression(expr);
129  result += unparseArmExpression(e->get_lhs(), labels, registers, arm_sign_none) + ", " +
130  unparseArmExpression(e->get_rhs(), labels, registers, arm_sign_minus);
131  break;
132  }
133 
134  case V_SgAsmBinaryAddPreupdate: {
135  /* This node cannot appear at the top of an ARM instruction operand tree */
136  SgAsmBinaryExpression *e = isSgAsmBinaryExpression(expr);
137  result += unparseArmExpression(e->get_lhs(), labels, registers, arm_sign_none) + ", " +
138  unparseArmExpression(e->get_rhs(), labels, registers, arm_sign_plus);
139  extra = "!";
140  break;
141  }
142 
143  case V_SgAsmBinarySubtractPreupdate: {
144  /* This node cannot appear at the top of an ARM instruction operand tree */
145  SgAsmBinaryExpression *e = isSgAsmBinaryExpression(expr);
146  result += unparseArmExpression(e->get_lhs(), labels, registers, arm_sign_none) + ", " +
147  unparseArmExpression(e->get_rhs(), labels, registers, arm_sign_minus);
148  extra = "!";
149  break;
150  }
151 
152  case V_SgAsmBinaryAddPostupdate: {
153  /* Two styles of syntax depending on whether this is at top-level or inside a memory reference expression. */
154  SgAsmBinaryExpression *e = isSgAsmBinaryExpression(expr);
155  if (suffix) {
156  result += unparseArmExpression(e->get_lhs(), labels, registers, arm_sign_none);
157  extra = ", " + unparseArmExpression(e->get_rhs(), labels, registers, arm_sign_plus);
158  } else {
159  /* Used by LDM* and STM* instructions outside memory reference expressions. RHS is unused. */
160  result = unparseArmExpression(e->get_lhs(), labels, registers, arm_sign_none) + "!";
161  }
162  break;
163  }
164 
165  case V_SgAsmBinarySubtractPostupdate: {
166  /* Two styles of syntax depending on whether this is at top-level or inside a memory reference expression. */
167  SgAsmBinaryExpression *e = isSgAsmBinaryExpression(expr);
168  if (suffix) {
169  result += unparseArmExpression(e->get_lhs(), labels, registers, arm_sign_none);
170  extra = ", " + unparseArmExpression(e->get_rhs(), labels, registers, arm_sign_minus);
171  } else {
172  /* Used by LDM* and STM* instructions outside memory reference expressions. RHS is unused. */
173  result += unparseArmExpression(e->get_lhs(), labels, registers, arm_sign_none) + "!";
174  }
175  break;
176  }
177 
178  case V_SgAsmMemoryReferenceExpression: {
179  SgAsmMemoryReferenceExpression* mr = isSgAsmMemoryReferenceExpression(expr);
180  SgAsmExpression* addr = mr->get_address();
181  switch (addr->variantT()) {
182  case V_SgAsmDirectRegisterExpression:
183  case V_SgAsmIndirectRegisterExpression:
184  case V_SgAsmBinaryAdd:
185  case V_SgAsmBinarySubtract:
186  case V_SgAsmBinaryAddPreupdate:
187  case V_SgAsmBinarySubtractPreupdate:
188  case V_SgAsmBinaryAddPostupdate:
189  case V_SgAsmBinarySubtractPostupdate:
190  break;
191  default: ASSERT_not_reachable("bad addressing mode: " + stringifyVariantT(addr->variantT()));
192  }
193 
194  std::string suffix;
195  result += "[" + unparseArmExpression(addr, labels, registers, arm_sign_none, &suffix) + "]";
196  result += suffix;
197  break;
198  }
199 
200  case V_SgAsmDirectRegisterExpression:
201  result += unparseArmRegister(isSgAsmDirectRegisterExpression(expr), registers);
202  break;
203  case V_SgAsmIntegerValueExpression: {
204  SgAsmIntegerValueExpression *ve = isSgAsmIntegerValueExpression(expr);
205  ASSERT_not_null(ve);
206  uint64_t v = ve->get_absoluteValue();
207  result += "#" + unparseArmSign(sign) + StringUtility::numberToString(v);
208  if (expr->get_comment().empty() && v!=0 && labels && ve->get_significantBits()>8) {
209  AsmUnparser::LabelMap::const_iterator li=labels->find(v);
210  if (li!=labels->end())
211  result = StringUtility::appendAsmComment(result, li->second);
212  }
213  break;
214  }
215 
216  default: {
217  ASSERT_not_reachable("unhandled expression kind: " + expr->class_name());
218  }
219  }
220 
221  /* The extra data should be passed back up the call stack so it can be inserted into the ultimate return string. We can't
222  * insert it here because the string can't be generated strictly left-to-right. If "suffix" is the null pointer then the
223  * caller isn't expecting a suffix and we'll have to just do our best -- the result will not be valid ARM assembly. */
224  if (extra.size()>0 && !suffix)
225  result = "\"" + result + "\" and \"" + extra + "\"";
226  if (suffix)
227  *suffix = extra;
228 
229  result = StringUtility::appendAsmComment(result, expr->get_comment());
230  return result;
231 }
232 
234 std::string unparseArmMnemonic(SgAsmArmInstruction *insn) {
235  ASSERT_not_null(insn);
236  std::string result = insn->get_mnemonic();
237  std::string cond = unparseArmCondition(insn->get_condition());
238  ASSERT_require(insn->get_positionOfConditionInMnemonic() >= 0);
239  ASSERT_require((size_t)insn->get_positionOfConditionInMnemonic() <= result.size());
240  result.insert(result.begin() + insn->get_positionOfConditionInMnemonic(), cond.begin(), cond.end());
241  return result;
242 }
243 
245 std::string unparseArmExpression(SgAsmExpression *expr, const AsmUnparser::LabelMap *labels,
246  const RegisterDictionary *registers) {
247  /* Find the instruction with which this expression is associated. */
248  SgAsmArmInstruction *insn = NULL;
249  for (SgNode *node=expr; !insn && node; node=node->get_parent()) {
250  insn = isSgAsmArmInstruction(node);
251  }
252  ASSERT_not_null(insn);
253 
254  if (insn->get_kind() == arm_b || insn->get_kind() == arm_bl) {
255  ASSERT_require(insn->get_operandList()->get_operands().size()==1);
256  ASSERT_require(insn->get_operandList()->get_operands()[0]==expr);
257  SgAsmIntegerValueExpression* tgt = isSgAsmIntegerValueExpression(expr);
258  ASSERT_not_null(tgt);
259  return StringUtility::addrToString(tgt->get_value(), tgt->get_significantBits());
260  } else {
261  return unparseArmExpression(expr, labels, registers, arm_sign_none);
262  }
263 }
static const RegisterDictionary * dictionary_arm7()
ARM7 registers.
ROSE_UTIL_API std::string numberToString(long long)
Convert an integer to a string.
Base class for references to a machine register.
std::string stringifyArmSignForExpressionUnparsing(long int n, const char *strip=NULL, bool canonic=false)
Converts an enum of type ArmSignForExpressionUnparsing to a string.
Definition: stringify.C:336
SgAsmExpression * get_lhs() const
Property: Left-hand side operand.
std::string stringifyArmInstructionCondition(long int n, const char *strip=NULL, bool canonic=false)
Converts an enum of type ArmInstructionCondition to a string.
Definition: stringify.C:107
Base class for machine instructions.
const std::string & get_comment() const
Property: Comment.
const SgAsmExpressionPtrList & get_operands() const
Property: Ordered list of instruction operands.
List of expression nodes.
std::string stringifyVariantT(long int n, const char *strip=NULL, bool canonic=false)
Converts an enum of type VariantT to a string.
Definition: stringify.C:28901
SgAsmExpression * get_address() const
Property: Memory address expression.
Main namespace for the ROSE library.
Describes (part of) a physical CPU register.
const SgAsmExpressionPtrList & get_expressions() const
Property: Pointers to expressions.
virtual VariantT variantT() const
returns new style SageIII enum values
ArmInstructionCondition get_condition() const
Property: Arm instruction condition.
RegisterDescriptor get_descriptor() const
Property: Descriptor for accessed register.
const std::string & get_mnemonic() const
Property: Instruction mnemonic string.
SgAsmExpression * get_rhs() const
Property: Right-hand side operand.
Reference to memory locations.
SgAsmOperandList * get_operandList() const
Property: AST node that holds all operands.
ROSE_UTIL_API std::string appendAsmComment(const std::string &s, const std::string &comment)
Append an assembly comment to a string.
Expression representing a machine register.
Base class for integer values.
This class represents the base class for all IR nodes within Sage III.
Definition: Cxx_Grammar.h:8322
ROSE_UTIL_API std::string addrToString(uint64_t value, size_t nbits=0)
Convert a virtual address to a string.
ArmInstructionKind get_kind() const
Property: Instruction kind.
size_t get_significantBits() const
Return the number of significant bits in the value.
int get_positionOfConditionInMnemonic() const
Property: Bit position of condition bits in instruction menmonic.
Defines registers available for a particular architecture.
Definition: Registers.h:32
Base class for expressions.
virtual std::string class_name() const
returns a string representing the class name
Represents one ARM machine instruction.
SgNode * get_parent() const
Access function for parent node.
uint64_t get_absoluteValue(size_t nbits=0) const
Returns the current absolute value zero filled to 64 bits.
const RegisterDescriptor * lookup(const std::string &name) const
Returns a descriptor for a given register name.
Base class for binary expressions.