Thanks Jens for your hints.
Here is a workaround.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
typedef vector<string> vstr;
int main()
{
vstr v;
v.push_back("bla bla");
string v0 = v[0];
cout << "Hello world!" << endl;
return 0;
}
I can only watch "v0" (see the screen shot)
[attachment deleted by admin]
Hi,
first of all, thank all for your help and replies to my question. Sorry for my delayed answer, but I am here in Calgary and -8h behind European time :)
However, here the code which I was using for testing:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
typedef vector<string> vstr;
int main()
{
vstr v;
v.push_back("1. bla bla");
v.push_back("2. bla bla");
v.push_back("3. bla bla");
int a[3] ={11, 22, 33};
for (unsigned int f = 0; f<3; f++)
{
cout <<" a[" << f <<"] = " << a[f];
cout << " and v[" << f << "] = " << v[f] << endl;
}
return 0;
}
I played around with "Add watches" and I was not able to get a similar debugger output of a string vector compared to the output of a normal array (see screen-shot-1.png).
The only thing which was working for the string vector was the "element view" i.e. "Add wachtes --> v[0] (see screen-shot-1.png).
But with this method you have to be very carefully, since if you enter a element which does not exist i.e. out of array range, you will get a "segmentation signal" from Code::Blocks. (see v[3] in "wachtes in screen-shot-1.png and signal in screen-shot-2.png). So for me this "element view" method is not a 100% good way, it is more a 80% provisional solution :)
However, it would be very convenient if the debugger would show the string vector similar like the array (see "a" in watches --> screen-shot-1.png).
Thanks
Martin
PS: @ Jens
special thanks to you for providing debian-repository for Code::Blocks.
I use Debain Lenny, and this is a very convenient way to be up to date with Code::Blocks nightly builds.
Small suggestion for your page http://apt.jenslody.de/ :
instead of this line:
--------------------------------------------------------------------------------------------
...The best and easiest way to add my public-key to apt's trustdb is to install the package jens-lody-debian-keyring with your preferred package-manager or apt-get. ....
--------------------------------------------------------------------------------------------
write it more explicitly like:
--------------------------------------------------------------------------------------------
... The best and easiest way to add my public-key to apt's trustdb is to install the package jens-lody-debian-keyring with
#apt-get-get install jens-lody-debian-keyring
or
#aptitude install jens-lody-debian-keyring
--------------------------------------------------------------------------------------------
Since most people do not read a web page they skim it.
[attachment deleted by admin]
You have to use the []-operator in your program, otherwise it gets not compiled in and therefore cannot be used by gdb.
Hi, Jens. Thanks for the reply.
I understand now. (Oh, My poor English, I need to read twice of these sentence to understand it's meaning :()
If I define v[0], then gdb can also understand v[1]. :D
#include <iostream>
#include <string>
#include <vector>
using namespace std;
typedef vector<string> vstr;
int main()
{
vstr v;
v.push_back("bla bla");
v.push_back("abcdef");
string v0 = v[0];
cout << "Hello world!" << endl;
return 0;
}
See my screen shot.
Edit:
Oh, taram has already mentioned that.
Edit2
If I just add "v" to "watch", then check on the "Watch as array" opiotion. I still can't view any contents. Seems GDB didn't regard "v" as an array beginning address.
We can only use "v[0], v[1]" instead. :D
[attachment deleted by admin]
Thanks, I'm trying to use this way on MinGW.
http://www.yolinux.com/TUTORIALS/GDB-Commands.html#STLDEREF
Not sure how to add "gdbinit", so, still Googling :D
Edit1:
In my cb debug start up, it the command line ( I copied from debug log output)
Command-line: D:\MinGW\bin\gdb.exe -nx -fullname -quiet -args bin/Debug/test_for_cb_forum.exe
Working dir : C:\test\test_for_cb_forum\
Seems there is default "-nx" options. :(
Edit2
I find in the "gdb_driver.cpp", these code "disable the .gdbinit related function".
wxString GDB_driver::GetCommandLine(const wxString& debugger, const wxString& debuggee)
{
wxString cmd;
cmd << debugger;
cmd << _T(" -nx"); // don't run .gdbinit
cmd << _T(" -fullname "); // report full-path filenames when breaking
cmd << _T(" -quiet"); // don't display version on startup
cmd << _T(" -args ") << debuggee;
return cmd;
}
wxString GDB_driver::GetCommandLine(const wxString& debugger, int pid)
{
wxString cmd;
cmd << debugger;
cmd << _T(" -nx"); // don't run .gdbinit
cmd << _T(" -fullname "); // report full-path filenames when breaking
cmd << _T(" -quiet"); // don't display version on startup
cmd << _T(" -pid=") << wxString::Format(_T("%d"), pid);
return cmd;
}
Hi, all, I can successfully view the vectors.
Here is the debug log output from "debugger (debug)" panel.
>>>>>>cb_gdb:
> pvector v
elem[0]: $1 = {
static npos = 4294967295,
_M_dataplus = {
<std::allocator<char>> = {
<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>},
members of std::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Alloc_hider:
_M_p = 0x3247c "bla bla"
}
}
elem[1]: $2 = {
static npos = 4294967295,
_M_dataplus = {
<std::allocator<char>> = {
<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>},
members of std::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Alloc_hider:
_M_p = 0x324ac "abcdef"
}
}
Vector size = 2
Vector capacity = 2
Element type = std::basic_string<char, std::char_traits<char>, std::allocator<char> > *
There are several steps:
1. copy the "stl-views-1.0.3.gdb (http://sourceware.org/gdb/wiki/STLSupport?action=AttachFile&do=view&target=stl-views-1.0.3.gdb)" file to the project directory.( This directory serves as working directory as GDB.exe starts)
2. In the Menu->setting->compiler and debuggers dialog.
Add "source stl-views-1.0.3.gdb" to the debugger initialization command control.
3. start debugging!
4.In the Menu->debug->set user command to the debug dialog.
Enter " pvector v"
5, the v will be shown :D
By the way, I think the "set user command to the debug" dialog should be embeded in the "debugger(debug" panel, so, people don't need to open it again and again. (seems to annoying).
Where is the term "Parse_MyClass" function?
This is fictional name, when you write a debug script you need to provide to functions Evaluate_MyClass and Parse_MyClass.
btw: It works on the vector<struct>, too :)
The vector<vector<> > case requires script binding for
local cmd_result = ExecuteDebuggerCmd("pvector $1");
or
local parsed_value = DebuggerEvaluateVariable("$1"); // $1 is a gdb variable I think
This way when I iterate the elements of the vector, I can evaluate and then parse them if they are complex
No problem, my idea with the naming was to replicate the build-in tonumber function of squirrel. And I have no problems with the new name (except that it will be good if you sync the wxaui branch to trunk, because that is what I'm using).
What about the other two scripting functions that are required? Are they hard to implement?
The former will be used to implement squirrel version of the stl-views file, at the moment that is not possible.
The latter will be used in parsing of complex structures.
At the moment (I think) if the vector is part of a struct it won't be parsed, when the tree item of the struct is expanded:
struct
{
std::string s;
std::vector<int> v;
} a;
In the watches
a
|-- s <--- not parsed as string
|-- v <--- not parsed as vector
BTW: the std::list will require two commands to be parsed
1. plist list (to find its T type)
2. plist list T to get the structure
I think, I know why the watching of vector with 1000 elements is slow.
The pvector command emits a line for every element in the vector, this means that it emits 1000 + 3 (size, capacity, elem type).
I've added a logging line as follows:
void GDB_driver::ParseOutput(const wxString& output)
{
m_pDBG->Log(wxString::Format(_("GDB_driver::ParseOutput output size: %d"), output.length()));
With this addition, when I add v as a watch, I get too many lines in the debugger pane that look the same:
GDB_driver::ParseOutput output size: 13
GDB_driver::ParseOutput output size: 15
GDB_driver::ParseOutput output size: 15
GDB_driver::ParseOutput output size: 15
GDB_driver::ParseOutput output size: 15
GDB_driver::ParseOutput output size: 15
GDB_driver::ParseOutput output size: 15
GDB_driver::ParseOutput output size: 15
GDB_driver::ParseOutput output size: 15
So, we are parsing the output from the debugger line by line (emiting 1002 pipe events more that we should).
And here is the proof:
In bool PipedProcess::HasInput() we have:
if (IsInputAvailable())
{
cbTextInputStream sout(*GetInputStream());
wxString msg;
msg << sout.ReadLine();
CodeBlocksEvent event(cbEVT_PIPEDPROCESS_STDOUT, m_Id);
event.SetString(msg);
wxPostEvent(m_Parent, event);
// m_Parent->ProcessEvent(event);
return true;
}
So, the question is can we replace the ReadLine method with ReadBuffer/ReadWholeData one?
What depends on the line by line parsing and what will break if we do the replacement?
p.s. I'm not sure how fast gdb runs the pvector script though
Hello again,
I've done a little experiment (see the patch):
Index: src/sdk/pipedprocess.cpp
===================================================================
--- src/sdk/pipedprocess.cpp (revision 5643)
+++ src/sdk/pipedprocess.cpp (working copy)
@@ -94,8 +94,8 @@
if ( !m_input )
break;
- if (EatEOL(c))
- break;
+// if (EatEOL(c))
+// break;
line += c;
}
Removing the EOL checks makes the ReadLine method to read the whole input data that is available
(the debug output shows that strings of 1000+ character are read).
And the CB is interactive again if the Parse_StlVector looks like this:
function Parse_StlVector(a_str, start)
{
// the whole processing not commented to test its speed
..... ....
// put this before the first return, so the function doesn't produce big string result
return "test-value";
}
With this setup the CB is quite interactive (less than a second, measured with my internal human clock :) ).
p.s. I've not tested for breakage of the compiler or so... just the debugger
6) When I do manually "Send user command to debugger" : "pvector v" , then I can see in the debug log pane : "pvector v"
So If I understand correctly, the pvector v command is emmiting something like (writting from memory because I'm not infront of my pc at the moment)
elem 0: $1 = 1
elem 0: $2 = 2
Vector size = 2
Vector capacity = 2
Element type int*
What gcc and gdb do you use?
I'm using gcc 4.3.3 and gdb 6.8 on gentoo amd64 bit
I think, I've read that the stl-views file has some modifications for gcc-4.3.x series.
If you are using older compiler, that might cause the problem. :(
I edited my post above, I made a copy/paste error on what answer I see in the debug pan upon isseing "pvector v".
It is "Undefined command: "pvector". Try "help"."
GCC: 4.3.1
GDB : 6.8
This means the extend gdb command script file was not load correctly.
"source stl-views-1.0.3.gdb"
If this file loaded correctly, you can type "pvector", then here is the log output.
> pvector
Prints std::vector<T> information.
Syntax: pvector <vector> <idx1> <idx2>
Note: idx, idx1 and idx2 must be in acceptable range [0..<vector>.size()-1].
Examples:
pvector v - Prints vector content, size, capacity and T typedef
pvector v 0 - Prints element[idx] from vector
pvector v 1 2 - Prints elements in range [idx1..idx2] from vector
>>>>>>cb_gdb:
What version of CB do you use? With tostring or with wxString_ToLong binding?
Open the script console, to see the script errors (view -> script console)
Firstly, Thanks for your reply!
I use the SVN 5645 CB and applied your patches(two patches, the debug command and STL vector).
I'm sorry, I'm not sure what's the difference between tostring or wxString_ToLong binding :(.
In my mind, I can only understand the wiki page of debug_script.
http://wiki.codeblocks.org/index.php?title=Debugger_scripts
Like the image
(http://sites.google.com/site/studycodeblocks/_/rsrc/1244949553645/imagescb/SquirrelFunction.png)
There are several steps:
1, send a command to GDB to query the variable type by "whatis v"
2, GDB return the type = XXXXXXX
3, if the type string matches some Evaluate_XXX function, then the correct script will be called by squirrel to GDB for more details
4, the corresponding Parse_XXXX function will be called to give the correct value the "watches panel"
So, what does the binding used for? :D
Here is my squirrel log output:
Welcome to the script console!
AN ERROR HAS OCCURED [the index 'tointeger' does not exist]
CALLSTACK
*FUNCTION [Parse_StlVector()] F:\cb_svn\src\output\share\codeblocks\scripts\gdb_types.script line [158]
LOCALS
[size_value] INSTANCE
[capacity_pos] 16
[vector_info_str] INSTANCE
[size_pos] 0
[start] 0
[a_str] INSTANCE
[this] TABLE
Seems I should use "tostring"? How can I do? Thanks.
Uf, I've swap tointeger with tostring again :(
The updated version of the gdb_types.script uses tointeger, but the function that should be called is wxString_ToLong (Morten likes that name more and modified my bindings patch)
AN ERROR HAS OCCURED [the index 'tointeger' does not exist]
CALLSTACK
*FUNCTION [Parse_StlVector()] F:\cb_svn\src\output\share\codeblocks\scripts\gdb_types.script line [158]
So on line 158, replace tointeger with wxString_ToLong and it will work
@killerbot, tonight I'll test "set debug on" or something like that for the source command
I find a small hack.
http://sourceware.org/ml/gdb/2007-06/msg00091.html
We can get the gdb environment variables, then write a templary file.
type "show env" in GDB, it will show one variable :
APPDATA=F:\cb_svn\src\output\AppData
I'm wondering if we can use something like
$(APPDATA)/stl-views-1.0.3.gdb
Since the "source" command can't interpret the $(APPDATA) :(
well there are a few options I think :
1) specify in the source command some $CB macro [$DATAPATH] and have the debugger plugin, run macro replacement before creating debug commands from it
// pass user init-commands
wxString init = Manager::Get()->GetConfigManager(_T("debugger"))->Read(_T("init_commands"), wxEmptyString);
// commands are passed in one go, in case the user defines functions in there
// or else it would lock up...
QueueCommand(new DebuggerCmd(this, init));
so this would result into :
// pass user init-commands
wxString init = Manager::Get()->GetConfigManager(_T("debugger"))->Read(_T("init_commands"), wxEmptyString);
Manager::Get()->GetMacrosManager()->ReplaceMacros(init);
// commands are passed in one go, in case the user defines functions in there
// or else it would lock up...
QueueCommand(new DebuggerCmd(this, init));
2) just specify the file to source with no extra path and have the command interpreter check in case the command is 'source' to check for the file in the current working directory, and in case not found there, check in the CB app directory (needs to know where that app/data directory is.
Option 1 seems the most easiest and quickest, but maybe not the most user friendliest.
QUESTION : does anyone see a negative side effect of issuing a macro replacement on those debugger init commands ?
Does that apply to the source command? Can you give a link for the excerpt from the gdb docs?
(gdb) source $cwd/test.gdb
$cwd/test.gdb: No such file or directory.
But why do we care, we won't place the source stl-views.gdb command in the initial commands list.
We'll do something like:
m_Types.Clear();
InitializeScripting();
if(stl_debugging_enabled)
QueueCommand(new DebuggerCmd(this, _T("source fullpath/stl-views.gdb")));
// pass user init-commands
wxString init = Manager::Get()->GetConfigManager(_T("debugger"))->Read(_T("init_commands"), wxEmptyString);
// commands are passed in one go, in case the user defines functions in there
// or else it would lock up...
QueueCommand(new DebuggerCmd(this, init));
So the user can't mess things up.
if(stl_debugging_enabled)
QueueCommand(new DebuggerCmd(this, _T("source fullpath/stl-views.gdb")));
great I will do it that way, but then we the $variable and MacroManager.
Can at this moment anyone try it out without the if test and with NO fullpath/stl-views.gdb present !! What's the outcome ?
In case there's no harm/crash when that file is not there, I can already apply this to trunk.
Later on I will added the stl-views.gdb to trunk and make sure it is copied along during the build (make/cbp[win/linux])...
results of my latest experiment.
* in CB debugger settings : no source init commands anymore
* mofdified "gdb_types.script"
* stl-views-1.0.3.gdb @ /usr/local/share/codeblocks
* code change in gdbdriver.cpp::GDB_driver::Prepare()
// define all scripted types
m_Types.Clear();
InitializeScripting();
wxString StlDebugCommand(_T("source $DATAPATH/stl-views-1.0.3.gdb"));
Manager::Get()->GetMacrosManager()->ReplaceMacros(StlDebugCommand);
QueueCommand(new DebuggerCmd(this, StlDebugCommand));
// pass user init-commands
==> works, I see 200 entries of the vector v. And when I send manually the "pvector v" command to gdb, I see all 1000 entries.
One strange thing :
elem[997]: $998 = 997
elem[998]: $999 = 998
elem[999]: $1000 = 999
Vector size = 1000
Vector capacity = 1024
Element type = int *
element type --> int * , shouldn't this be int ?
OK, here is a little patch
Index: src/scripts/gdb_types.script
===================================================================
--- src/scripts/gdb_types.script (revision 5731)
+++ src/scripts/gdb_types.script (working copy)
@@ -164,9 +164,12 @@
local element_type_value = vector_info_str.Mid(capacity_end_pos + 15,
vector_info_str.length() - capacity_end_pos - 15);
- local result = _T("[size] = ") + size_value + _T("\n");
- result += _T("[capacity] = ") + capacity_value + _T("\n");
- result += _T("[element type] = ") + element_type_value + _T("\n");
+ local result = _T("[size] = ") + size_value + _T(",\n");
+ result += _T("[capacity] = ") + capacity_value + _T(",\n");
+ result += _T("[element type] = ") + element_type_value;
+
+ if(size > 0)
+ result += _T(",\n");
local value_str = a_str;
for(local item = 0; item < size; item += 1)
@@ -185,8 +188,12 @@
local equal_pos = elem_value.Find(_T(" = "));
if(equal_pos >= 0)
elem_value.Remove(0, equal_pos + 3);
+ if(item > 0)
+ result += _T(",");
result += _T("[") + item + _T("] = ") + elem_value + _T("\n");
}
+ else
+ break;
value_str.Remove(0, elem_end);
}
It does two things:
1. Add , at the end of every item/line, so the output more like the one emitted from GDB (not readly needed in trunk, but in my local patch)
2. Fixes an almost infinite loop if the vector is not initialized.
std::vector<int> v; // <- if you break here and add v to the watches, C::B freezes, because vector.size is very big number (in my case, but it could be anything)
v.push_back(1);
Best regards...
I think, this is known bug... will look at it tonight
Update: yes known bug...
Here is the output of the whatis command:
> whatis v_str
type = std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >,std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >
And this line matches the regexp for std::string and so the script for std::string is used instead of the one for the vector.
Here is a patch that fixes the problem (not tested extensively)
Index: src/plugins/debuggergdb/gdb_commands.h
===================================================================
--- src/plugins/debuggergdb/gdb_commands.h (revision 5826)
+++ src/plugins/debuggergdb/gdb_commands.h (working copy)
@@ -702,6 +702,8 @@
m_watch->GetSymbol(symbol);
m_watch->GetType(type);
+ type.Trim(true);
+ type.Trim(false);
m_Cmd = static_cast<GDB_driver*>(m_pDriver)->GetScriptedTypeCommand(type, m_ParseFunc);
if (m_Cmd.IsEmpty())
{
@@ -798,7 +800,7 @@
// m_pWatch(watch)
m_watch(watch)
{
- m_Cmd << _T("whatis ");
+ m_Cmd << _T("whatis &");
// m_Cmd << m_pWatch->keyword;
wxString symbol;
m_watch->GetSymbol(symbol);
@@ -813,6 +815,7 @@
// type = bool
wxString tmp = output.AfterFirst(_T('='));
+ tmp = tmp.substr(0, tmp.length() - 1);
// actually add this watch with high priority
// m_pDriver->QueueCommand(new GdbCmd_Watch(m_pDriver, m_pDTree, m_pWatch, tmp), DebuggerDriver::High);
wxString old_type;
@@ -850,6 +853,8 @@
m_Type(w_type),
m_Address(address)
{
+ m_Type.Trim(true);
+ m_Type.Trim(false);
m_Cmd = static_cast<GDB_driver*>(m_pDriver)->GetScriptedTypeCommand(w_type, m_ParseFunc);
if (m_Cmd.IsEmpty())
{
Index: src/scripts/gdb_types.script
===================================================================
--- src/scripts/gdb_types.script (revision 5826)
+++ src/scripts/gdb_types.script (working copy)
@@ -24,7 +24,7 @@
// STL String
driver.RegisterType(
_T("STL String"),
- _T("[^[:alnum:]_]*string[^[:alnum:]_]*"),
+ _T("^std::basic_string<.*>$"),
_T("Evaluate_StlString"),
_T("Parse_StlString")
);
@@ -32,7 +32,7 @@
// STL Vector
driver.RegisterType(
_T("STL Vector"),
- _T("[^[:alnum:]_]*vector<.*"),
+ _T("^std::vector<(.*)>$"),
_T("Evaluate_StlVector"),
_T("Parse_StlVector")
);
The patch includes a fix for another problem:
> whatis gdb_type
Attempt to take contents of a non-pointer value.
>>>>>>cb_gdb:
> whatis &gdb_type
type = const wxString &*
>>>>>>cb_gdb:
That thing is caused by the command "source stl-views-1.0.3.script", and unfortunately, I've not reported it to gdb upstream, will do so someday...
The patch evaluates the type of the address of the watched variable and then strips the * at the end of the result.
Testing is welcome.
p.s. the patch is agains the wxpropgrid_debugger branch, if you have problems applying it, I'll produce one against trunk