views:

413

answers:

11

I would like to do something like a simple and quick general console debugger. This small lib should be embedded to the main program.

So I would like to do stuff like this while running the program in console mode:

"input: print i" "output: 15.53" "input: set color 255" "input: print color" "output: 255"

And both "i" and "color" would be pre-declared variables in-code. Its not an interpreter, just a handy way to check and modify variables contents.

GDB isn't a valid solution for my problem since I will use this code for computer graphics programs that I will code, so it need to be able to run in "Release Mode".

One very simple solution I have found so far is to just make a list of a structs that contains a void pointer, the pointer data type and a string which represents the variable name. But it wouldn't be as automatic as I imagine it could be.

Is there any way to convert a string, lets say "color", to obtain the address of the integer variable named color in C++? If not, how could I solve the problem?

+3  A: 

Variable names are for the programmer, and C++ doesn't store meta-data. (Data about the source code). You cannot access a variable by name at run-time.

That said, you could use something like std::map or unordered_map (either tr1 or boost), which gives you a key and value. The problem is that the value must be homogeneous in a container. This could be alleviated with the use of Boost.Any.

GMan
You'd want to store the type anyway, as the script statement "foo=7" needs to be interpreted differently depending on the type of foo - int, float or even string? `boost::variant<>` is a better choice; you can enumerate all types your scripting language supports.
MSalters
+2  A: 

No, you can't do this. Once you compile the source code into binary form and strip it of its symbols, there is no record of the human-readable names in the binary.

One option in C++ would be to use a std::map from std::string to whatever data type your variables are. You could then refer to my_map["my_variable_name"] = new_value. But this involves a not-insignificant performance impact and isn't a good idea in most cases.

James McNellis
+1  A: 

AFAIK, there is no general solution to this. You could use debugging information generated by the compiler to do this. Obviously, you would have to include debugging information even in release builds. And you would have to figure out the format of these debugging information for your particular platform/compiler, read it, parse it, etc...

I think, the way you mentioned (explicitly declaring the locations you want to access from your "debugger") seems the best way to go here. You can use macros as syntactic sugar, in order to ease the burden somewhat:

struct descriptor {
    const char* name;
    const char* type;
};

#define DEFGLOBAL(type, name) \
    static struct descriptor name ## _descriptor = { \
         # name, # type \
    }; \
    type name

DEFGLOBAL(int, some_number);

I'd recommend having a look at the Emacs source code. They do something along the above lines to export C variables to the Lisp interpreter. They also use it to export primitive functions, etc. to Lisp level.

Dirk
+1  A: 

Work hard or use Lua. Links:

Andrejs Cainikovs
A: 

You could optimize it and build it with debugging symbols(possible in GCC) and then figure out how to read the debugging symbols and such to debug yourself just like gdb would.. but that really seems like overkill.. Are you sure this is a viable design and that your using the proper language to do such a thing? When exactly will this console debugger ever be used?

Earlz
+4  A: 

You may not be aware of this idiom, which may make it easier for you to implement this:

#include <stdio.h>
#define REPORT(V) printf("%s: %i\n", #V, V);
int main() {
  int i = 5;
  REPORT(i);
  return 0;
}

Output is

i: 5
Grumdrig
The problem is, if it's not an int you want to print, then the `%i` won't work.
Matthieu M.
Minor detail, easily solved by using C++. E.g. `std::clog << (#V) << (V) << std::endl`
MSalters
+4  A: 

Not for the feint of heart, but you can use dlopen and dlsym to get the address of globally declared variables.

Keith Randall
A: 

The simple solution of which you have thought is essentially the only solution available for non-debug C/C++ code. However, I think there are two stumbling blocks you should consider:

  1. You will only be able to observe global variables. Any local variables in your functions will not be available to your inspector, since those stack frames will not exist when you process input from the command line, presumably as part of a top-level processing loop. (Unless you process command line input in every function, which I would not recommend, and in which case you would never know what function's stack frame would be inspected when you typed your command.)
  2. You will prevent the compiler from making certain register optimizations. If your code ever takes the address of a variable (e.g. to include a pointer to that variable in your inspector's symbol table), then the compiler must place that variable at a memory location, even when it would otherwise keep that variable solely in a register for speed.
Matthew Xavier
+1  A: 

You can use GDB with an external symbol file (symbol-file command). So if you build your executable with it's debug info in an external file, you don't even have to write your own debugger... Just don't forget to bring the symbol file when you go debug a customer's installed executable.

xtofl
A: 

An alternative for Lua would be to use Boost::Python; it too allows you to create a quick-n-dirty script API.

MSalters
A: 

What makes you think you can't run GDB in "release mode"? What GDB relies on to identify variables are the debug symbols, and they can be built regardless of what other compiler flags are specified. You can enable optimizations and everything else that constitutes your "release mode", and still produce debug symbols for GDB to use.

jalf