ROSE  0.9.6a
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SgAsmFunction.C
Go to the documentation of this file.
1 /* SgAsmFunction member definitions. Do not move them to src/ROSETTA/Grammar/BinaryInstruction.code (or any *.code file)
2  * because then they won't get indexed/formatted/etc. by C-aware tools. */
3 
4 #include "sage3basic.h"
5 #include "stringify.h"
6 
7 #include "rosePublicConfig.h"
8 #ifdef ROSE_HAVE_GCRYPT_H
9 #include <gcrypt.h>
10 #endif
11 
12 using namespace rose;
13 
16 std::string
17 SgAsmFunction::reason_key(const std::string &prefix)
18 {
19  return (prefix + "E = entry address H = CFG head C = function call(*)\n" +
20  prefix + "X = exception frame T = thunk I = imported/dyn-linked\n" +
21  prefix + "O = exported S = function symbol P = instruction pattern\n" +
22  prefix + "G = CFG graph analysis U = user-def detection N = NOP/zero padding\n" +
23  prefix + "D = discontiguous blocks V = intra-function block L = leftover blocks\n" +
24  prefix + "Mxxx are miscellaneous reasons (at most one misc reason per function):\n" +
25  prefix + " M001 = code between function padding bytes\n" +
26  prefix + "Note: \"c\" means this is the target of a call-like instruction or instruction\n" +
27  prefix + " sequence but the call is not present in the global control flow graph, while\n" +
28  prefix + " \"C\" means the call is in the CFG.\n");
29 }
30 
32 std::string
33 SgAsmFunction::reason_str(bool do_pad) const
34 {
35  return reason_str(do_pad, get_reason());
36 }
37 
40 std::string
41 SgAsmFunction::reason_str(bool do_pad, unsigned r)
42 {
43  using namespace StringUtility; // for add_to_reason_string()
44  std::string result;
45 
46  /* entry point and instruction heads are mutually exclusive, so we use the same column for both when padding. */
47  if (r & FUNC_ENTRY_POINT) {
48  add_to_reason_string(result, true, do_pad, "E", "entry point");
49  } else {
50  add_to_reason_string(result, (r & FUNC_INSNHEAD), do_pad, "H", "insn head");
51  }
52 
53  /* Function call:
54  * "C" means the function was detected because we saw a call-like instructon (such as x86 CALL or FARCALL) or instruction
55  * sequence (such as pushing the return value and then branching) in code that was determined to be reachable by
56  * analyzing the control flow graph.
57  *
58  * "c" means this function is the target of some call-like instruction (such as x86 CALL or FARCALL) but could not
59  * determine whether the instruction is actually executed.
60  */
61  if (r & FUNC_CALL_TARGET) {
62  add_to_reason_string(result, true, do_pad, "C", "function call");
63  } else {
64  add_to_reason_string(result, (r & FUNC_CALL_INSN), do_pad, "c", "call instruction");
65  }
66 
67  if (r & FUNC_EH_FRAME) {
68  add_to_reason_string(result, true, do_pad, "X", "exception frame");
69  } else {
70  add_to_reason_string(result, (r & FUNC_THUNK), do_pad, "T", "thunk");
71  }
72  add_to_reason_string(result, (r & FUNC_IMPORT), do_pad, "I", "import");
73  add_to_reason_string(result, (r & FUNC_EXPORT), do_pad, "E", "export");
74  add_to_reason_string(result, (r & FUNC_SYMBOL), do_pad, "S", "symbol");
75  add_to_reason_string(result, (r & FUNC_PATTERN), do_pad, "P", "pattern");
76  add_to_reason_string(result, (r & FUNC_GRAPH), do_pad, "G", "graph");
77  add_to_reason_string(result, (r & FUNC_USERDEF), do_pad, "U", "user defined");
78  add_to_reason_string(result, (r & FUNC_PADDING), do_pad, "N", "padding");
79  add_to_reason_string(result, (r & FUNC_DISCONT), do_pad, "D", "discontiguous");
80  add_to_reason_string(result, (r & FUNC_LEFTOVERS), do_pad, "L", "leftovers");
81  add_to_reason_string(result, (r & FUNC_INTRABLOCK), do_pad, "V", "intrablock");
82 
83  /* The miscellaneous marker is special. It's a single letter like the others, but is followed by a fixed width
84  * integer indicating the (user-defined) algorithm that added the function. */
85  {
86  char abbr[32], full[64];
87  int width = snprintf(abbr, sizeof abbr, "%u", FUNC_MISCMASK);
88  snprintf(abbr, sizeof abbr, "M%0*u", width, (r & FUNC_MISCMASK));
89  abbr[sizeof(abbr)-1] = '\0';
90  if (!do_pad) {
91  std::string miscname = stringifySgAsmFunctionFunctionReason((r & FUNC_MISCMASK), "FUNC_");
92  if (miscname.empty() || miscname[0]=='(') {
93  snprintf(full, sizeof full, "misc-%u", (r & FUNC_MISCMASK));
94  } else {
95  for (size_t i=0; i<miscname.size(); ++i)
96  miscname[i] = tolower(miscname[i]);
97  strncpy(full, miscname.c_str(), sizeof full);
98  }
99  full[sizeof(full)-1] = '\0';
100  } else {
101  full[0] = '\0';
102  }
103  add_to_reason_string(result, (r & FUNC_MISCMASK), do_pad, abbr, full);
104  }
105 
106  return result;
107 }
108 
147 size_t
149 {
150  struct T1: public AstSimpleProcessing {
151  ExtentMap *extents;
152  rose_addr_t *lo_addr, *hi_addr;
153  NodeSelector *selector;
154  size_t nnodes;
155  T1(ExtentMap *extents, rose_addr_t *lo_addr, rose_addr_t *hi_addr, NodeSelector *selector)
156  : extents(extents), lo_addr(lo_addr), hi_addr(hi_addr), selector(selector), nnodes(0) {
157  if (lo_addr)
158  *lo_addr = 0;
159  if (hi_addr)
160  *hi_addr = 0;
161  }
162  void visit(SgNode *node) {
163  if (selector && !(*selector)(node))
164  return;
165  SgAsmInstruction *insn = isSgAsmInstruction(node);
166  SgAsmStaticData *data = isSgAsmStaticData(node);
167  rose_addr_t lo, hi;
168  if (insn) {
169  lo = insn->get_address();
170  hi = lo + insn->get_size();
171  } else if (data) {
172  lo = data->get_address();
173  hi = lo + data->get_size();
174  } else {
175  return;
176  }
177 
178  if (0==nnodes++) {
179  if (lo_addr)
180  *lo_addr = lo;
181  if (hi_addr)
182  *hi_addr = hi;
183  } else {
184  if (lo_addr)
185  *lo_addr = std::min(*lo_addr, lo);
186  if (hi_addr)
187  *hi_addr = std::max(*hi_addr, hi);
188  }
189  if (extents && hi>lo)
190  extents->insert(Extent(lo, hi-lo));
191  }
192  } t1(extents, lo_addr, hi_addr, selector);
193  t1.traverse(this, preorder);
194  return t1.nnodes;
195 }
196 
197 bool
198 SgAsmFunction::get_sha1(uint8_t digest[20], NodeSelector *selector)
199 {
200 #ifdef ROSE_HAVE_GCRYPT_H
201  struct T1: public AstSimpleProcessing {
202  NodeSelector *selector;
203  gcry_md_hd_t md; // message digest
204  T1(NodeSelector *selector): selector(selector) {
205  gcry_error_t error = gcry_md_open(&md, GCRY_MD_SHA1, 0);
206  assert(GPG_ERR_NO_ERROR==error);
207  }
208  ~T1() {
209  gcry_md_close(md);
210  }
211  void visit(SgNode *node) {
212  if (selector && !(*selector)(node))
213  return;
214  SgAsmInstruction *insn = isSgAsmInstruction(node);
215  SgAsmStaticData *data = isSgAsmStaticData(node);
216  if (insn) {
217  SgUnsignedCharList buf = insn->get_raw_bytes();
218  gcry_md_write(md, &buf[0], buf.size());
219  } else if (data) {
220  SgUnsignedCharList buf = data->get_raw_bytes();
221  gcry_md_write(md, &buf[0], buf.size());
222  }
223  }
224  void read(uint8_t digest[20]) {
225  assert(gcry_md_get_algo_dlen(GCRY_MD_SHA1)==20);
226  gcry_md_final(md);
227  unsigned char *d = gcry_md_read(md, GCRY_MD_SHA1);
228  assert(d!=NULL);
229  memcpy(digest, d, 20);
230  }
231  } t1(selector);
232  t1.traverse(this, preorder);
233  t1.read(digest);
234  return true;
235 #else
236  memset(digest, 0, 20);
237  return false;
238 #endif
239 }
240 
243 SgAsmBlock *
245  for (SgAsmStatementPtrList::const_iterator si=p_statementList.begin(); si!=p_statementList.end(); ++si) {
246  SgAsmBlock *bb = isSgAsmBlock(*si);
247  if (bb && bb->get_address()==p_entry_va)
248  return bb;
249  }
250  return NULL;
251 }