X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fcommandinterpreter.cpp;h=367ac17f9651684e98113d472140cc1b23e4a4d2;hb=de6ac03ffc36843bbbb0d496007b3046a4422ee1;hp=71e8ee7a001b7eafc14b1ec4f014ff47a48bac84;hpb=c6b2f7585d51164dc32f4dd2a05855913e464c58;p=gldbg.git diff --git a/source/commandinterpreter.cpp b/source/commandinterpreter.cpp index 71e8ee7..367ac17 100644 --- a/source/commandinterpreter.cpp +++ b/source/commandinterpreter.cpp @@ -1,15 +1,19 @@ /* $Id$ This file is part of gldbg -Copyright © 2009 Mikko Rasa, Mikkosoft Productions +Copyright © 2009-2010 Mikko Rasa, Mikkosoft Productions Distributed under the GPL */ +#include +#include #include #include #include #include +#include #include "commandinterpreter.h" +#include "enums.h" #include "gldbg.h" #include "tracer.h" @@ -19,14 +23,66 @@ using namespace Msp; CommandInterpreter::CommandInterpreter(GlDbg &d): gldbg(d) { - commands["run"] = &CommandInterpreter::cmd_run; - commands["continue"] = &CommandInterpreter::cmd_continue; - commands["c"] = &CommandInterpreter::cmd_continue; - commands["kill"] = &CommandInterpreter::cmd_kill; - commands["signal"] = &CommandInterpreter::cmd_signal; - commands["exit"] = &CommandInterpreter::cmd_exit; - commands["quit"] = &CommandInterpreter::cmd_exit; - commands["trace"] = &CommandInterpreter::cmd_trace; + register_command("help", this, &CommandInterpreter::cmd_help) + .set_help("Provides help on commands", + "help\n" + " Displays a list of commands\n\n" + "help COMMAND\n" + " Gives detailed information on a command\n"); + register_command("exit", this, &CommandInterpreter::cmd_exit) + .set_help("Ends the debugging session"); + commands["quit"] = new CommandAlias(commands["exit"]); + + register_command("run", this, &CommandInterpreter::cmd_run) + .set_help("Starts the program"); + register_command("continue", this, &CommandInterpreter::cmd_continue) + .set_help("Resumes program execution"); + register_command("kill", this, &CommandInterpreter::cmd_kill) + .set_help("Terminates the program immediately"); + register_command("signal", this, &CommandInterpreter::cmd_signal) + .set_help("Resumes execution with a signal", + "signal NUM\n" + "signal NAME\n" + " Sends the signal identified by NUM or NAME to the program and resumes\n" + " execution. Currently recognized signal names are HUP, INT, TERM, SEGV\n" + " and TERM.\n"); + + register_command("trace", this, &CommandInterpreter::cmd_trace) + .set_help("Traces GL function calls", + "trace\n" + " Send trace output to stdout.\n\n" + "trace FILE\n" + " Send trace output to FILE (- for stdout).\n\n" + "trace {off|on}\n" + " Temporarily suspend or resume trace without closing the file.\n\n" + "trace end\n" + " Terminate trace, closing the file.\n"); + + register_command("profile", this, &CommandInterpreter::cmd_profile) + .set_help("Profiles GL usage and performance", + "profile {on|off}\n" + " Enables or disables profiling\n"); + + register_command("state", this, &CommandInterpreter::cmd_state) + .set_help("Inspects general GL state", + "state vertex\n" + " Print current vertex attributes\n\n" + "state bind\n" + " Show current bindings\n"); + + register_command("texture", this, &CommandInterpreter::cmd_texture) + .set_help("Inspect texture state", + "texture\n" + " Lists texture objects\n\n" + "texture ID\n" + " Print information about a texture object\n"); + + register_command("buffer", this, &CommandInterpreter::cmd_buffer) + .set_help("Inspect buffer object state", + "buffer\n" + " Lists buffer objects\n\n" + "buffer ID\n" + " Print information about a buffer object\n"); } void CommandInterpreter::execute(const string &cmd) @@ -47,9 +103,32 @@ void CommandInterpreter::execute(const string &cmd) if(space!=string::npos) args = cmd.substr(space+1); - (this->*(i->second))(args); + i->second->execute(args); } +void CommandInterpreter::cmd_help(const string &args) +{ + if(args.empty()) + { + for(CommandMap::const_iterator i=commands.begin(); i!=commands.end(); ++i) + if(!dynamic_cast(i->second)) + IO::print("%-10s : %s\n", i->first, i->second->get_description()); + } + else + { + CommandMap::const_iterator i = commands.find(args); + if(i==commands.end()) + throw KeyError("Unknown command", args); + + const Command *cmd = i->second; + while(const CommandAlias *alias = dynamic_cast(cmd)) + cmd = alias->get_target(); + + IO::print("%s : %s\n", i->first, cmd->get_description()); + if(!cmd->get_help().empty()) + IO::print("\n%s", cmd->get_help()); + } +} void CommandInterpreter::cmd_run(const string &) { @@ -58,12 +137,28 @@ void CommandInterpreter::cmd_run(const string &) void CommandInterpreter::cmd_continue(const string &) { + IO::print("Continuing.\n"); gldbg.get_process().resume(); } void CommandInterpreter::cmd_signal(const string &args) { - gldbg.get_process().resume(lexical_cast(args)); + unsigned sig = 0; + if(args=="HUP" || args=="SIGHUP") + sig = SIGHUP; + else if(args=="INT" || args=="SIGINT") + sig = SIGINT; + else if(args=="ILL" || args=="SIGILL") + sig = SIGILL; + else if(args=="SEGV" || args=="SIGSEGV") + sig = SIGSEGV; + else if(args=="TERM" || args=="SIGTERM") + sig = SIGTERM; + else if(isnumrc(args)) + sig = lexical_cast(args); + else + throw InvalidParameterValue("Invalid signal specification"); + gldbg.get_process().resume(sig); } void CommandInterpreter::cmd_kill(const string &) @@ -73,42 +168,252 @@ void CommandInterpreter::cmd_kill(const string &) void CommandInterpreter::cmd_exit(const string &) { - gldbg.quit(); + if(gldbg.get_process().get_state()!=Process::INACTIVE) + { + IO::print("Program is still running. Kill it?\n"); + char *answer = readline("[y/n] "); + if(answer[0]=='y') + { + gldbg.get_process().kill(); + gldbg.quit(true); + } + else + IO::print("Not confirmed.\n"); + } + else + gldbg.quit(false); } void CommandInterpreter::cmd_trace(const string &args) { Tracer &tracer = gldbg.get_tracer(); - if(args[0]=='>') + if(args.empty() || args=="-") + { + tracer.set_output(IO::cout); + IO::print("Tracing to stdout\n"); + } + else if(args=="on") + { + tracer.enable(); + IO::print("Tracing enabled\n"); + } + else if(args=="off") + { + tracer.disable(); + IO::print("Tracing disabled\n"); + } + else if(args=="end") + { + tracer.set_output(0); + IO::print("Tracing terminated\n"); + } + else + { + tracer.set_output(new IO::File(args, IO::M_WRITE)); + IO::print("Tracing to %s\n", args); + } +} + +void CommandInterpreter::cmd_profile(const string &args) +{ + Profiler &profiler = gldbg.get_profiler(); + if(args.empty() || args=="on") + profiler.enable(); + else if(args=="off") + profiler.disable(); + else + throw InvalidParameterValue("Invalid argument"); +} + +void CommandInterpreter::cmd_state(const string &args) +{ + const GlState &glstate = gldbg.get_glstate(); + if(args=="vertex") { - string fn = args.substr(1); - if(fn=="-") + IO::print("Current vertex attributes:\n"); + const Vector4 &color = glstate.get_color(); + IO::print(" Color: [%05.3f, %05.3f, %05.3f, %05.3f]\n", color.r, color.g, color.b, color.a); + for(unsigned i=0; i<8; ++i) { - tracer.set_output(IO::cout); - IO::print("Tracing to stdout\n"); + const Vector4 &texcoord = glstate.get_texcoord(i); + IO::print(" TexCoord%d: [%05.3f, %05.3f, %05.3f, %05.3f]\n", i, texcoord.s, texcoord.t, texcoord.p, texcoord.q); } - else + const Vector3 &normal = glstate.get_normal(); + IO::print(" Normal: [%05.3f, %05.3f, %05.3f]\n", normal.x, normal.y, normal.z); + } + else if(args=="bind") + { + IO::print("Current bindings:\n"); + for(unsigned i=0; i<8; ++i) { - tracer.set_output(new IO::File(fn, IO::M_WRITE)); - IO::print("Tracing to %s\n", fn); + IO::print(" Texture unit %d:\n", i); + const TexUnitState &unit = glstate.get_texture_unit(i); + IO::print(" GL_TEXTURE_2D: %s\n", unit.describe_binding(GL_TEXTURE_2D)); + IO::print(" GL_TEXTURE_3D: %s\n", unit.describe_binding(GL_TEXTURE_3D)); } + IO::print(" Buffers:\n"); + const BufferState *buf = glstate.get_current_buffer(GL_ARRAY_BUFFER); + IO::print(" GL_ARRAY_BUFFER: %d\n", (buf ? buf->id : 0)); + buf = glstate.get_current_buffer(GL_ELEMENT_ARRAY_BUFFER); + IO::print(" GL_ELEMENT_ARRAY_BUFFER: %d\n", (buf ? buf->id : 0)); } else + throw InvalidParameterValue("Invalid or missing argument"); +} + +void CommandInterpreter::cmd_texture(const string &args) +{ + if(args.empty()) { - if(args=="on") + const map &textures = gldbg.get_glstate().get_textures(); + IO::print("%d texture objects:\n", textures.size()); + for(map::const_iterator i = textures.begin(); i!=textures.end(); ++i) { - tracer.enable(); - IO::print("Tracing enabled\n"); + const TextureState &tex = i->second; + IO::print(" %d: %s, %d images\n", i->first, tex.describe(), tex.images.size()); } - else if(args=="off") + } + else + { + unsigned id = lexical_cast(args); + const TextureState &tex = gldbg.get_glstate().get_texture(id); + IO::print("Texture object %d\n", id); + IO::print(" Target: %s\n", describe_enum(tex.target, "TextureTarget")); + IO::print(" Images:\n"); + for(unsigned i=0; ifirst, i->second.describe()); + } + else + { + unsigned id = lexical_cast(args); + const BufferState &buf = gldbg.get_glstate().get_buffer(id); + IO::print("Buffer %d:\n", id); + IO::print(" Size: %d bytes\n", buf.size); + IO::print(" Usage: %s\n", describe_enum(buf.usage, "")); + if(buf.content.stride) { - tracer.set_output(0); - IO::print("Tracing terminated\n"); + IO::print(" Stride: %d bytes\n", buf.content.stride); + + IO::print(" Arrays:\n"); + const vector &arrays = buf.content.arrays; + for(vector::const_iterator i=arrays.begin(); i!=arrays.end(); ++i) + { + if(i->kind) + IO::print(" %2d: %s, %d %s\n", i->offset, + describe_enum(i->kind, ""), i->size, describe_enum(i->type, "DataType")); + else + IO::print(" %2d: Attrib %d, %d %s\n", i->offset, + i->index, i->size, describe_enum(i->type, "DataType")); + } + + IO::print(" Data:\n"); + string header; + for(vector::const_iterator i=arrays.begin(); i!=arrays.end(); ++i) + { + if(!header.empty()) + header += " | "; + + string label; + if(i->kind==GL_VERTEX_ARRAY) + label = "Vertex"; + else if(i->kind==GL_NORMAL_ARRAY) + label = "Normal"; + else if(i->kind==GL_COLOR_ARRAY) + label = "Color"; + else if(i->kind==GL_TEXTURE_COORD_ARRAY) + { + if(i->size==1) + label = "TexC"; + else + label = "TexCoord"; + } + else if(!i->kind) + { + if(i->size==1) + label = format("A %d", i->index); + else + label = format("Attrib %d", i->index); + } + + unsigned width = i->size; + if(i->type==GL_FLOAT) + width *= 5; + else if(i->type==GL_UNSIGNED_BYTE) + width *= 3; + width += i->size-1; + + header.append((width-label.size())/2, ' '); + header += label; + header.append((width-label.size()+1)/2, ' '); + } + IO::print(" %s\n", header); + + unsigned n_verts = buf.size/buf.content.stride; + for(unsigned i=0; i::const_iterator j=arrays.begin(); j!=arrays.end(); ++j) + { + if(!line.empty()) + line += " |"; + + const char *base = vertex+j->offset; + for(unsigned k=0; ksize; ++k) + { + if(j->type==GL_FLOAT) + line += format(" %5.2f", *(reinterpret_cast(base)+k)); + else if(j->type==GL_UNSIGNED_BYTE) + line += format(" %3u", *(reinterpret_cast(base)+k)); + } + } + + IO::print("%3d:%s\n", i, line); + } } } } + + +void CommandInterpreter::Command::set_help(const string &d) +{ + description = d; +} + +void CommandInterpreter::Command::set_help(const string &d, const string &h) +{ + description = d; + help = h; +} + + +CommandInterpreter::CommandAlias::CommandAlias(Command *t): + target(t) +{ } + +void CommandInterpreter::CommandAlias::execute(const string &a) +{ + target->execute(a); +}