procs.cpp 12 KB

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