print out source line numbers when available

This commit is contained in:
Bill Currie 2001-07-14 23:53:59 +00:00
parent 6e06ecc461
commit 66c8f00dc7
6 changed files with 353 additions and 5 deletions

View file

@ -32,7 +32,7 @@
#ifndef __pr_debug_h
#define __pr_debug_h
typedef struct {
typedef struct pr_auxfunction_s {
unsigned long function; // function def this aux info is for
unsigned long source_line; // first source line for this function
unsigned long line_info; // index to first lineno entry
@ -40,7 +40,7 @@ typedef struct {
unsigned long num_locals; // number of local defs
} pr_auxfunction_t;
typedef struct {
typedef struct pr_lineno_s {
union {
unsigned long func; // (line==0) index of function aux info
unsigned long addr; // (line!=0) dstatement_t address
@ -50,7 +50,7 @@ typedef struct {
#define PROG_DEBUG_VERSION 0x00001001 // MMmmmRRR 0.001.001 (hex)
typedef struct {
typedef struct pr_debug_header_s {
int version;
unsigned short crc; // of the progs.dat this progs.sym file is for
unsigned short you_tell_me_and_we_will_both_know;

View file

@ -32,6 +32,7 @@
#include "QF/link.h"
#include "QF/vfile.h"
#include "QF/pr_comp.h"
#include "QF/pr_debug.h"
typedef union pr_type_u {
float float_var;
@ -71,6 +72,7 @@ void PR_PrintStatement (progs_t * pr, dstatement_t *s);
void PR_ExecuteProgram (progs_t *pr, func_t fnum);
void PR_LoadProgs (progs_t *pr, char *progsname);
void PR_LoadStrings (progs_t *pr);
void PR_LoadDebug (progs_t *pr);
edict_t *PR_InitEdicts (progs_t *pr, int num_edicts);
void PR_Profile_f (void);
@ -153,13 +155,27 @@ char *PR_GlobalStringNoContents (progs_t *pr, int ofs);
pr_type_t *GetEdictFieldValue(progs_t *pr, edict_t *ed, char *field);
//
// PR STrings stuff
// PR Strings stuff
//
char *PR_GetString(progs_t *pr, int num);
int PR_SetString(progs_t *pr, char *s);
void PR_GarbageCollect (progs_t *pr);
//
// PR Debug stuff
//
void PR_Debug_Init (void);
void PR_Debug_Init_Cvars (void);
pr_auxfunction_t *PR_Get_Lineno_Func (progs_t *pr, pr_lineno_t *lineno);
unsigned long PR_Get_Lineno_Addr (progs_t *pr, pr_lineno_t *lineno);
unsigned long PR_Get_Lineno_Line (progs_t *pr, pr_lineno_t *lineno);
pr_lineno_t *PR_Find_Lineno (progs_t *pr, unsigned long addr);
const char *PR_Get_Source_File (progs_t *pr, pr_lineno_t *lineno);
const char *PR_Get_Source_Line (progs_t *pr, unsigned long addr);
extern struct cvar_s *pr_debug;
//============================================================================
@ -179,6 +195,7 @@ typedef struct strref_s {
} strref_t;
struct progs_s {
char *progs_name;
dprograms_t *progs;
struct hashtab_s *function_hash;
@ -232,6 +249,13 @@ struct progs_s {
builtin_t *builtins;
int numbuiltins;
// debug info
char *debugfile;
struct pr_debug_header_s *debug;
struct pr_auxfunction_s *auxfunctions;
struct pr_lineno_s *linenos;
ddef_t *local_defs;
// required globals
struct {
float *time;

View file

@ -3,6 +3,6 @@ INCLUDES= -I$(top_srcdir)/include
lib_LTLIBRARIES = libQFgamecode.la
libQFgamecode_la_LDFLAGS = -version-info 1:0:0
libQFgamecode_la_SOURCES = pr_edict.c pr_exec.c pr_opcode.c pr_strings.c
libQFgamecode_la_SOURCES = pr_edict.c pr_debug.c pr_exec.c pr_opcode.c pr_strings.c
LIBLIST = libQFgamecode.la @LIBRARY_SEARCH_PATH@

312
libs/gamecode/pr_debug.c Normal file
View file

@ -0,0 +1,312 @@
/*
pr_debug.c
progs debugging
Copyright (C) 2001 Bill Currie <bill@tanwiha.org>
Author: Bill Currie <bill@tanwiha.org>
Date: 2001/7/13
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
$Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <stdlib.h>
#include "QF/cvar.h"
#include "QF/hash.h"
#include "QF/pr_debug.h"
#include "QF/progs.h"
#include "QF/qendian.h"
#include "QF/sys.h"
#include "QF/vfs.h"
#include "QF/zone.h"
typedef struct {
char *text;
size_t len;
} line_t;
typedef struct {
char *name;
char *text;
line_t *lines;
int num_lines;
} file_t;
cvar_t *pr_debug;
static hashtab_t *file_hash;
file_t *
PR_Load_Source_File (progs_t *pr, const char *fname)
{
file_t *f = Hash_Find (file_hash, fname);
char *l;
if (f)
return f;
f = malloc (sizeof (file_t));
if (!f)
return 0;
f->text = COM_LoadFile (fname, 0);
if (!f->text) {
free (f);
return 0;
}
for (f->num_lines = 1, l = f->text; *l; l++)
if (*l == '\n')
f->num_lines++;
f->name = strdup (fname);
if (!f->name) {
free (f->text);
free (f);
return 0;
}
f->lines = malloc (f->num_lines * sizeof (line_t));
if (!f->lines) {
free (f->name);
free (f->text);
free (f);
return 0;
}
f->lines[0].text = f->text;
for (f->num_lines = 0, l = f->text; *l; l++) {
if (*l == '\n') {
f->lines[f->num_lines].len = l - f->lines[f->num_lines].text;
f->lines[++f->num_lines].text = l + 1;
}
}
f->lines[f->num_lines++].len = l - f->lines[f->num_lines].text;
Hash_Add (file_hash, f);
return f;
}
void
PR_LoadDebug (progs_t *pr)
{
pr_type_t *str = PR_GetGlobalPointer (pr, ".debug_file");
int start = Hunk_LowMark ();
int i;
char *path_end;
char *sym_file;
char *sym_path;
Hash_FlushTable (file_hash);
if (!str)
return;
pr->debugfile = PR_GetString (pr, str->string_var);
sym_file = COM_SkipPath (pr->debugfile);
path_end = COM_SkipPath (pr->progs_name);
sym_path = Hunk_TempAlloc (strlen (sym_file) + (path_end - pr->progs_name) + 1);
strncpy (sym_path, pr->progs_name, path_end - pr->progs_name);
strcpy (sym_path + (path_end - pr->progs_name), sym_file);
pr->debug = (pr_debug_header_t*)COM_LoadHunkFile (sym_path);
if (!pr->debug) {
Sys_Printf ("can't load %s for debug info\n", sym_path);
return;
}
pr->debug->version = LittleLong (pr->debug->version);
if (pr->debug->version != PROG_DEBUG_VERSION) {
Sys_Printf ("ignoring %s with unsupported version %x.%03x.%03x\n",
sym_path,
(pr->debug->version >> 24) & 0xff,
(pr->debug->version >> 12) & 0xfff,
pr->debug->version & 0xfff);
Hunk_FreeToLowMark (start);
pr->debug = 0;
pr->auxfunctions = 0;
pr->linenos = 0;
pr->local_defs = 0;
return;
}
pr->debug->crc = LittleShort (pr->debug->crc);
if (pr->debug->crc != pr->crc) {
Sys_Printf ("ignoring %s that doesn't match %s. (crcs: sys:%d dat:%d)",
sym_path,
pr->progs_name,
pr->debug->crc,
pr->crc);
Hunk_FreeToLowMark (start);
pr->debug = 0;
pr->auxfunctions = 0;
pr->linenos = 0;
pr->local_defs = 0;
return;
}
pr->debug->you_tell_me_and_we_will_both_know = LittleShort (pr->debug->you_tell_me_and_we_will_both_know);
pr->debug->auxfunctions = LittleLong (pr->debug->auxfunctions);
pr->debug->num_auxfunctions = LittleLong (pr->debug->num_auxfunctions);
pr->debug->linenos = LittleLong (pr->debug->linenos);
pr->debug->num_linenos = LittleLong (pr->debug->num_linenos);
pr->debug->locals = LittleLong (pr->debug->locals);
pr->debug->num_locals = LittleLong (pr->debug->num_locals);
pr->auxfunctions = (pr_auxfunction_t*)((char*)pr->debug + pr->debug->auxfunctions);
pr->linenos = (pr_lineno_t*)((char*)pr->debug + pr->debug->linenos);
pr->local_defs = (ddef_t*)((char*)pr->debug + pr->debug->locals);
for (i = 0; i < pr->debug->num_auxfunctions; i++) {
pr->auxfunctions[i].function = LittleLong (pr->auxfunctions[i].function);
pr->auxfunctions[i].source_line = LittleLong (pr->auxfunctions[i].source_line);
pr->auxfunctions[i].line_info = LittleLong (pr->auxfunctions[i].line_info);
pr->auxfunctions[i].local_defs = LittleLong (pr->auxfunctions[i].local_defs);
pr->auxfunctions[i].num_locals = LittleLong (pr->auxfunctions[i].num_locals);
}
for (i = 0; i < pr->debug->num_linenos; i++) {
pr->linenos[i].fa.func = LittleLong (pr->linenos[i].fa.func);
pr->linenos[i].line = LittleLong (pr->linenos[i].line);
}
for (i = 0; i < pr->debug->num_locals; i++) {
pr->local_defs[i].type = LittleShort (pr->local_defs[i].type);
pr->local_defs[i].ofs = LittleShort (pr->local_defs[i].ofs);
pr->local_defs[i].s_name = LittleLong (pr->local_defs[i].s_name);
}
}
pr_auxfunction_t *
PR_Get_Lineno_Func (progs_t *pr, pr_lineno_t *lineno)
{
while (lineno > pr->linenos && lineno->line)
lineno--;
if (lineno->line)
return 0;
return &pr->auxfunctions[lineno->fa.func];
}
unsigned long
PR_Get_Lineno_Addr (progs_t *pr, pr_lineno_t *lineno)
{
pr_auxfunction_t *f;
if (lineno->line)
return lineno->fa.addr;
f = &pr->auxfunctions[lineno->fa.func];
return pr->pr_functions[f->function].first_statement;
}
unsigned long
PR_Get_Lineno_Line (progs_t *pr, pr_lineno_t *lineno)
{
pr_auxfunction_t *f;
if (lineno->line)
return lineno->line;
f = &pr->auxfunctions[lineno->fa.func];
return f->source_line;
}
pr_lineno_t *
PR_Find_Lineno (progs_t *pr, unsigned long addr)
{
pr_lineno_t *lineno = 0;
int i;
if (!pr->debug)
return 0;
if (!pr->debug->num_linenos)
return 0;
for (i = pr->debug->num_linenos - 1; i >= 0; i--) {
if (PR_Get_Lineno_Addr (pr, &pr->linenos[i]) <= addr) {
lineno = &pr->linenos[i];
break;
}
}
return lineno;
}
const char *
PR_Get_Source_File (progs_t *pr, pr_lineno_t *lineno)
{
pr_auxfunction_t *f;
f = PR_Get_Lineno_Func (pr, lineno);
return PR_GetString(pr, pr->pr_functions[f->function].s_file);
}
const char *
PR_Get_Source_Line (progs_t *pr, unsigned long addr)
{
pr_auxfunction_t *func;
const char *fname;
unsigned long line;
char *str;
file_t *file;
pr_lineno_t *lineno = PR_Find_Lineno (pr, addr);
if (!lineno || PR_Get_Lineno_Addr (pr, lineno) != addr)
return 0;
func = PR_Get_Lineno_Func (pr, lineno);
fname = PR_Get_Source_File (pr, lineno);
if (!func || !fname)
return 0;
line = PR_Get_Lineno_Line (pr, lineno);
line += func->source_line;
str = Hunk_TempAlloc (strlen (fname) + 12);
sprintf (str, "%s:%ld", fname, line);
file = PR_Load_Source_File (pr, fname);
if (!file || line > file->num_lines)
return str;
str = Hunk_TempAlloc (strlen (str) + file->lines[line - 1].len + 2);
sprintf (str, "%s:%ld:%.*s", fname, line,
(int)file->lines[line - 1].len, file->lines[line - 1].text);
return str;
}
static const char *
file_get_key (void *_f, void *unused)
{
return ((file_t*)_f)->name;
}
static void
file_free (void *_f, void *unused)
{
file_t *f = (file_t*)_f;
free (f->lines);
free (f->text);
free (f->name);
free (f);
}
void
PR_Debug_Init (void)
{
file_hash = Hash_NewTable (1024, file_get_key, file_free, 0);
}
void
PR_Debug_Init_Cvars (void)
{
pr_debug = Cvar_Get ("pr_debug", "0", CVAR_NONE, NULL,
"enable progs debugging");
}

View file

@ -1039,6 +1039,8 @@ PR_LoadProgs (progs_t * pr, char *progsname)
PR_Error (pr, "%s has unrecognised version number (%08x)",
progsname, pr->progs->version);
pr->progs_name = progsname; //XXX is this safe?
pr->pr_functions =
(dfunction_t *) ((byte *) pr->progs + pr->progs->ofs_functions);
pr->pr_strings = (char *) pr->progs + pr->progs->ofs_strings;
@ -1129,6 +1131,8 @@ PR_LoadProgs (progs_t * pr, char *progsname)
// initialise the strings managment code
PR_LoadStrings (pr);
PR_LoadDebug (pr);
// LordHavoc: bounds check anything static
for (i = 0, st = pr->pr_statements; i < pr->progs->numstatements; i++, st++) {
switch (st->op) {
@ -1280,12 +1284,14 @@ PR_Init_Cvars (void)
"Server progs bounds checking");
pr_deadbeef = Cvar_Get ("pr_deadbeef", "0", CVAR_NONE, NULL,
"set to clear unallocated memory ot 0xdeadbeef");
PR_Debug_Init_Cvars ();
}
void
PR_Init (void)
{
PR_Opcode_Init ();
PR_Debug_Init ();
}
edict_t *

View file

@ -58,6 +58,12 @@ PR_PrintStatement (progs_t * pr, dstatement_t *s)
int addr = s - pr->pr_statements;
opcode_t *op;
if (pr_debug->int_val) {
const char *source_line = PR_Get_Source_Line (pr, addr);
if (source_line)
Con_Printf ("%s\n", source_line);
}
Con_Printf ("%-7d ", addr);
op = PR_Opcode (s->op);
if (op) {