PageRenderTime 32ms CodeModel.GetById 0ms RepoModel.GetById 1ms app.codeStats 0ms

/quakeforge/trunk/libs/gamecode/engine/pr_debug.c

#
C | 1054 lines | 916 code | 103 blank | 35 comment | 217 complexity | c61b62d8f2930554a7cd4c31f248220b MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, AGPL-3.0, AGPL-1.0, Unlicense
  1. /*
  2. pr_debug.c
  3. progs debugging
  4. Copyright (C) 2001 Bill Currie <bill@tanwiha.org>
  5. Author: Bill Currie <bill@tanwiha.org>
  6. Date: 2001/7/13
  7. This program is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU General Public License
  9. as published by the Free Software Foundation; either version 2
  10. of the License, or (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  14. See the GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to:
  17. Free Software Foundation, Inc.
  18. 59 Temple Place - Suite 330
  19. Boston, MA 02111-1307, USA
  20. */
  21. #ifdef HAVE_CONFIG_H
  22. # include "config.h"
  23. #endif
  24. static __attribute__ ((used)) const char rcsid[] =
  25. "$Id: pr_debug.c 11892 2010-05-27 12:21:50Z taniwha $";
  26. #ifdef HAVE_STRING_H
  27. # include <string.h>
  28. #endif
  29. #ifdef HAVE_STRINGS_H
  30. # include <strings.h>
  31. #endif
  32. #include <ctype.h>
  33. #include <sys/types.h>
  34. #include <stdlib.h>
  35. #include "QF/cvar.h"
  36. #include "QF/dstring.h"
  37. #include "QF/hash.h"
  38. #include "QF/pr_debug.h"
  39. #include "QF/progs.h"
  40. #include "QF/qendian.h"
  41. #include "QF/quakefs.h"
  42. #include "QF/script.h"
  43. #include "QF/sys.h"
  44. #include "QF/va.h"
  45. #include "QF/zone.h"
  46. #include "compat.h"
  47. typedef struct {
  48. char *text;
  49. size_t len;
  50. } line_t;
  51. typedef struct {
  52. char *name;
  53. char *text;
  54. line_t *lines;
  55. pr_uint_t num_lines;
  56. progs_t *pr;
  57. } file_t;
  58. cvar_t *pr_debug;
  59. cvar_t *pr_source_path;
  60. static hashtab_t *file_hash;
  61. static char *source_path_string;
  62. static char **source_paths;
  63. static const char *
  64. file_get_key (void *_f, void *unused)
  65. {
  66. return ((file_t*)_f)->name;
  67. }
  68. static void
  69. file_free (void *_f, void *unused)
  70. {
  71. file_t *f = (file_t*)_f;
  72. progs_t *pr = f->pr;
  73. free (f->lines);
  74. ((progs_t *) pr)->free_progs_mem (pr, f->text);
  75. free (f->name);
  76. free (f);
  77. }
  78. static void
  79. source_path_f (cvar_t *var)
  80. {
  81. int i;
  82. char *s;
  83. if (source_path_string)
  84. free (source_path_string);
  85. source_path_string = strdup (var->string);
  86. if (source_paths)
  87. free (source_paths);
  88. for (i = 2, s = source_path_string; *s; s++)
  89. if (*s == ';')
  90. i++;
  91. source_paths = malloc (i * sizeof (char **));
  92. source_paths[0] = source_path_string;
  93. for (i = 1, s = source_path_string; *s; s++)
  94. if (*s == ';') {
  95. *s++ = 0;
  96. source_paths[i++] = s;
  97. }
  98. source_paths[i] = 0;
  99. }
  100. static void
  101. pr_debug_expression_error (script_t *script, const char *msg)
  102. {
  103. Sys_Printf ("%s\n", msg);
  104. }
  105. static pr_type_t *
  106. parse_expression (progs_t *pr, const char *expr)
  107. {
  108. script_t *es;
  109. char *e;
  110. pr_type_t *expr_ptr;
  111. es = Script_New ();
  112. es->error = pr_debug_expression_error;
  113. Script_Start (es, "<console>", expr);
  114. expr_ptr = 0;
  115. if (Script_GetToken (es, 1)) {
  116. if (strequal (es->token->str, "[")) {
  117. edict_t *ent;
  118. ddef_t *field;
  119. if (!Script_GetToken (es, 1))
  120. goto error;
  121. ent = EDICT_NUM (pr, strtol (es->token->str, &e, 0));
  122. if (e == es->token->str)
  123. goto error;
  124. if (!Script_GetToken (es, 1) && !strequal (es->token->str, "]" ))
  125. goto error;
  126. if (!Script_GetToken (es, 1) && !strequal (es->token->str, "." ))
  127. goto error;
  128. if (!Script_GetToken (es, 1))
  129. goto error;
  130. field = PR_FindField (pr, es->token->str);
  131. if (!field)
  132. goto error;
  133. expr_ptr = &ent->v[field->ofs];
  134. } else if (isdigit (es->token->str[0])) {
  135. expr_ptr = PR_GetPointer (pr, strtol (es->token->str, 0, 0));
  136. } else {
  137. ddef_t *global = PR_FindGlobal (pr, es->token->str);
  138. if (!global)
  139. goto error;
  140. expr_ptr = PR_GetPointer (pr, global->ofs);
  141. }
  142. pr->wp_conditional = 0;
  143. if (Script_TokenAvailable (es, 1)) {
  144. if (!Script_GetToken (es, 1) && !strequal (es->token->str, "==" ))
  145. goto error;
  146. if (!Script_GetToken (es, 1))
  147. goto error;
  148. pr->wp_val.integer_var = strtol (es->token->str, &e, 0);
  149. if (e == es->token->str)
  150. goto error;
  151. if (*e == '.' || *e == 'e' || *e == 'E')
  152. pr->wp_val.float_var = strtod (es->token->str, &e);
  153. pr->wp_conditional = 1;
  154. }
  155. if (Script_TokenAvailable (es, 1))
  156. Sys_Printf ("ignoring tail\n");
  157. }
  158. error:
  159. return expr_ptr;
  160. }
  161. void
  162. PR_Debug_Init (void)
  163. {
  164. file_hash = Hash_NewTable (1024, file_get_key, file_free, 0);
  165. }
  166. void
  167. PR_Debug_Init_Cvars (void)
  168. {
  169. pr_debug = Cvar_Get ("pr_debug", "0", CVAR_NONE, NULL,
  170. "enable progs debugging");
  171. pr_source_path = Cvar_Get ("pr_source_path", ".", CVAR_NONE, source_path_f,
  172. "where to look (within gamedir) for source "
  173. "files");
  174. }
  175. static file_t *
  176. PR_Load_Source_File (progs_t *pr, const char *fname)
  177. {
  178. char *path = 0, *l, *p, **dir;
  179. file_t *f = Hash_Find (file_hash, fname);
  180. if (f)
  181. return f;
  182. f = calloc (1, sizeof (file_t));
  183. if (!f)
  184. return 0;
  185. for (dir = source_paths; *dir && !f->text; dir++) {
  186. f->text = pr->load_file (pr, va ("%s%s%s", *dir, **dir ? "/" : "",
  187. fname));
  188. }
  189. if (!f->text) {
  190. pr->file_error (pr, path);
  191. free (f);
  192. return 0;
  193. }
  194. for (f->num_lines = 1, l = f->text; *l; l++)
  195. if (*l == '\n')
  196. f->num_lines++;
  197. f->name = strdup (fname);
  198. if (!f->name) {
  199. pr->free_progs_mem (pr, f->text);
  200. free (f);
  201. return 0;
  202. }
  203. f->lines = malloc (f->num_lines * sizeof (line_t));
  204. if (!f->lines) {
  205. free (f->name);
  206. pr->free_progs_mem (pr, f->text);
  207. free (f);
  208. return 0;
  209. }
  210. f->lines[0].text = f->text;
  211. for (f->num_lines = 0, l = f->text; *l; l++) {
  212. if (*l == '\n') {
  213. for (p = l; p > f->lines[f->num_lines].text && isspace(p[-1]); p--)
  214. ;
  215. f->lines[f->num_lines].len = p - f->lines[f->num_lines].text;
  216. f->lines[++f->num_lines].text = l + 1;
  217. }
  218. }
  219. f->lines[f->num_lines].len = l - f->lines[f->num_lines].text;
  220. f->num_lines++;
  221. f->pr = pr;
  222. Hash_Add (file_hash, f);
  223. return f;
  224. }
  225. VISIBLE int
  226. PR_LoadDebug (progs_t *pr)
  227. {
  228. char *sym_path;
  229. const char *path_end, *sym_file;
  230. pr_uint_t i;
  231. ddef_t *def;
  232. pr_type_t *str = 0;
  233. if (pr->debug)
  234. pr->free_progs_mem (pr, pr->debug);
  235. pr->debug = 0;
  236. pr->auxfunctions = 0;
  237. if (pr->auxfunction_map)
  238. pr->free_progs_mem (pr, pr->auxfunction_map);
  239. pr->auxfunction_map = 0;
  240. pr->linenos = 0;
  241. pr->local_defs = 0;
  242. if (!pr_debug->int_val)
  243. return 1;
  244. def = PR_FindGlobal (pr, ".debug_file");
  245. if (def)
  246. str = &pr->pr_globals[def->ofs];
  247. Hash_FlushTable (file_hash);
  248. if (!str)
  249. return 1;
  250. pr->debugfile = PR_GetString (pr, str->string_var);
  251. sym_file = QFS_SkipPath (pr->debugfile);
  252. path_end = QFS_SkipPath (pr->progs_name);
  253. sym_path = malloc (strlen (sym_file) + (path_end - pr->progs_name) + 1);
  254. strncpy (sym_path, pr->progs_name, path_end - pr->progs_name);
  255. strcpy (sym_path + (path_end - pr->progs_name), sym_file);
  256. pr->debug = pr->load_file (pr, sym_path);
  257. if (!pr->debug) {
  258. Sys_Printf ("can't load %s for debug info\n", sym_path);
  259. free (sym_path);
  260. return 1;
  261. }
  262. pr->debug->version = LittleLong (pr->debug->version);
  263. if (pr->debug->version != PROG_DEBUG_VERSION) {
  264. Sys_Printf ("ignoring %s with unsupported version %x.%03x.%03x\n",
  265. sym_path,
  266. (pr->debug->version >> 24) & 0xff,
  267. (pr->debug->version >> 12) & 0xfff,
  268. pr->debug->version & 0xfff);
  269. pr->debug = 0;
  270. free (sym_path);
  271. return 1;
  272. }
  273. pr->debug->crc = LittleShort (pr->debug->crc);
  274. if (pr->debug->crc != pr->crc) {
  275. Sys_Printf ("ignoring %s that doesn't match %s. (CRCs: "
  276. "sym:%d dat:%d)\n",
  277. sym_path,
  278. pr->progs_name,
  279. pr->debug->crc,
  280. pr->crc);
  281. pr->debug = 0;
  282. free (sym_path);
  283. return 1;
  284. }
  285. free (sym_path);
  286. pr->debug->you_tell_me_and_we_will_both_know = LittleShort
  287. (pr->debug->you_tell_me_and_we_will_both_know);
  288. pr->debug->auxfunctions = LittleLong (pr->debug->auxfunctions);
  289. pr->debug->num_auxfunctions = LittleLong (pr->debug->num_auxfunctions);
  290. pr->debug->linenos = LittleLong (pr->debug->linenos);
  291. pr->debug->num_linenos = LittleLong (pr->debug->num_linenos);
  292. pr->debug->locals = LittleLong (pr->debug->locals);
  293. pr->debug->num_locals = LittleLong (pr->debug->num_locals);
  294. pr->auxfunctions = (pr_auxfunction_t*)((char*)pr->debug +
  295. pr->debug->auxfunctions);
  296. pr->linenos = (pr_lineno_t*)((char*)pr->debug + pr->debug->linenos);
  297. pr->local_defs = (ddef_t*)((char*)pr->debug + pr->debug->locals);
  298. i = pr->progs->numfunctions * sizeof (pr_auxfunction_t *);
  299. pr->auxfunction_map = pr->allocate_progs_mem (pr, i);
  300. for (i = 0; i < pr->debug->num_auxfunctions; i++) {
  301. pr->auxfunctions[i].function = LittleLong
  302. (pr->auxfunctions[i].function);
  303. pr->auxfunctions[i].source_line = LittleLong
  304. (pr->auxfunctions[i].source_line);
  305. pr->auxfunctions[i].line_info = LittleLong
  306. (pr->auxfunctions[i].line_info);
  307. pr->auxfunctions[i].local_defs = LittleLong
  308. (pr->auxfunctions[i].local_defs);
  309. pr->auxfunctions[i].num_locals = LittleLong
  310. (pr->auxfunctions[i].num_locals);
  311. pr->auxfunction_map[pr->auxfunctions[i].function] =
  312. &pr->auxfunctions[i];
  313. }
  314. for (i = 0; i < pr->debug->num_linenos; i++) {
  315. pr->linenos[i].fa.func = LittleLong (pr->linenos[i].fa.func);
  316. pr->linenos[i].line = LittleLong (pr->linenos[i].line);
  317. }
  318. for (i = 0; i < pr->debug->num_locals; i++) {
  319. pr->local_defs[i].type = LittleShort (pr->local_defs[i].type);
  320. pr->local_defs[i].ofs = LittleShort (pr->local_defs[i].ofs);
  321. pr->local_defs[i].s_name = LittleLong (pr->local_defs[i].s_name);
  322. }
  323. return 1;
  324. }
  325. pr_auxfunction_t *
  326. PR_Get_Lineno_Func (progs_t *pr, pr_lineno_t *lineno)
  327. {
  328. while (lineno > pr->linenos && lineno->line)
  329. lineno--;
  330. if (lineno->line)
  331. return 0;
  332. return &pr->auxfunctions[lineno->fa.func];
  333. }
  334. pr_uint_t
  335. PR_Get_Lineno_Addr (progs_t *pr, pr_lineno_t *lineno)
  336. {
  337. pr_auxfunction_t *f;
  338. if (lineno->line)
  339. return lineno->fa.addr;
  340. f = &pr->auxfunctions[lineno->fa.func];
  341. return pr->pr_functions[f->function].first_statement;
  342. }
  343. pr_uint_t
  344. PR_Get_Lineno_Line (progs_t *pr, pr_lineno_t *lineno)
  345. {
  346. if (lineno->line)
  347. return lineno->line;
  348. return 0;
  349. }
  350. pr_lineno_t *
  351. PR_Find_Lineno (progs_t *pr, pr_uint_t addr)
  352. {
  353. pr_uint_t i;
  354. pr_lineno_t *lineno = 0;
  355. if (!pr->debug)
  356. return 0;
  357. if (!pr->debug->num_linenos)
  358. return 0;
  359. for (i = pr->debug->num_linenos; i > 0; i--) {
  360. if (PR_Get_Lineno_Addr (pr, &pr->linenos[i - 1]) <= addr) {
  361. lineno = &pr->linenos[i - 1];
  362. break;
  363. }
  364. }
  365. return lineno;
  366. }
  367. const char *
  368. PR_Get_Source_File (progs_t *pr, pr_lineno_t *lineno)
  369. {
  370. pr_auxfunction_t *f;
  371. f = PR_Get_Lineno_Func (pr, lineno);
  372. return PR_GetString(pr, pr->pr_functions[f->function].s_file);
  373. }
  374. const char *
  375. PR_Get_Source_Line (progs_t *pr, pr_uint_t addr)
  376. {
  377. const char *fname;
  378. pr_uint_t line;
  379. file_t *file;
  380. pr_auxfunction_t *func;
  381. pr_lineno_t *lineno;
  382. lineno = PR_Find_Lineno (pr, addr);
  383. if (!lineno || PR_Get_Lineno_Addr (pr, lineno) != addr)
  384. return 0;
  385. func = PR_Get_Lineno_Func (pr, lineno);
  386. fname = PR_Get_Source_File (pr, lineno);
  387. if (!func || !fname)
  388. return 0;
  389. line = PR_Get_Lineno_Line (pr, lineno);
  390. line += func->source_line;
  391. file = PR_Load_Source_File (pr, fname);
  392. if (!file || line > file->num_lines)
  393. return va ("%s:%u", fname, line);
  394. return va ("%s:%u:%.*s", fname, line, (int)file->lines[line - 1].len,
  395. file->lines[line - 1].text);
  396. }
  397. ddef_t *
  398. PR_Get_Param_Def (progs_t *pr, dfunction_t *func, unsigned parm)
  399. {
  400. pr_uint_t i;
  401. pr_auxfunction_t *aux_func;
  402. ddef_t *ddef = 0;
  403. if (!pr->debug)
  404. return 0;
  405. if (!func)
  406. return 0;
  407. if (func->numparms >= 0 && parm >= (unsigned) func->numparms)
  408. return 0;
  409. if (func->numparms < 0 && parm >= (unsigned) -func->numparms)
  410. return 0;
  411. aux_func = pr->auxfunction_map[func - pr->pr_functions];
  412. if (!aux_func)
  413. return 0;
  414. for (i = 0; i < aux_func->num_locals; i++) {
  415. ddef = &pr->local_defs[aux_func->local_defs + i];
  416. if (!parm--)
  417. break;
  418. if (ddef->type == ev_vector)
  419. i += 3; // skip over component defs
  420. }
  421. return ddef;
  422. }
  423. static pr_auxfunction_t *
  424. get_aux_function (progs_t *pr)
  425. {
  426. dfunction_t *func;
  427. if (!pr->pr_xfunction || !pr->auxfunction_map)
  428. return 0;
  429. func = pr->pr_xfunction->descriptor;
  430. return pr->auxfunction_map[func - pr->pr_functions];
  431. }
  432. ddef_t *
  433. PR_Get_Local_Def (progs_t *pr, pr_int_t offs)
  434. {
  435. pr_uint_t i;
  436. dfunction_t *func;
  437. pr_auxfunction_t *aux_func;
  438. if (!pr->pr_xfunction)
  439. return 0;
  440. func = pr->pr_xfunction->descriptor;
  441. aux_func = pr->auxfunction_map[func - pr->pr_functions];
  442. if (!aux_func)
  443. return 0;
  444. offs -= func->parm_start;
  445. if (offs < 0 || offs >= func->locals)
  446. return 0;
  447. for (i = 0; i < aux_func->num_locals; i++)
  448. if (pr->local_defs[aux_func->local_defs + i].ofs == offs)
  449. return &pr->local_defs[aux_func->local_defs + i];
  450. return 0;
  451. }
  452. VISIBLE void
  453. PR_DumpState (progs_t *pr)
  454. {
  455. if (pr->pr_xfunction) {
  456. if (pr_debug->int_val && pr->debug) {
  457. pr_lineno_t *lineno;
  458. pr_auxfunction_t *func = 0;
  459. dfunction_t *descriptor = pr->pr_xfunction->descriptor;
  460. pr_int_t addr = pr->pr_xstatement;
  461. lineno = PR_Find_Lineno (pr, addr);
  462. if (lineno)
  463. func = PR_Get_Lineno_Func (pr, lineno);
  464. if (func && descriptor == pr->pr_functions + func->function)
  465. addr = PR_Get_Lineno_Addr (pr, lineno);
  466. else
  467. addr = max (descriptor->first_statement, addr - 5);
  468. while (addr != pr->pr_xstatement)
  469. PR_PrintStatement (pr, pr->pr_statements + addr++, 3);
  470. }
  471. PR_PrintStatement (pr, pr->pr_statements + pr->pr_xstatement, 3);
  472. }
  473. PR_StackTrace (pr);
  474. }
  475. static const char *
  476. value_string (progs_t *pr, etype_t type, pr_type_t *val)
  477. {
  478. static dstring_t *line;
  479. ddef_t *def;
  480. pr_int_t ofs;
  481. edict_t *edict;
  482. dfunction_t *f;
  483. const char *str;
  484. if (!line)
  485. line = dstring_new ();
  486. type &= ~DEF_SAVEGLOBAL;
  487. switch (type) {
  488. case ev_string:
  489. if (!PR_StringValid (pr, val->string_var))
  490. return "*** invalid ***";
  491. str = PR_GetString (pr, val->string_var);
  492. dstring_copystr (line, "\"");
  493. while (*str) {
  494. const char *s;
  495. for (s = str; *s && !strchr ("\"\n\t", *s); s++)
  496. ;
  497. if (s != str)
  498. dstring_appendsubstr (line, str, s - str);
  499. if (*s) {
  500. switch (*s) {
  501. case '\"':
  502. dstring_appendstr (line, "\\\"");
  503. break;
  504. case '\n':
  505. dstring_appendstr (line, "\\n");
  506. break;
  507. case '\t':
  508. dstring_appendstr (line, "\\t");
  509. break;
  510. default:
  511. dasprintf (line, "\\x%02x", *s & 0xff);
  512. }
  513. s++;
  514. }
  515. str = s;
  516. }
  517. dstring_appendstr (line, "\"");
  518. break;
  519. case ev_entity:
  520. edict = PROG_TO_EDICT (pr, val->entity_var);
  521. dsprintf (line, "entity %d", NUM_FOR_BAD_EDICT (pr, edict));
  522. break;
  523. case ev_func:
  524. if (val->func_var < 0 || val->func_var >= pr->progs->numfunctions)
  525. dsprintf (line, "INVALID:%d", val->func_var);
  526. else if (!val->func_var)
  527. return "NULL";
  528. else {
  529. f = pr->pr_functions + val->func_var;
  530. dsprintf (line, "%s()", PR_GetString (pr, f->s_name));
  531. }
  532. break;
  533. case ev_field:
  534. def = PR_FieldAtOfs (pr, val->integer_var);
  535. if (def)
  536. dsprintf (line, ".%s", PR_GetString (pr, def->s_name));
  537. else
  538. dsprintf (line, ".<$%04x>", val->integer_var);
  539. break;
  540. case ev_void:
  541. return "void";
  542. case ev_float:
  543. dsprintf (line, "%g", val->float_var);
  544. break;
  545. case ev_vector:
  546. dsprintf (line, "'%g %g %g'",
  547. val->vector_var[0], val->vector_var[1],
  548. val->vector_var[2]);
  549. break;
  550. case ev_pointer:
  551. def = 0;
  552. ofs = val->integer_var;
  553. if (pr_debug->int_val && pr->debug)
  554. def = PR_Get_Local_Def (pr, ofs);
  555. if (!def)
  556. def = PR_GlobalAtOfs (pr, ofs);
  557. if (def && def->s_name)
  558. dsprintf (line, "&%s", PR_GetString (pr, def->s_name));
  559. else
  560. dsprintf (line, "[$%x]", ofs);
  561. break;
  562. case ev_quat:
  563. dsprintf (line, "'%g %g %g %g'",
  564. val->vector_var[0], val->vector_var[1],
  565. val->vector_var[2], val->vector_var[3]);
  566. break;
  567. case ev_integer:
  568. dsprintf (line, "%d", val->integer_var);
  569. break;
  570. case ev_uinteger:
  571. dsprintf (line, "$%08x", val->uinteger_var);
  572. break;
  573. case ev_sel:
  574. dsprintf (line, "(SEL) %s", PR_GetString (pr, val->string_var));
  575. break;
  576. default:
  577. dsprintf (line, "bad type %i", type);
  578. break;
  579. }
  580. return line->str;
  581. }
  582. static ddef_t *
  583. def_string (progs_t *pr, pr_int_t ofs, dstring_t *dstr)
  584. {
  585. ddef_t *def = 0;
  586. const char *name;
  587. if (pr_debug->int_val && pr->debug)
  588. def = PR_Get_Local_Def (pr, ofs);
  589. if (!def)
  590. def = PR_GlobalAtOfs (pr, ofs);
  591. if (!def || !*(name = PR_GetString (pr, def->s_name)))
  592. dsprintf (dstr, "[$%x]", ofs);
  593. else
  594. dsprintf (dstr, "%s", name);
  595. return def;
  596. }
  597. static const char *
  598. global_string (progs_t *pr, pr_int_t ofs, etype_t type, int contents)
  599. {
  600. static dstring_t *line = NULL;
  601. ddef_t *def = NULL;
  602. const char *s;
  603. if (!line)
  604. line = dstring_newstr();
  605. if (type == ev_short) {
  606. dsprintf (line, "%04x", (short) ofs);
  607. return line->str;
  608. }
  609. def = def_string (pr, ofs, line);
  610. if (def || type != ev_void) {
  611. const char *oi = "";
  612. if (def) {
  613. if (type == ev_void)
  614. type = def->type;
  615. if (type != (etype_t) (def->type & ~DEF_SAVEGLOBAL))
  616. oi = "?";
  617. }
  618. if (ofs > pr->globals_size)
  619. s = "Out of bounds";
  620. else
  621. s = value_string (pr, type, &pr->pr_globals[ofs]);
  622. if (strequal(line->str, "IMMEDIATE") || strequal(line->str, ".imm")) {
  623. dsprintf (line, "%s", s);
  624. } else {
  625. if (contents)
  626. dasprintf (line, "%s(%s)", oi, s);
  627. }
  628. }
  629. return line->str;
  630. }
  631. VISIBLE void
  632. PR_Debug_Watch (progs_t *pr, const char *expr)
  633. {
  634. if (!expr) {
  635. Sys_Printf ("watch <watchpoint expr>\n");
  636. if (pr->watch) {
  637. Sys_Printf (" watching [%d]\n",
  638. (int) (intptr_t) (pr->watch - pr->pr_globals));
  639. if (pr->wp_conditional)
  640. Sys_Printf (" if new val == %d\n",
  641. pr->wp_val.integer_var);
  642. } else {
  643. Sys_Printf (" none active\n");
  644. }
  645. return;
  646. }
  647. pr->watch = parse_expression (pr, expr);
  648. if (pr->watch) {
  649. Sys_Printf ("watchpoint set to [%d]\n", PR_SetPointer (pr, pr->watch));
  650. if (pr->wp_conditional)
  651. Sys_Printf (" if new val == %d\n", pr->wp_val.integer_var);
  652. } else {
  653. Sys_Printf ("watchpoint cleared\n");
  654. }
  655. }
  656. VISIBLE void
  657. PR_Debug_Print (progs_t *pr, const char *expr)
  658. {
  659. pr_type_t *print;
  660. if (!expr) {
  661. Sys_Printf ("print <print expr>\n");
  662. return;
  663. }
  664. print = parse_expression (pr, expr);
  665. if (print) {
  666. pr_int_t ofs = PR_SetPointer (pr, print);
  667. const char *s = global_string (pr, ofs, ev_void, 1);
  668. Sys_Printf ("[%d] = %s\n", ofs, s);
  669. }
  670. }
  671. VISIBLE void
  672. PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents)
  673. {
  674. int addr = s - pr->pr_statements;
  675. int dump_code = contents & 2;
  676. const char *fmt;
  677. opcode_t *op;
  678. static dstring_t *line;
  679. dfunction_t *call_func = 0;
  680. ddef_t *parm_def = 0;
  681. pr_auxfunction_t *aux_func = 0;
  682. if (!line)
  683. line = dstring_new ();
  684. dstring_clearstr (line);
  685. if (pr_debug->int_val > 1)
  686. dump_code = 1;
  687. if (pr_debug->int_val && pr->debug) {
  688. const char *source_line = PR_Get_Source_Line (pr, addr);
  689. if (source_line) {
  690. dasprintf (line, "%s%s", source_line, dump_code ? "\n" : "");
  691. if (!dump_code)
  692. goto do_print;
  693. }
  694. if (!dump_code)
  695. return;
  696. }
  697. op = PR_Opcode (s->op);
  698. if (!op) {
  699. Sys_Printf ("%sUnknown instruction %d\n", line->str, s->op);
  700. return;
  701. }
  702. if (!(fmt = op->fmt))
  703. fmt = "%Ga, %Gb, %gc";
  704. dasprintf (line, "%04x ", addr);
  705. if (pr_debug->int_val > 2)
  706. dasprintf (line, "%02x %04x(%8s) %04x(%8s) %04x(%8s)\t",
  707. s->op,
  708. s->a, pr_type_name[op->type_a],
  709. s->b, pr_type_name[op->type_b],
  710. s->c, pr_type_name[op->type_c]);
  711. dasprintf (line, "%s ", op->opname);
  712. while (*fmt) {
  713. if (*fmt == '%') {
  714. if (fmt[1] == '%') {
  715. dstring_appendsubstr (line, fmt + 1, 1);
  716. fmt += 2;
  717. } else {
  718. const char *str;
  719. char mode = fmt[1], opchar = fmt[2];
  720. unsigned parm_ind = 0;
  721. pr_int_t opval;
  722. etype_t optype = ev_void;
  723. if (mode == 'P') {
  724. opchar = fmt[3];
  725. parm_ind = fmt[2] - '0';
  726. fmt++; // P has one extra item
  727. if (parm_ind >= MAX_PARMS)
  728. goto err;
  729. }
  730. switch (opchar) {
  731. case 'a':
  732. opval = s->a;
  733. optype = op->type_a;
  734. break;
  735. case 'b':
  736. opval = s->b;
  737. optype = op->type_b;
  738. break;
  739. case 'c':
  740. opval = s->c;
  741. optype = op->type_c;
  742. break;
  743. case 'x':
  744. if (mode == 'P') {
  745. opval = pr->pr_real_params[parm_ind]
  746. - pr->pr_globals;
  747. break;
  748. }
  749. default:
  750. goto err;
  751. }
  752. switch (mode) {
  753. case 'R':
  754. optype = ev_void;
  755. aux_func = get_aux_function (pr);
  756. if (aux_func)
  757. optype = aux_func->return_type;
  758. str = global_string (pr, opval, optype, contents & 1);
  759. break;
  760. case 'F':
  761. str = global_string (pr, opval, optype, contents & 1);
  762. call_func = pr->pr_functions + G_FUNCTION (pr, opval);
  763. break;
  764. case 'P':
  765. parm_def = PR_Get_Param_Def (pr, call_func, parm_ind);
  766. optype = ev_void;
  767. if (parm_def)
  768. optype = parm_def->type;
  769. str = global_string (pr, opval, optype, contents & 1);
  770. break;
  771. case 'V':
  772. str = global_string (pr, opval, ev_void, contents & 1);
  773. break;
  774. case 'G':
  775. str = global_string (pr, opval, optype, contents & 1);
  776. break;
  777. case 'g':
  778. str = global_string (pr, opval, optype, 0);
  779. break;
  780. case 's':
  781. str = va ("%d", (short) opval);
  782. break;
  783. case 'O':
  784. str = va ("%04x", addr + (short) opval);
  785. break;
  786. default:
  787. goto err;
  788. }
  789. dstring_appendstr (line, str);
  790. fmt += 3;
  791. continue;
  792. err:
  793. dstring_appendstr (line, fmt);
  794. break;
  795. }
  796. } else {
  797. dstring_appendsubstr (line, fmt++, 1);
  798. }
  799. }
  800. do_print:
  801. Sys_Printf ("%s\n", line->str);
  802. }
  803. static void
  804. dump_frame (progs_t *pr, prstack_t *frame)
  805. {
  806. dfunction_t *f = frame->f ? frame->f->descriptor : 0;
  807. if (!f) {
  808. Sys_Printf ("<NO FUNCTION>\n");
  809. return;
  810. }
  811. if (pr_debug->int_val && pr->debug) {
  812. pr_lineno_t *lineno = PR_Find_Lineno (pr, frame->s);
  813. pr_auxfunction_t *func = PR_Get_Lineno_Func (pr, lineno);
  814. pr_uint_t line = PR_Get_Lineno_Line (pr, lineno);
  815. pr_int_t addr = PR_Get_Lineno_Addr (pr, lineno);
  816. line += func->source_line;
  817. if (addr == frame->s) {
  818. Sys_Printf ("%12s:%u : %s: %x\n",
  819. PR_GetString (pr, f->s_file),
  820. line,
  821. PR_GetString (pr, f->s_name),
  822. frame->s);
  823. } else {
  824. Sys_Printf ("%12s:%u+%d : %s: %x\n",
  825. PR_GetString (pr, f->s_file),
  826. line, frame->s - addr,
  827. PR_GetString (pr, f->s_name),
  828. frame->s);
  829. }
  830. } else {
  831. Sys_Printf ("%12s : %s: %x\n", PR_GetString (pr, f->s_file),
  832. PR_GetString (pr, f->s_name), frame->s);
  833. }
  834. }
  835. VISIBLE void
  836. PR_StackTrace (progs_t *pr)
  837. {
  838. int i;
  839. prstack_t top;
  840. if (pr->pr_depth == 0) {
  841. Sys_Printf ("<NO STACK>\n");
  842. return;
  843. }
  844. top.s = pr->pr_xstatement;
  845. top.f = pr->pr_xfunction;
  846. dump_frame (pr, &top);
  847. for (i = pr->pr_depth - 1; i >= 0; i--)
  848. dump_frame (pr, pr->pr_stack + i);
  849. }
  850. VISIBLE void
  851. PR_Profile (progs_t * pr)
  852. {
  853. pr_int_t max, num, i;
  854. dfunction_t *best, *f;
  855. num = 0;
  856. do {
  857. max = 0;
  858. best = NULL;
  859. for (i = 0; i < pr->progs->numfunctions; i++) {
  860. f = &pr->pr_functions[i];
  861. if (f->profile > max) {
  862. max = f->profile;
  863. best = f;
  864. }
  865. }
  866. if (best) {
  867. if (num < 10)
  868. Sys_Printf ("%7i %s\n", best->profile,
  869. PR_GetString (pr, best->s_name));
  870. num++;
  871. best->profile = 0;
  872. }
  873. } while (best);
  874. }
  875. /*
  876. ED_Print
  877. For debugging
  878. */
  879. VISIBLE void
  880. ED_Print (progs_t *pr, edict_t *ed)
  881. {
  882. int type, l;
  883. pr_uint_t i;
  884. const char *name;
  885. ddef_t *d;
  886. pr_type_t *v;
  887. if (ed->free) {
  888. Sys_Printf ("FREE\n");
  889. return;
  890. }
  891. Sys_Printf ("\nEDICT %d:\n", NUM_FOR_BAD_EDICT (pr, ed));
  892. for (i = 0; i < pr->progs->numfielddefs; i++) {
  893. d = &pr->pr_fielddefs[i];
  894. if (!d->s_name) // null field def (probably 1st)
  895. continue;
  896. name = PR_GetString (pr, d->s_name);
  897. if (name[strlen (name) - 2] == '_')
  898. continue; // skip _x, _y, _z vars
  899. v = ed->v + d->ofs;
  900. // if the value is still all 0, skip the field
  901. type = d->type & ~DEF_SAVEGLOBAL;
  902. switch (type) {
  903. case ev_entity:
  904. case ev_integer:
  905. case ev_uinteger:
  906. case ev_pointer:
  907. case ev_func:
  908. case ev_field:
  909. if (!v->integer_var)
  910. continue;
  911. break;
  912. case ev_sel:
  913. if (!v[0].integer_var
  914. && !PR_GetString (pr, v[1].string_var)[0])
  915. continue;
  916. break;
  917. case ev_string:
  918. if (PR_StringValid (pr, v->string_var))
  919. if (!PR_GetString (pr, v->string_var)[0])
  920. continue;
  921. break;
  922. case ev_float:
  923. if (!v->float_var)
  924. continue;
  925. break;
  926. case ev_vector:
  927. if (!v[0].float_var && !v[1].float_var && !v[2].float_var)
  928. continue;
  929. break;
  930. case ev_void:
  931. break;
  932. default:
  933. PR_Error (pr, "ED_Print: Unhandled type %d", type);
  934. }
  935. Sys_Printf ("%s", name);
  936. l = strlen (name);
  937. while (l++ < 15)
  938. Sys_Printf (" ");
  939. Sys_Printf ("%s\n", value_string (pr, d->type, v));
  940. }
  941. }