PageRenderTime 27ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/quakeforge/branches/release_0_5_5/libs/gamecode/engine/pr_debug.c

#
C | 859 lines | 736 code | 88 blank | 35 comment | 155 complexity | 603a49605fbc30202dbbf813cff75ede 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__ ((unused)) const char rcsid[] =
  25. "$Id: pr_debug.c 10823 2004-04-08 02:33:20Z 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 <stdlib.h>
  33. #include "QF/cvar.h"
  34. #include "QF/dstring.h"
  35. #include "QF/hash.h"
  36. #include "QF/pr_debug.h"
  37. #include "QF/progs.h"
  38. #include "QF/qendian.h"
  39. #include "QF/quakefs.h"
  40. #include "QF/sys.h"
  41. #include "QF/va.h"
  42. #include "QF/zone.h"
  43. #include "compat.h"
  44. typedef struct {
  45. char *text;
  46. size_t len;
  47. } line_t;
  48. typedef struct {
  49. char *name;
  50. char *text;
  51. line_t *lines;
  52. unsigned int num_lines;
  53. progs_t *pr;
  54. } file_t;
  55. cvar_t *pr_debug;
  56. cvar_t *pr_source_path;
  57. static hashtab_t *file_hash;
  58. static char *source_path_string;
  59. static char **source_paths;
  60. static const char *
  61. file_get_key (void *_f, void *unused)
  62. {
  63. return ((file_t*)_f)->name;
  64. }
  65. static void
  66. file_free (void *_f, void *unused)
  67. {
  68. file_t *f = (file_t*)_f;
  69. progs_t *pr = f->pr;
  70. free (f->lines);
  71. ((progs_t *) pr)->free_progs_mem (pr, f->text);
  72. free (f->name);
  73. free (f);
  74. }
  75. static void
  76. source_path_f (cvar_t *var)
  77. {
  78. int i;
  79. char *s;
  80. if (source_path_string)
  81. free (source_path_string);
  82. source_path_string = strdup (var->string);
  83. if (source_paths)
  84. free (source_paths);
  85. for (i = 2, s = source_path_string; *s; s++)
  86. if (*s == ';')
  87. i++;
  88. source_paths = malloc (i * sizeof (char **));
  89. source_paths[0] = source_path_string;
  90. for (i = 1, s = source_path_string; *s; s++)
  91. if (*s == ';') {
  92. *s++ = 0;
  93. source_paths[i++] = s;
  94. }
  95. source_paths[i] = 0;
  96. }
  97. void
  98. PR_Debug_Init (void)
  99. {
  100. file_hash = Hash_NewTable (1024, file_get_key, file_free, 0);
  101. }
  102. void
  103. PR_Debug_Init_Cvars (void)
  104. {
  105. pr_debug = Cvar_Get ("pr_debug", "0", CVAR_NONE, NULL,
  106. "enable progs debugging");
  107. pr_source_path = Cvar_Get ("pr_source_path", ".", CVAR_NONE, source_path_f,
  108. "where to look (within gamedir) for source "
  109. "files");
  110. }
  111. static file_t *
  112. PR_Load_Source_File (progs_t *pr, const char *fname)
  113. {
  114. char *path = 0, *l, **dir;
  115. file_t *f = Hash_Find (file_hash, fname);
  116. if (f)
  117. return f;
  118. f = calloc (1, sizeof (file_t));
  119. if (!f)
  120. return 0;
  121. for (dir = source_paths; *dir && !f->text; dir++) {
  122. int len;
  123. len = strlen (*dir) + strlen (fname) + 2;
  124. path = Hunk_TempAlloc (len);
  125. sprintf (path, "%s%s%s", *dir, **dir ? "/" : "", fname);
  126. f->text = pr->load_file (pr, path);
  127. }
  128. if (!f->text) {
  129. pr->file_error (pr, path);
  130. free (f);
  131. return 0;
  132. }
  133. for (f->num_lines = 1, l = f->text; *l; l++)
  134. if (*l == '\n')
  135. f->num_lines++;
  136. f->name = strdup (fname);
  137. if (!f->name) {
  138. pr->free_progs_mem (pr, f->text);
  139. free (f);
  140. return 0;
  141. }
  142. f->lines = malloc (f->num_lines * sizeof (line_t));
  143. if (!f->lines) {
  144. free (f->name);
  145. pr->free_progs_mem (pr, f->text);
  146. free (f);
  147. return 0;
  148. }
  149. f->lines[0].text = f->text;
  150. for (f->num_lines = 0, l = f->text; *l; l++) {
  151. if (*l == '\n') {
  152. f->lines[f->num_lines].len = l - f->lines[f->num_lines].text;
  153. f->lines[++f->num_lines].text = l + 1;
  154. }
  155. }
  156. f->lines[f->num_lines++].len = l - f->lines[f->num_lines].text;
  157. f->pr = pr;
  158. Hash_Add (file_hash, f);
  159. return f;
  160. }
  161. int
  162. PR_LoadDebug (progs_t *pr)
  163. {
  164. char *sym_path;
  165. const char *path_end, *sym_file;
  166. unsigned int i;
  167. int start = Hunk_LowMark ();
  168. ddef_t *def;
  169. pr_type_t *str = 0;
  170. if (pr->debug)
  171. pr->free_progs_mem (pr, pr->debug);
  172. pr->debug = 0;
  173. pr->auxfunctions = 0;
  174. if (pr->auxfunction_map)
  175. pr->free_progs_mem (pr, pr->auxfunction_map);
  176. pr->auxfunction_map = 0;
  177. pr->linenos = 0;
  178. pr->local_defs = 0;
  179. if (!pr_debug->int_val)
  180. return 1;
  181. def = PR_FindGlobal (pr, ".debug_file");
  182. if (def)
  183. str = &pr->pr_globals[def->ofs];
  184. Hash_FlushTable (file_hash);
  185. if (!str)
  186. return 1;
  187. pr->debugfile = PR_GetString (pr, str->string_var);
  188. sym_file = QFS_SkipPath (pr->debugfile);
  189. path_end = QFS_SkipPath (pr->progs_name);
  190. sym_path = Hunk_TempAlloc (strlen (sym_file) + (path_end - pr->progs_name)
  191. + 1);
  192. strncpy (sym_path, pr->progs_name, path_end - pr->progs_name);
  193. strcpy (sym_path + (path_end - pr->progs_name), sym_file);
  194. pr->debug = pr->load_file (pr, sym_path);
  195. if (!pr->debug) {
  196. Sys_Printf ("can't load %s for debug info\n", sym_path);
  197. return 1;
  198. }
  199. pr->debug->version = LittleLong (pr->debug->version);
  200. if (pr->debug->version != PROG_DEBUG_VERSION) {
  201. Sys_Printf ("ignoring %s with unsupported version %x.%03x.%03x\n",
  202. sym_path,
  203. (pr->debug->version >> 24) & 0xff,
  204. (pr->debug->version >> 12) & 0xfff,
  205. pr->debug->version & 0xfff);
  206. Hunk_FreeToLowMark (start);
  207. pr->debug = 0;
  208. return 1;
  209. }
  210. pr->debug->crc = LittleShort (pr->debug->crc);
  211. if (pr->debug->crc != pr->crc) {
  212. Sys_Printf ("ignoring %s that doesn't match %s. (CRCs: "
  213. "sym:%d dat:%d)\n",
  214. sym_path,
  215. pr->progs_name,
  216. pr->debug->crc,
  217. pr->crc);
  218. Hunk_FreeToLowMark (start);
  219. pr->debug = 0;
  220. return 1;
  221. }
  222. pr->debug->you_tell_me_and_we_will_both_know = LittleShort
  223. (pr->debug->you_tell_me_and_we_will_both_know);
  224. pr->debug->auxfunctions = LittleLong (pr->debug->auxfunctions);
  225. pr->debug->num_auxfunctions = LittleLong (pr->debug->num_auxfunctions);
  226. pr->debug->linenos = LittleLong (pr->debug->linenos);
  227. pr->debug->num_linenos = LittleLong (pr->debug->num_linenos);
  228. pr->debug->locals = LittleLong (pr->debug->locals);
  229. pr->debug->num_locals = LittleLong (pr->debug->num_locals);
  230. pr->auxfunctions = (pr_auxfunction_t*)((char*)pr->debug +
  231. pr->debug->auxfunctions);
  232. pr->linenos = (pr_lineno_t*)((char*)pr->debug + pr->debug->linenos);
  233. pr->local_defs = (ddef_t*)((char*)pr->debug + pr->debug->locals);
  234. i = pr->progs->numfunctions * sizeof (pr_auxfunction_t *);
  235. pr->auxfunction_map = pr->allocate_progs_mem (pr, i);
  236. for (i = 0; i < pr->debug->num_auxfunctions; i++) {
  237. pr->auxfunctions[i].function = LittleLong
  238. (pr->auxfunctions[i].function);
  239. pr->auxfunctions[i].source_line = LittleLong
  240. (pr->auxfunctions[i].source_line);
  241. pr->auxfunctions[i].line_info = LittleLong
  242. (pr->auxfunctions[i].line_info);
  243. pr->auxfunctions[i].local_defs = LittleLong
  244. (pr->auxfunctions[i].local_defs);
  245. pr->auxfunctions[i].num_locals = LittleLong
  246. (pr->auxfunctions[i].num_locals);
  247. pr->auxfunction_map[pr->auxfunctions[i].function] =
  248. &pr->auxfunctions[i];
  249. }
  250. for (i = 0; i < pr->debug->num_linenos; i++) {
  251. pr->linenos[i].fa.func = LittleLong (pr->linenos[i].fa.func);
  252. pr->linenos[i].line = LittleLong (pr->linenos[i].line);
  253. }
  254. for (i = 0; i < pr->debug->num_locals; i++) {
  255. pr->local_defs[i].type = LittleShort (pr->local_defs[i].type);
  256. pr->local_defs[i].ofs = LittleShort (pr->local_defs[i].ofs);
  257. pr->local_defs[i].s_name = LittleLong (pr->local_defs[i].s_name);
  258. }
  259. return 1;
  260. }
  261. pr_auxfunction_t *
  262. PR_Get_Lineno_Func (progs_t *pr, pr_lineno_t *lineno)
  263. {
  264. while (lineno > pr->linenos && lineno->line)
  265. lineno--;
  266. if (lineno->line)
  267. return 0;
  268. return &pr->auxfunctions[lineno->fa.func];
  269. }
  270. unsigned int
  271. PR_Get_Lineno_Addr (progs_t *pr, pr_lineno_t *lineno)
  272. {
  273. pr_auxfunction_t *f;
  274. if (lineno->line)
  275. return lineno->fa.addr;
  276. f = &pr->auxfunctions[lineno->fa.func];
  277. return pr->pr_functions[f->function].first_statement;
  278. }
  279. unsigned int
  280. PR_Get_Lineno_Line (progs_t *pr, pr_lineno_t *lineno)
  281. {
  282. if (lineno->line)
  283. return lineno->line;
  284. return 0;
  285. }
  286. pr_lineno_t *
  287. PR_Find_Lineno (progs_t *pr, unsigned int addr)
  288. {
  289. int i;
  290. pr_lineno_t *lineno = 0;
  291. if (!pr->debug)
  292. return 0;
  293. if (!pr->debug->num_linenos)
  294. return 0;
  295. for (i = pr->debug->num_linenos - 1; i >= 0; i--) {
  296. if (PR_Get_Lineno_Addr (pr, &pr->linenos[i]) <= addr) {
  297. lineno = &pr->linenos[i];
  298. break;
  299. }
  300. }
  301. return lineno;
  302. }
  303. const char *
  304. PR_Get_Source_File (progs_t *pr, pr_lineno_t *lineno)
  305. {
  306. pr_auxfunction_t *f;
  307. f = PR_Get_Lineno_Func (pr, lineno);
  308. return PR_GetString(pr, pr->pr_functions[f->function].s_file);
  309. }
  310. const char *
  311. PR_Get_Source_Line (progs_t *pr, unsigned int addr)
  312. {
  313. char *str;
  314. const char *fname;
  315. unsigned int line;
  316. file_t *file;
  317. pr_auxfunction_t *func;
  318. pr_lineno_t *lineno;
  319. lineno = PR_Find_Lineno (pr, addr);
  320. if (!lineno || PR_Get_Lineno_Addr (pr, lineno) != addr)
  321. return 0;
  322. func = PR_Get_Lineno_Func (pr, lineno);
  323. fname = PR_Get_Source_File (pr, lineno);
  324. if (!func || !fname)
  325. return 0;
  326. line = PR_Get_Lineno_Line (pr, lineno);
  327. line += func->source_line;
  328. file = PR_Load_Source_File (pr, fname);
  329. str = Hunk_TempAlloc (strlen (fname) + 12);
  330. sprintf (str, "%s:%d", fname, line);
  331. if (!file || line > file->num_lines)
  332. return str;
  333. str = Hunk_TempAlloc (strlen (str) + file->lines[line - 1].len + 2);
  334. sprintf (str, "%s:%d:%.*s", fname, line,
  335. (int)file->lines[line - 1].len, file->lines[line - 1].text);
  336. return str;
  337. }
  338. ddef_t *
  339. PR_Get_Local_Def (progs_t *pr, int offs)
  340. {
  341. unsigned int i;
  342. dfunction_t *func = pr->pr_xfunction;
  343. pr_auxfunction_t *aux_func;
  344. if (!func)
  345. return 0;
  346. aux_func = pr->auxfunction_map[func - pr->pr_functions];
  347. if (!aux_func)
  348. return 0;
  349. offs -= func->parm_start;
  350. if (offs < 0 || offs >= func->locals)
  351. return 0;
  352. for (i = 0; i < aux_func->num_locals; i++)
  353. if (pr->local_defs[aux_func->local_defs + i].ofs == offs)
  354. return &pr->local_defs[aux_func->local_defs + i];
  355. return 0;
  356. }
  357. void
  358. PR_DumpState (progs_t *pr)
  359. {
  360. if (pr->pr_xfunction) {
  361. if (pr_debug->int_val && pr->debug) {
  362. pr_lineno_t *lineno;
  363. pr_auxfunction_t *func = 0;
  364. int addr = pr->pr_xstatement;
  365. lineno = PR_Find_Lineno (pr, addr);
  366. if (lineno)
  367. func = PR_Get_Lineno_Func (pr, lineno);
  368. if (func && pr->pr_xfunction == pr->pr_functions + func->function)
  369. addr = PR_Get_Lineno_Addr (pr, lineno);
  370. else
  371. addr = max (pr->pr_xfunction->first_statement, addr - 5);
  372. while (addr != pr->pr_xstatement)
  373. PR_PrintStatement (pr, pr->pr_statements + addr++, 1);
  374. }
  375. PR_PrintStatement (pr, pr->pr_statements + pr->pr_xstatement, 1);
  376. }
  377. PR_StackTrace (pr);
  378. }
  379. static const char *
  380. value_string (progs_t *pr, etype_t type, pr_type_t *val)
  381. {
  382. static dstring_t *line;
  383. ddef_t *def;
  384. int ofs;
  385. edict_t *edict;
  386. dfunction_t *f;
  387. const char *str;
  388. if (!line)
  389. line = dstring_new ();
  390. type &= ~DEF_SAVEGLOBAL;
  391. switch (type) {
  392. case ev_string:
  393. if (!PR_StringValid (pr, val->string_var))
  394. return "*** invalid ***";
  395. str = PR_GetString (pr, val->string_var);
  396. dstring_copystr (line, "\"");
  397. while (*str) {
  398. const char *s;
  399. for (s = str; *s && !strchr ("\"\n\t", *s); s++)
  400. ;
  401. if (s != str)
  402. dstring_appendsubstr (line, str, s - str);
  403. if (*s) {
  404. switch (*s) {
  405. case '\"':
  406. dstring_appendstr (line, "\\\"");
  407. break;
  408. case '\n':
  409. dstring_appendstr (line, "\\n");
  410. break;
  411. case '\t':
  412. dstring_appendstr (line, "\\t");
  413. break;
  414. default:
  415. dasprintf (line, "\\x%02x", *s & 0xff);
  416. }
  417. s++;
  418. }
  419. str = s;
  420. }
  421. dstring_appendstr (line, "\"");
  422. break;
  423. case ev_entity:
  424. edict = PROG_TO_EDICT (pr, val->entity_var);
  425. dsprintf (line, "entity %i", NUM_FOR_BAD_EDICT (pr, edict));
  426. break;
  427. case ev_func:
  428. if (val->func_var < 0 || val->func_var >= pr->progs->numfunctions)
  429. dsprintf (line, "INVALID:%d", val->func_var);
  430. else if (!val->func_var)
  431. return "NULL";
  432. else {
  433. f = pr->pr_functions + val->func_var;
  434. dsprintf (line, "%s()", PR_GetString (pr, f->s_name));
  435. }
  436. break;
  437. case ev_field:
  438. def = ED_FieldAtOfs (pr, val->integer_var);
  439. if (def)
  440. dsprintf (line, ".%s", PR_GetString (pr, def->s_name));
  441. else
  442. dsprintf (line, ".<$%04x>", val->integer_var);
  443. break;
  444. case ev_void:
  445. return "void";
  446. case ev_float:
  447. dsprintf (line, "%g", val->float_var);
  448. break;
  449. case ev_vector:
  450. dsprintf (line, "'%g %g %g'",
  451. val->vector_var[0], val->vector_var[1],
  452. val->vector_var[2]);
  453. break;
  454. case ev_pointer:
  455. def = 0;
  456. ofs = val->integer_var;
  457. if (pr_debug->int_val && pr->debug)
  458. def = PR_Get_Local_Def (pr, ofs);
  459. if (!def)
  460. def = ED_GlobalAtOfs (pr, ofs);
  461. if (def && def->s_name)
  462. dsprintf (line, "&%s", PR_GetString (pr, def->s_name));
  463. else
  464. dsprintf (line, "[$%x]", ofs);
  465. break;
  466. case ev_quat:
  467. dsprintf (line, "'%g %g %g %g'",
  468. val->vector_var[0], val->vector_var[1],
  469. val->vector_var[2], val->vector_var[3]);
  470. break;
  471. case ev_integer:
  472. dsprintf (line, "%d", val->integer_var);
  473. break;
  474. case ev_uinteger:
  475. dsprintf (line, "$%08x", val->uinteger_var);
  476. break;
  477. case ev_sel:
  478. dsprintf (line, "(SEL) %s", PR_GetString (pr, val->string_var));
  479. break;
  480. default:
  481. dsprintf (line, "bad type %i", type);
  482. break;
  483. }
  484. return line->str;
  485. }
  486. static ddef_t *
  487. def_string (progs_t *pr, int ofs, dstring_t *dstr)
  488. {
  489. ddef_t *def = 0;
  490. const char *name;
  491. if (pr_debug->int_val && pr->debug)
  492. def = PR_Get_Local_Def (pr, ofs);
  493. if (!def)
  494. def = ED_GlobalAtOfs (pr, ofs);
  495. if (!def || !*(name = PR_GetString (pr, def->s_name)))
  496. dsprintf (dstr, "[$%x]", ofs);
  497. else
  498. dsprintf (dstr, "%s", name);
  499. return def;
  500. }
  501. static const char *
  502. global_string (progs_t *pr, int ofs, etype_t type, int contents)
  503. {
  504. ddef_t *def = NULL;
  505. static dstring_t *line = NULL;
  506. const char *s;
  507. if (!line)
  508. line = dstring_newstr();
  509. if (type == ev_short) {
  510. dsprintf (line, "%04x", (short) ofs);
  511. return line->str;
  512. }
  513. def = def_string (pr, ofs, line);
  514. if (def || type != ev_void) {
  515. const char *oi = "";
  516. if (def) {
  517. if (type == ev_void)
  518. type = def->type;
  519. if (type != (etype_t) (def->type & ~DEF_SAVEGLOBAL))
  520. oi = "?";
  521. }
  522. if (ofs > pr->globals_size)
  523. s = "Out of bounds";
  524. else
  525. s = value_string (pr, type, &pr->pr_globals[ofs]);
  526. if (strequal(line->str, "IMMEDIATE") || strequal(line->str, ".imm")) {
  527. dsprintf (line, "%s", s);
  528. } else {
  529. if (contents)
  530. dasprintf (line, "%s(%s)", oi, s);
  531. }
  532. }
  533. return line->str;
  534. }
  535. void
  536. PR_PrintStatement (progs_t * pr, dstatement_t *s, int contents)
  537. {
  538. int addr = s - pr->pr_statements;
  539. const char *fmt;
  540. opcode_t *op;
  541. static dstring_t *line;
  542. if (!line)
  543. line = dstring_new ();
  544. dstring_clearstr (line);
  545. if (pr_debug->int_val && pr->debug) {
  546. const char *source_line = PR_Get_Source_Line (pr, addr);
  547. if (source_line)
  548. dasprintf (line, "%s\n", source_line);
  549. }
  550. op = PR_Opcode (s->op);
  551. if (!op) {
  552. Sys_Printf ("%sUnknown instruction %d\n", line->str, s->op);
  553. return;
  554. }
  555. if (!(fmt = op->fmt))
  556. fmt = "%Ga, %Gb, %gc";
  557. dasprintf (line, "%04x ", addr);
  558. if (pr_debug->int_val > 1)
  559. dasprintf (line, "%02x %04x(%8s) %04x(%8s) %04x(%8s)\t",
  560. s->op,
  561. s->a, pr_type_name[op->type_a],
  562. s->b, pr_type_name[op->type_b],
  563. s->c, pr_type_name[op->type_c]);
  564. dasprintf (line, "%s ", op->opname);
  565. while (*fmt) {
  566. if (*fmt == '%') {
  567. if (fmt[1] == '%') {
  568. dstring_appendsubstr (line, fmt + 1, 1);
  569. fmt += 2;
  570. } else {
  571. const char *str;
  572. char mode = fmt[1];
  573. char opchar = fmt[2];
  574. long opval;
  575. etype_t optype;
  576. switch (opchar) {
  577. case 'a':
  578. opval = s->a;
  579. optype = op->type_a;
  580. break;
  581. case 'b':
  582. opval = s->b;
  583. optype = op->type_b;
  584. break;
  585. case 'c':
  586. opval = s->c;
  587. optype = op->type_c;
  588. break;
  589. default:
  590. goto err;
  591. }
  592. switch (mode) {
  593. case 'V':
  594. str = global_string (pr, opval, ev_void, contents);
  595. break;
  596. case 'G':
  597. str = global_string (pr, opval, optype, contents);
  598. break;
  599. case 'g':
  600. str = global_string (pr, opval, optype, 0);
  601. break;
  602. case 's':
  603. str = va ("%d", (short) opval);
  604. break;
  605. case 'O':
  606. str = va ("%04x", addr + (short) opval);
  607. break;
  608. default:
  609. goto err;
  610. }
  611. dstring_appendstr (line, str);
  612. fmt += 3;
  613. continue;
  614. err:
  615. dstring_appendstr (line, fmt);
  616. break;
  617. }
  618. } else {
  619. dstring_appendsubstr (line, fmt++, 1);
  620. }
  621. }
  622. Sys_Printf ("%s\n", line->str);
  623. }
  624. static void
  625. dump_frame (progs_t *pr, prstack_t *frame)
  626. {
  627. dfunction_t *f = frame->f;
  628. if (!f) {
  629. Sys_Printf ("<NO FUNCTION>\n");
  630. return;
  631. }
  632. if (pr_debug->int_val && pr->debug) {
  633. pr_lineno_t *lineno = PR_Find_Lineno (pr, frame->s);
  634. pr_auxfunction_t *func = PR_Get_Lineno_Func (pr, lineno);
  635. unsigned int line = PR_Get_Lineno_Line (pr, lineno);
  636. int addr = PR_Get_Lineno_Addr (pr, lineno);
  637. line += func->source_line;
  638. if (addr == frame->s) {
  639. Sys_Printf ("%12s:%d : %s: %x\n",
  640. PR_GetString (pr, f->s_file),
  641. line,
  642. PR_GetString (pr, f->s_name),
  643. frame->s);
  644. } else {
  645. Sys_Printf ("%12s:%d+%d : %s: %x\n",
  646. PR_GetString (pr, f->s_file),
  647. line, frame->s - addr,
  648. PR_GetString (pr, f->s_name),
  649. frame->s);
  650. }
  651. } else {
  652. Sys_Printf ("%12s : %s: %x\n", PR_GetString (pr, f->s_file),
  653. PR_GetString (pr, f->s_name), frame->s);
  654. }
  655. }
  656. void
  657. PR_StackTrace (progs_t *pr)
  658. {
  659. int i;
  660. prstack_t top;
  661. if (pr->pr_depth == 0) {
  662. Sys_Printf ("<NO STACK>\n");
  663. return;
  664. }
  665. top.s = pr->pr_xstatement;
  666. top.f = pr->pr_xfunction;
  667. dump_frame (pr, &top);
  668. for (i = pr->pr_depth - 1; i >= 0; i--)
  669. dump_frame (pr, pr->pr_stack + i);
  670. }
  671. void
  672. PR_Profile (progs_t * pr)
  673. {
  674. int max, num, i;
  675. dfunction_t *best, *f;
  676. num = 0;
  677. do {
  678. max = 0;
  679. best = NULL;
  680. for (i = 0; i < pr->progs->numfunctions; i++) {
  681. f = &pr->pr_functions[i];
  682. if (f->profile > max) {
  683. max = f->profile;
  684. best = f;
  685. }
  686. }
  687. if (best) {
  688. if (num < 10)
  689. Sys_Printf ("%7i %s\n", best->profile,
  690. PR_GetString (pr, best->s_name));
  691. num++;
  692. best->profile = 0;
  693. }
  694. } while (best);
  695. }
  696. /*
  697. ED_Print
  698. For debugging
  699. */
  700. void
  701. ED_Print (progs_t *pr, edict_t *ed)
  702. {
  703. int l;
  704. unsigned int i;
  705. const char *name;
  706. int type;
  707. ddef_t *d;
  708. pr_type_t *v;
  709. if (ed->free) {
  710. Sys_Printf ("FREE\n");
  711. return;
  712. }
  713. Sys_Printf ("\nEDICT %i:\n", NUM_FOR_BAD_EDICT (pr, ed));
  714. for (i = 0; i < pr->progs->numfielddefs; i++) {
  715. d = &pr->pr_fielddefs[i];
  716. if (!d->s_name) // null field def (probably 1st)
  717. continue;
  718. name = PR_GetString (pr, d->s_name);
  719. if (name[strlen (name) - 2] == '_')
  720. continue; // skip _x, _y, _z vars
  721. v = ed->v + d->ofs;
  722. // if the value is still all 0, skip the field
  723. type = d->type & ~DEF_SAVEGLOBAL;
  724. switch (type) {
  725. case ev_entity:
  726. case ev_integer:
  727. case ev_uinteger:
  728. case ev_pointer:
  729. case ev_func:
  730. case ev_field:
  731. if (!v->integer_var)
  732. continue;
  733. break;
  734. case ev_sel:
  735. if (!v[0].integer_var
  736. && !PR_GetString (pr, v[1].string_var)[0])
  737. continue;
  738. break;
  739. case ev_string:
  740. if (PR_StringValid (pr, v->string_var))
  741. if (!PR_GetString (pr, v->string_var)[0])
  742. continue;
  743. break;
  744. case ev_float:
  745. if (!v->float_var)
  746. continue;
  747. break;
  748. case ev_vector:
  749. if (!v[0].float_var && !v[1].float_var && !v[2].float_var)
  750. continue;
  751. break;
  752. default:
  753. PR_Error (pr, "ED_Print: Unhandled type %d", type);
  754. }
  755. Sys_Printf ("%s", name);
  756. l = strlen (name);
  757. while (l++ < 15)
  758. Sys_Printf (" ");
  759. Sys_Printf ("%s\n", value_string (pr, d->type, v));
  760. }
  761. }