Debugging
in Dead Souls
So you've
made some cool stuff but darn it, it doesn't work. There are
various
tools
available in the Dead Souls lib to hunt down the source of the
problem:
1 elog
2
dbxframe and dbxwhere
3
tell_player() and debug()
4 tail
5 bk
and restore
elog
If the file is somewhere in your home directory, just type: elog
This will provide you a listing of the last few lines of your personal
error log. Warning lines tell you about code that works but should
be fixed in some way. Lines that don't contain the word "Warning" are
error lines: they indicate something about your code that prevents
it from working. For example:
> update
sample_room
---
*Error in loading object '/realms/cratylus/area/room/sample_room'
Object: /secure/cmds/creators/update at line 148
'<function>' at /secure/save/creators/c/cratylus (<function>) at /:0
'cmdAll' at /secure/save/creators/c/cratylus (/lib/command.c) at line 84
'cmd' at /secure/cmds/creators/update at line 109
'eventUpdate' at /secure/cmds/creators/update at line 148
'CATCH' at /secure/cmds/creators/update at line 148
Trace written to /log/catch
/realms/cratylus/area/room/sample_room: Error in update
*Error in loading object '/realms/cratylus/area/room/sample_room'
This output lets you know something is wrong, but
isn't very specific as to exactly what. If you look at your error
log, you probably will see something more detailed and helpful:
> elog
/log/errors/cratylus:
/realms/cratylus/area/room/sample_room.c line 10: Undefined variable 'Sample'
/realms/cratylus/area/room/sample_room.c line 10: parse error
Now you can see that the error is my syntax on
line 10. I would then use ed to examine the code, and specifically lines 9
through 11. It turns out that I forgot to put quotes around the room name,
so the parser tried to use it as a variable, which, of course, it couldn't.
If the file in question is in /secure, you'd type elog secure , or if
it's in /cmds, elog cmds , and so on.
dbxwhere & dbxframe
Two helpful debugging commands are dbxframe and dbxwhere. Let's
take a look at my broken sample_room.c file. We'll start with dbxwhere,
which lists for us the chain of events that led to the error. The
individual steps are called frames.
> dbxwhere
*Error in loading object '/realms/cratylus/area/room/sample_room'
Object: /secure/cmds/creators/update at line 148
#0: '<function>' at /secure/save/creators/c/cratylus (<function>) at /:0
#1: 'cmdAll' at /secure/save/creators/c/cratylus (/lib/command.c) at line 84
#2: 'cmd' at /secure/cmds/creators/update at line 109
#3: 'eventUpdate' at /secure/cmds/creators/update at line 148
#4: 'CATCH' at /secure/cmds/creators/update at line 148
The output is
similar to the update error we saw above, but in
enumerating the steps, dbxwhere
lets us use dbxframe to get
tighter detail on a given error frame:
> dbxframe
4
------
/secure/cmds/creators/update.c:148 - CATCH(0)
----------------------------------------------------------------
if( args == base_name(this_object()) ) {
this_player()->eventPrint("Cannot reload update after destruct.\n"
"It will be reloaded at next reference.");
return 0;
}
=>
tmp = catch(call_other(args, "???"));
if( !tmp ) {
if(identify(flags ^ U_AUTOMATED) ==
"8")this_player()->eventPrint(args + ": Ok");
return 1;
} else this_player()->eventPrint(args + ": Error in update\n" + tmp);
return 0;
We're now looking at the error context for error
frame 4. The output of the command shows
us part of
the file that was performing the evaluation when the error
occurred, and even
points out
the offending line using a text arrow: =>
In this particular case, the information is not that
helpful. We are being told that
the error
occurred while we were using the update command, and it
failed at the line
where update
does its thing. Duh, we knew that. The elog command was much
more helpful.
Where this kind of tracing comes in handy is when
you encounter a runtime error
when you're
not updating a file. For example, if I tried to enter that
room, rather than
update it,
I'd get a big pukey error message and not know why. If you
run into an
unexpected
error, dbxwhere
will help you pinpoint it if elog
doesn't provide useful information,
and dbxframe will help detail
the source of the problem.
tell_player(),
debug()
Sometimes it's hard to fix code if you don't know
what it's doing. In
the above example, you might want to know what the variable "args" is,
if
your code is behaving unexpectedly. You could find out by adding a line
like:
tell_player("cratylus", "args is:
"+identify(args));
or:
tell_player("cratylus",
"%^BLUE%^args
is: "+identify(args)+"%^RESET%^");
You could also use:
debug("args is: ", args);
or:
debug("args is: ", args,
"blue");
...which has the advantage of being shorter to type
and you'll get
the message more promptly. To be able to receive debug messages,
you need to enable your debugging mode by typing:
debug on
debug() is available in 2.0r20 and above.
tail
This is a version of the unix tail command. It
displays the last few lines of a file.
This command
is important for examining crucial log files:
tail
/log/catch
tail /log/runtime
tail
/log/player_errors
bk
& restore
These commands
aren't so much for debugging as they
are for safe coding. Before you
edit a file,
it is a very good idea to back it up first. The bk command lets you
quickly and
conveniently back up a file before you edit it. When I
typed:
bk
sample_room
A file with a
unique identifying number was created in my bak/
directory. If I
were to type
it again, then sample_room.c would get copied again to
bak/, with
a new unique
number added to the name.
The number is basically the number of seconds
elapsed since January 1, 1970.
Adding this
number, we can keep track of which backed up version of a
file
is most
recent by looking at the name.
Suppose I edited a file called sample_npc.c. I use
bk to back it up, make some changes,
then use bk
again, make some more changes, but now it won't update. I
don't
feel like
debugging, I just need this file working again, so I want to
restore from
backup. The
sequence of commands would look something like this:
ed
sample_npc.c
bk
sample_npc
ed
sample_npc.c
update
sample_npc.c
<error
occurs here>
restore
sample_npc
The reason identifying numbers are used is that you
can also choose to
restore the
second-to-last backup version of a file, and other previous
versions.
The very last backup version is effectively version
0, so it's not
necessary to
specify a number. If I wanted to restore the version I
backed
up before
that one, I would type something like this:
restore
sample_npc 1
And if I wanted the version before that one, I'd
specify 2 instead of 1,
and so on.
Please note that this is an intentionally simple
system. There are
no menus, no
version branches, or diff tracking. The reason for this is
that it is
not a versioning
system. It is a backup
system. It is a convenient
tool to back
out of screwups, not a development tool to test file
versions.
Dead Souls Homepage