procs.cpp 12 KB

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