procs.cpp 12 KB

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