procs.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. /*
  2. * File: procs.c
  3. * Purpose: Functions to support Call graphs and procedures
  4. * Date: November 1993
  5. * (C) Cristina Cifuentes
  6. */
  7. #include <cstring>
  8. #include <cassert>
  9. #include "dcc.h"
  10. #include "project.h"
  11. extern Project g_proj;
  12. /* Static indentation buffer */
  13. static constexpr int indSize=81; /* size of indentation buffer; max 20 */
  14. static char indentBuf[indSize] =
  15. " ";
  16. // not static, used in icode.cpp at emitGotoLabel
  17. const char *indentStr(int indLevel) // Indentation according to the depth of the statement
  18. {
  19. return (&indentBuf[indSize-(indLevel*4)-1]);
  20. }
  21. /* Inserts an outEdge at the current callGraph pointer if the newProc does
  22. * not exist. */
  23. void CALL_GRAPH::insertArc (ilFunction newProc)
  24. {
  25. CALL_GRAPH *pcg;
  26. /* Check if procedure already exists */
  27. auto res=std::find_if(outEdges.begin(),outEdges.end(),[newProc](CALL_GRAPH *e) {return e->proc==newProc;});
  28. if(res!=outEdges.end())
  29. return;
  30. /* Include new arc */
  31. pcg = new CALL_GRAPH;
  32. pcg->proc = newProc;
  33. outEdges.push_back(pcg);
  34. }
  35. /* Inserts a (caller, callee) arc in the call graph tree. */
  36. bool CALL_GRAPH::insertCallGraph(ilFunction caller, ilFunction callee)
  37. {
  38. int i;
  39. if (proc == caller)
  40. {
  41. insertArc (callee);
  42. return true;
  43. }
  44. else
  45. {
  46. for (i = 0; i < outEdges.size(); i++)
  47. if (outEdges[i]->insertCallGraph (caller, callee))
  48. return true;
  49. return (false);
  50. }
  51. }
  52. bool CALL_GRAPH::insertCallGraph(Function *caller, ilFunction callee)
  53. {
  54. return insertCallGraph(g_proj.funcIter(caller),callee);
  55. }
  56. /* Displays the current node of the call graph, and invokes recursively on
  57. * the nodes the procedure invokes. */
  58. void CALL_GRAPH::writeNodeCallGraph(int indIdx)
  59. {
  60. int i;
  61. printf ("%s%s\n", indentStr(indIdx), proc->name.c_str());
  62. for (i = 0; i < outEdges.size(); i++)
  63. outEdges[i]->writeNodeCallGraph (indIdx + 1);
  64. }
  65. /* Writes the header and invokes recursive procedure */
  66. void CALL_GRAPH::write()
  67. {
  68. printf ("\nCall Graph:\n");
  69. writeNodeCallGraph (0);
  70. }
  71. /**************************************************************************
  72. * Routines to support arguments
  73. *************************************************************************/
  74. /* Updates the argument table by including the register(s) (ie. lhs of
  75. * picode) and the actual expression (ie. rhs of picode).
  76. * Note: register(s) are only included once in the table. */
  77. void LOCAL_ID::newRegArg(iICODE picode, iICODE ticode) const
  78. {
  79. COND_EXPR *lhs;
  80. STKFRAME * call_args_stackframe, *target_stackframe;
  81. const ID *id;
  82. int tidx;
  83. boolT regExist;
  84. condId type;
  85. Function * tproc;
  86. eReg regL, regH; /* Registers involved in arguments */
  87. /* Flag ticode as having register arguments */
  88. tproc = ticode->hl()->call.proc;
  89. tproc->flg |= REG_ARGS;
  90. /* Get registers and index into target procedure's local list */
  91. call_args_stackframe = ticode->hl()->call.args;
  92. target_stackframe = &tproc->args;
  93. lhs = picode->hl()->asgn.lhs;
  94. type = lhs->expr.ident.idType;
  95. if (type == REGISTER)
  96. {
  97. regL = id_arr[lhs->expr.ident.idNode.regiIdx].id.regi;
  98. if (regL < rAL)
  99. tidx = tproc->localId.newByteWordReg(TYPE_WORD_SIGN, regL);
  100. else
  101. tidx = tproc->localId.newByteWordReg(TYPE_BYTE_SIGN, regL);
  102. }
  103. else if (type == LONG_VAR)
  104. {
  105. int longIdx = lhs->expr.ident.idNode.longIdx;
  106. regL = id_arr[longIdx].id.longId.l;
  107. regH = id_arr[longIdx].id.longId.h;
  108. tidx = tproc->localId.newLongReg(TYPE_LONG_SIGN, regH, regL, tproc->Icode.begin() /*0*/);
  109. }
  110. /* Check if register argument already on the formal argument list */
  111. regExist = false;
  112. for(STKSYM &tgt_sym : *target_stackframe)
  113. {
  114. if( tgt_sym.regs == NULL ) // both REGISTER and LONG_VAR require this precondition
  115. continue;
  116. if (type == REGISTER)
  117. {
  118. if ( tgt_sym.regs->expr.ident.idNode.regiIdx == tidx )
  119. {
  120. regExist = true;
  121. }
  122. }
  123. else if (type == LONG_VAR)
  124. {
  125. if ( tgt_sym.regs->expr.ident.idNode.longIdx == tidx )
  126. {
  127. regExist = true;
  128. }
  129. }
  130. if(regExist == true)
  131. break;
  132. }
  133. /* Do ts (formal arguments) */
  134. if (regExist == false)
  135. {
  136. STKSYM newsym;
  137. newsym.setArgName(target_stackframe->size());
  138. if (type == REGISTER)
  139. {
  140. if (regL < rAL)
  141. {
  142. newsym.type = TYPE_WORD_SIGN;
  143. newsym.regs = COND_EXPR::idRegIdx(tidx, WORD_REG);
  144. }
  145. else
  146. {
  147. newsym.type = TYPE_BYTE_SIGN;
  148. newsym.regs = COND_EXPR::idRegIdx(tidx, BYTE_REG);
  149. }
  150. tproc->localId.id_arr[tidx].name = newsym.name;
  151. }
  152. else if (type == LONG_VAR)
  153. {
  154. newsym.regs = COND_EXPR::idLongIdx (tidx);
  155. newsym.type = TYPE_LONG_SIGN;
  156. tproc->localId.id_arr[tidx].name = newsym.name;
  157. tproc->localId.propLongId (regL, regH, tproc->localId.id_arr[tidx].name.c_str());
  158. }
  159. target_stackframe->push_back(newsym);
  160. target_stackframe->numArgs++;
  161. }
  162. /* Do ps (actual arguments) */
  163. STKSYM newsym;
  164. newsym.setArgName(call_args_stackframe->size());
  165. newsym.actual = picode->hl()->asgn.rhs;
  166. newsym.regs = lhs;
  167. /* Mask off high and low register(s) in picode */
  168. switch (type) {
  169. case REGISTER:
  170. id = &id_arr[lhs->expr.ident.idNode.regiIdx];
  171. picode->du.def &= maskDuReg[id->id.regi];
  172. if (id->id.regi < rAL)
  173. newsym.type = TYPE_WORD_SIGN;
  174. else
  175. newsym.type = TYPE_BYTE_SIGN;
  176. break;
  177. case LONG_VAR:
  178. id = &id_arr[lhs->expr.ident.idNode.longIdx];
  179. picode->du.def &= maskDuReg[id->id.longId.h];
  180. picode->du.def &= maskDuReg[id->id.longId.l];
  181. newsym.type = TYPE_LONG_SIGN;
  182. break;
  183. }
  184. call_args_stackframe->push_back(newsym);
  185. call_args_stackframe->numArgs++;
  186. }
  187. /** Inserts the new expression (ie. the actual parameter) on the argument
  188. * list.
  189. * @return true if it was a near call that made use of a segment register.
  190. * false elsewhere
  191. */
  192. bool CallType::newStkArg(COND_EXPR *exp, llIcode opcode, Function * pproc)
  193. {
  194. uint8_t regi;
  195. /* Check for far procedure call, in which case, references to segment
  196. * registers are not be considered another parameter (i.e. they are
  197. * long references to another segment) */
  198. if (exp)
  199. {
  200. if ((exp->m_type == IDENTIFIER) && (exp->expr.ident.idType == REGISTER))
  201. {
  202. regi = pproc->localId.id_arr[exp->expr.ident.idNode.regiIdx].id.regi;
  203. if ((regi >= rES) && (regi <= rDS))
  204. if (opcode == iCALLF)
  205. return false;
  206. else
  207. return true;
  208. }
  209. }
  210. /* Place register argument on the argument list */
  211. STKSYM newsym;
  212. newsym.actual = exp;
  213. args->push_back(newsym);
  214. args->numArgs++;
  215. return false;
  216. }
  217. /* Places the actual argument exp in the position given by pos in the
  218. * argument list of picode. */
  219. void CallType::placeStkArg (COND_EXPR *exp, int pos)
  220. {
  221. (*args)[pos].actual = exp;
  222. (*args)[pos].setArgName(pos);
  223. }
  224. COND_EXPR *CallType::toId()
  225. {
  226. return COND_EXPR::idFunc( proc, args);
  227. }
  228. /* Checks to determine whether the expression (actual argument) has the
  229. * same type as the given type (from the procedure's formal list). If not,
  230. * the actual argument gets modified */
  231. void adjustActArgType (COND_EXPR *exp, hlType forType, Function * pproc)
  232. {
  233. hlType actType;
  234. int offset, offL;
  235. if (exp == NULL)
  236. return;
  237. actType = exp-> expType (pproc);
  238. if (((actType == forType) || (exp->m_type != IDENTIFIER)))
  239. return;
  240. switch (forType)
  241. {
  242. case TYPE_UNKNOWN: case TYPE_BYTE_SIGN:
  243. case TYPE_BYTE_UNSIGN: case TYPE_WORD_SIGN:
  244. case TYPE_WORD_UNSIGN: case TYPE_LONG_SIGN:
  245. case TYPE_LONG_UNSIGN: case TYPE_RECORD:
  246. break;
  247. case TYPE_PTR:
  248. case TYPE_CONST:
  249. break;
  250. case TYPE_STR:
  251. switch (actType) {
  252. case TYPE_CONST:
  253. /* It's an offset into image where a string is
  254. * found. Point to the string. */
  255. offL = exp->expr.ident.idNode.kte.kte;
  256. if (prog.fCOM)
  257. offset = (pproc->state.r[rDS]<<4) + offL + 0x100;
  258. else
  259. offset = (pproc->state.r[rDS]<<4) + offL;
  260. exp->expr.ident.idNode.strIdx = offset;
  261. exp->expr.ident.idType = STRING;
  262. break;
  263. case TYPE_PTR:
  264. /* It's a pointer to a char rather than a pointer to
  265. * an integer */
  266. /***HERE - modify the type ****/
  267. break;
  268. case TYPE_WORD_SIGN:
  269. break;
  270. } /* eos */
  271. break;
  272. }
  273. }
  274. /* Determines whether the formal argument has the same type as the given
  275. * type (type of the actual argument). If not, the formal argument is
  276. * changed its type */
  277. void STKFRAME::adjustForArgType(int numArg_, hlType actType_)
  278. {
  279. hlType forType;
  280. STKSYM * psym, * nsym;
  281. int off, i;
  282. /* If formal argument does not exist, do not create new ones, just
  283. * ignore actual argument
  284. */
  285. if(numArg_>size())
  286. return;
  287. /* Find stack offset for this argument */
  288. off = m_minOff;
  289. i=0;
  290. for(STKSYM &s : *this) // walk formal arguments upto numArg_
  291. {
  292. if(i>=numArg_)
  293. break;
  294. off+=s.size;
  295. i++;
  296. }
  297. /* Find formal argument */
  298. //psym = &at(numArg_);
  299. //i = numArg_;
  300. //auto iter=std::find_if(sym.begin(),sym.end(),[off](STKSYM &s)->bool {s.off==off;});
  301. auto iter=std::find_if(begin()+numArg_,end(),[off](STKSYM &s)->bool {s.label==off;});
  302. if(iter==end()) // symbol not found
  303. return;
  304. psym = &(*iter);
  305. forType = psym->type;
  306. if (forType != actType_)
  307. {
  308. switch (actType_) {
  309. case TYPE_UNKNOWN: case TYPE_BYTE_SIGN:
  310. case TYPE_BYTE_UNSIGN: case TYPE_WORD_SIGN:
  311. case TYPE_WORD_UNSIGN: case TYPE_RECORD:
  312. break;
  313. case TYPE_LONG_UNSIGN: case TYPE_LONG_SIGN:
  314. if ((forType == TYPE_WORD_UNSIGN) ||
  315. (forType == TYPE_WORD_SIGN) ||
  316. (forType == TYPE_UNKNOWN))
  317. {
  318. /* Merge low and high */
  319. psym->type = actType_;
  320. psym->size = 4;
  321. nsym = psym + 1;
  322. nsym->macro = "HI";
  323. psym->macro = "LO";
  324. nsym->hasMacro = true;
  325. psym->hasMacro = true;
  326. nsym->name = psym->name;
  327. nsym->invalid = true;
  328. numArgs--;
  329. }
  330. break;
  331. case TYPE_PTR:
  332. case TYPE_CONST:
  333. case TYPE_STR:
  334. break;
  335. } /* eos */
  336. }
  337. }