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