procs.cpp 12 KB

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