SCI: Expand kernel breakpoint pattern matching for negative matches

See matchKernelBreakpointPattern() for samples. The main envisioned use is

DoSound*,!DoSoundUpdateCues

to match all DoSound sub-functions except DoSoundUpdateCues.
This commit is contained in:
Willem Jan Palenstijn 2017-05-28 22:39:41 +02:00
parent e7b6a257b9
commit c7d631cb66
3 changed files with 56 additions and 14 deletions

View File

@ -3993,6 +3993,9 @@ bool Console::cmdBreakpointKernel(int argc, const char **argv) {
debugPrintf("Sets a breakpoint on execution of a kernel function.\n");
debugPrintf("Usage: %s <name> [<action>]\n", argv[0]);
debugPrintf("Example: %s DrawPic\n", argv[0]);
debugPrintf(" %s DoSoundPlay,DoSoundStop\n", argv[0]);
debugPrintf(" %s DoSound*\n", argv[0]);
debugPrintf(" %s DoSound*,!DoSoundUpdateCues\n", argv[0]);
debugPrintf(" %s DrawPic log\n", argv[0]);
debugPrintf("See bp_action usage for possible actions.\n");
return true;
@ -4008,11 +4011,7 @@ bool Console::cmdBreakpointKernel(int argc, const char **argv) {
}
// Check if any kernel functions match, to catch typos
Common::String name = argv[1];
bool wildcard = name.lastChar() == '*';
Common::String prefix = name;
if (wildcard)
prefix.deleteLastChar();
Common::String pattern = argv[1];
bool found = false;
const Kernel::KernelFunctionArray &kernelFuncs = _engine->getKernel()->_kernelFuncs;
for (uint id = 0; id < kernelFuncs.size() && !found; id++) {
@ -4020,14 +4019,14 @@ bool Console::cmdBreakpointKernel(int argc, const char **argv) {
const KernelSubFunction *kernelSubCall = kernelFuncs[id].subFunctions;
if (!kernelSubCall) {
Common::String kname = kernelFuncs[id].name;
if (name == kname || (wildcard && kname.hasPrefix(prefix)))
if (matchKernelBreakpointPattern(pattern, kname))
found = true;
} else {
uint kernelSubCallCount = kernelFuncs[id].subFunctionCount;
for (uint subId = 0; subId < kernelSubCallCount; subId++) {
if (kernelSubCall->name) {
Common::String kname = kernelSubCall->name;
if (name == kname || (wildcard && kname.hasPrefix(prefix)))
if (matchKernelBreakpointPattern(pattern, kname))
found = true;
}
kernelSubCall++;
@ -4036,13 +4035,13 @@ bool Console::cmdBreakpointKernel(int argc, const char **argv) {
}
}
if (!found) {
debugPrintf("No kernel functions match %s.\n", name.c_str());
debugPrintf("No kernel functions match %s.\n", pattern.c_str());
return true;
}
Breakpoint bp;
bp._type = BREAK_KERNEL;
bp._name = name;
bp._name = pattern;
bp._action = action;
_debugState._breakpoints.push_back(bp);

View File

@ -30,6 +30,8 @@
#include "sci/engine/script.h"
#include "sci/engine/scriptdebug.h"
#include "common/algorithm.h"
namespace Sci {
//#define VM_DEBUG_SEND
@ -782,6 +784,49 @@ bool SciEngine::checkAddressBreakpoint(const reg32_t &address) {
return found;
}
bool matchKernelBreakpointPattern(const Common::String &pattern, const Common::String &name) {
// Pattern:
// A comma-separated list of atoms.
// An atom is a (possibly empty) word, optionally with a ! prefix (for
// a negative-match), and/or a * suffix (for a prefix-match).
// The last matching atom in the pattern takes effect.
// Examples:
// FrameOut : matches only FrameOut
// * : matches everything
// *,!FrameOut : matches everything except FrameOut
// InitBresen,DoBresen : matches InitBresen and DoBresen
// DoSound*,!DoSoundUpdateCues : matches all DoSound sub-functions except
// DoSoundUpdateCues
bool result = false;
Common::String::const_iterator i = pattern.begin();
while (i != pattern.end()) {
Common::String::const_iterator next = Common::find(i, pattern.end(), ',');
bool negative = *i == '!';
if (negative)
i++;
Common::String atom(i, next - i);
bool wildcard = atom.lastChar() == '*';
if (wildcard)
atom.deleteLastChar();
if ((!wildcard && atom == name) || (wildcard && name.hasPrefix(atom)))
result = !negative;
i = next;
if (i != pattern.end())
++i; // skip comma
}
return result;
}
bool SciEngine::checkKernelBreakpoint(const Common::String &name) {
if (!(_debugState._activeBreakpointTypes & BREAK_KERNEL))
return false;
@ -793,11 +838,7 @@ bool SciEngine::checkKernelBreakpoint(const Common::String &name) {
if (bp->_action == BREAK_NONE || bp->_type != BREAK_KERNEL)
continue;
bool wildcard = bp->_name.lastChar() == '*';
Common::String prefix = bp->_name;
if (wildcard)
prefix.deleteLastChar();
if (bp->_name == name || (wildcard && name.hasPrefix(prefix))) {
if (matchKernelBreakpointPattern(bp->_name, name)) {
if (bp->_action == BREAK_BREAK) {
if (!found)
_console->debugPrintf("Break on k%s\n", name.c_str());

View File

@ -39,6 +39,8 @@ void logBacktrace();
bool printObject(reg_t obj);
bool matchKernelBreakpointPattern(const Common::String &pattern, const Common::String &name);
}
#endif