Printing complex Go structs in GDB - gdb

I need some help in using GDB + Python extensions for Go.
The struct LogQuery I am trying to look into is composed as follows:
LogQuery (struct)
CommonCmd (struct)
Context (struct)
out
Globs
flagHelp
...
flagLog
...
Breakpoint 3, acme/subcmds.CmdObj (context=..., cmdName="log_query", noname=
void) at /nobackup/git/goacme/src/acme/subcmds/cmder.go:32
32 cmd = NewLogQuery(context) //debugger
(gdb) s
acme/subcmds.NewLogQuery (context=..., noname=void)
at /nobackup/git/goacme/src/acme/subcmds/log_query.go:29
29 func NewLogQuery(context context.Context) LogQuery {
(gdb) n
30 obj := LogQuery{NewCommonCmd(context), "", "", "", "", 0, "", ""}
(gdb)
31 return obj
1 - printing the object (obj) inside the constructor works. But how do I see 'obj.Globs'?
(gdb) p obj
$8 = {acme/subcmds.CommonCmd = {acme/context.Context = {out = 0, Globs =
0xf840050140}, FlagArgs = "", flagDebug = "", flagHelp = false,
flagOutput = "", flagVerbose = false, CmdName = "", debug = 0x0},
flagColl = "", flagData = "", flagDb = "", flagHost = "", flagLimit = 0,
flagLog = "", flagQuery = ""}
Returning to the caller
(gdb) n
acme/subcmds.CmdObj (context=..., cmdName="log_query", noname=void)
at /nobackup/git/goacme/src/acme/subcmds/cmder.go:40
40 if cmdName == "acme" {
Here I see the type of the object, but can't seem to be able the see anything in it
(gdb) p cmd
$9 = "(subcmds.LogQuery)0xf840052b60"
(gdb) p $dtype(cmd)
$2 = (struct cmds.Add *) 0xf840034210
(gdb) p cmd->Globs
A syntax error in expression, near `>Globs'.
(gdb) p cmd.Globs
There is no member named Globs.

Related

string_view print weird in c++

I follow others' guides to rewrite my string split function.
#include<string>
#include<list>
#include<optional>
#include<malloc.h>
#include<string_view>
#include<iostream>
#include<vector>
#include "include/common.h"
using std::list;
using std::string;
using std::optional;
using std::vector;
using std::string_view;
/* there not use optional is better cuz list.length == 0 repr that */
/*
#brief: split string by substring
*/
vector<string_view> split(string content, string_view delim_str) {
size_t tail_pos = 0;
size_t head_pos = std::string::npos;
vector<string_view> str_view_vec;
while((head_pos = content.find(delim_str, tail_pos))
!= std::string::npos)
{
DBG("tail_pos = %zu, head_pos = %zu", tail_pos, head_pos);
str_view_vec.emplace_back(&content[tail_pos], head_pos - tail_pos);
tail_pos = head_pos + delim_str.length();
}
if(tail_pos != content.length() - 1) {
str_view_vec.emplace_back(&content[tail_pos], content.length() - tail_pos);
}
return str_view_vec;
}
int main() {
string s("123 12312 123213a as dasd as asd");
std::cout << string_view("asdasd 123") << std::endl;
vector<string_view> l = split(s, string_view(" "));
for(const auto &i : l) {
std::cout << i << std::endl;
}
}
then compile and print:
❯ clang -o String String.cpp -g -std=c++17 -I../ -lstdc++; ./String
asdasd 123
[x] split(), String.cpp:49 : tail_pos = 0, head_pos = 3
[x] split(), String.cpp:49 : tail_pos = 4, head_pos = 9
[x] split(), String.cpp:49 : tail_pos = 10, head_pos = 17
[x] split(), String.cpp:49 : tail_pos = 18, head_pos = 20
[x] split(), String.cpp:49 : tail_pos = 21, head_pos = 25
[x] split(), String.cpp:49 : tail_pos = 26, head_pos = 28
#S
a
as
dasd
as
asd
This result is so weird cuz it doesn't print any chars in 123 12312 123213a but prints three lines of random chars;
I use lldb to verify the return value and found it seems ok;
* thread #1, name = 'String', stop reason = breakpoint 1.1
frame #0: 0x00000000004027f8 String`split(content=error: summary string parsing error, delim_str=(_M_len = 1, _M_str = " ")) at String.cpp:56:5
53 if(tail_pos != content.length() - 1) {
54 str_view_vec.emplace_back(&content[tail_pos], content.length() - tail_pos);
55 }
-> 56 return str_view_vec;
57 }
58 int main() {
59
(lldb) p str
Available completions:
str_view_vec -- vector<basic_string_view<char, char_traits<char> >, allocator<basic_string_view<char, char_traits<char> > > > &
struct
(lldb) p str_view_vec
(std::vector<std::basic_string_view<char, std::char_traits<char> >, std::allocator<std::basic_string_view<char, std::char_traits<char> > > >) $0 = size=7 {
[0] = (_M_len = 3, _M_str = "123 12312 123213a as dasd as asd")
[1] = (_M_len = 5, _M_str = "12312 123213a as dasd as asd")
[2] = (_M_len = 7, _M_str = "123213a as dasd as asd")
[3] = (_M_len = 2, _M_str = "as dasd as asd")
[4] = (_M_len = 4, _M_str = "dasd as asd")
[5] = (_M_len = 2, _M_str = "as asd")
[6] = (_M_len = 3, _M_str = "asd")
}
(lldb) q
So I want to figure out where these weird chars come from and why alphabetic lines are normal only digital lines are not print well.
Change this
vector<string_view> split(string content, string_view delim_str) {
to this
vector<string_view> split(const string& content, string_view delim_str) {
Your string views are 'pointing' at content which is destroyed when the split function exits. Using a reference avoids this.
If you want to avoid this whole issue, then use strings instead of string views. String views don't work independently of the string they view.

Using libipt, how does one add a matching rule such as 'dport' for TCP packets?

I've been trying to add netfilter rules programmatically without making calls to the iptables binary. Aside from the header files for libipt, the closest thing to documentation I've found is here. There's nothing in the documentation describing what I want to do, oddly enough.
In ip_tables.h at the bottom of the ipt_entry struct is the following bit of code:
/* The matches (if any), then the target. */
unsigned char elems[0];
However, I haven't found any way to properly read or modify elems.
I also tried adding a rule via iptables iptables -A INPUT -p tcp --dest 192.168.1.10 --dport 8080 -j ACCEPT and then running a program that calls into libipt like so: ipt_entry *rule = iptc_first_rule(chain, iptHandle);. I ran it in GDB and broke on the line following
iptc_first_rule. Dumping the ipt_entry structure gives me this:
(gdb) p *rule
$4 = {
ip = {
src = {
s_addr = 0
},
dst = {
s_addr = 167880896
},
smsk = {
s_addr = 0
},
dmsk = {
s_addr = 4294967295
},
iniface = '\000' <repeats 15 times>,
outiface = '\000' <repeats 15 times>,
iniface_mask = '\000' <repeats 15 times>,
outiface_mask = '\000' <repeats 15 times>,
proto = 6,
flags = 0 '\000',
invflags = 0 '\000'
},
nfcache = 0,
target_offset = 160,
next_offset = 200,
comefrom = 2,
counters = {
pcnt = 0,
bcnt = 0
},
elems = 0x77e85b58 "0"
}
I saw that there was something in the elems member, so I tried dumping it too:
(gdb) x /10s rule->elems
0x77e85b58: "0"
0x77e85b5a: "tcp"
0x77e85b5e: "%s"
0x77e85b61: ""
0x77e85b62: ""
0x77e85b63: ""
0x77e85b64: "%s(): set IP_HDRINC"
0x77e85b78: ""
0x77e85b79: ""
0x77e85b7a: "\377\377P"
Lastly, I tried looking at the source code of iptables. However, I had to stop looking at that spaghetti soup before throwing myself out of the nearest window.
How in the heck do you specify a destination port for a rule?
Edit: I forgot to mention, the target platform is openWRT, which doesn't provide any of the newer netfilter libraries. I'm stuck with libipt/xtables.

string iterator not stopping at end of string

I'm reading yummy recipes from a line made of different substrings divided by ; in this order:
Recipe index (R1)
Number to be cooked (1)
Recipe name (Ensalada Mixta)
Ingredients and their quantity (Lechuga 200;...)
The first three work like a charm, you can see they are stored in the data array and printed in the printf block. The problem comes reading the rest. The reader iterator reads through the line perfectly but doesn't stop at the end, so it add rubbish values to the pair and throws a segfault. Here's the output from this MRE:
:: R1
:: 1
:: Ensalada Mixta
-> Lechuga 200
-> Tomate 50
-> Pepino 50
-> Cebolla 50
-> Aceite Oliva 5
-> Vinagre De Vino 10
-> Sal 1
[1] 85313 segmentation fault (core dumped)
The loop should stop after Sal 1, so what am I doing terribly wrong? Here's the code:
#include <cmath>
#include <list>
#include <string>
#include <utility>
#include <cstdio>
using namespace std;
int main () {
string line = "R1;1;Ensalada Mixta;Lechuga 200;Tomate 50;Pepino 50;Cebolla 50;Aceite Oliva 5;Vinagre De Vino 10;Sal 1";
list<pair<string, unsigned> > ings;
string recipe_data[3];
string::const_iterator reader = line.cbegin();
//Lectura del código, plato y ing_name de la receta
for (int i = 0; i < 3; ++reader) {
if (*reader != ';')
recipe_data[i].push_back(*reader);
else
++i;
}
printf(":: %s\n", recipe_data[0].c_str());
printf(":: %s\n", recipe_data[1].c_str());
printf(":: %s\n", recipe_data[2].c_str());
/*
* This is the problematic loop. The problem is in the while boolean
* expression, which always evaluates to false.
*/
while (reader != line.cend()) {
string ing_name = "";
unsigned ing_quantity = 0;
while (*reader != ';' && reader != line.cend()) {
ing_name += *reader;
++reader;
}
string::reverse_iterator it = ing_name.rbegin();
for (int i = 0; *it != ' '; i++) {
char c[1] = {*it};
ing_quantity += atoi(c) * pow(10, i);
++it;
ing_name.pop_back();
}
ing_name.pop_back();
pair<string, unsigned> ing(ing_name, ing_quantity);
ings.push_back(ing);
printf("-> %s %d\n", ing.first.c_str(), ing.second);
++reader;
}
}
Here's gdb output using a breakpoint on the very last ++reader line:
Breakpoint 1, main () at so.cpp:52
52 ++reader;
1: reader = 59 ';'
2: line.cend() = 0 '\000'
3: ing = {first = "Tomate", second = 50}
(gdb)
Continuing.
-> Pepino 50
Breakpoint 1, main () at so.cpp:52
52 ++reader;
1: reader = 59 ';'
2: line.cend() = 0 '\000'
3: ing = {first = "Pepino", second = 50}
(gdb)
Continuing.
-> Cebolla 50
Breakpoint 1, main () at so.cpp:52
52 ++reader;
1: reader = 59 ';'
2: line.cend() = 0 '\000'
3: ing = {first = "Cebolla", second = 50}
(gdb)
Continuing.
-> Aceite Oliva 5
Breakpoint 1, main () at so.cpp:52
52 ++reader;
1: reader = 59 ';'
2: line.cend() = 0 '\000'
3: ing = {first = "Aceite Oliva", second = 5}
(gdb)
Continuing.
-> Vinagre De Vino 10
Breakpoint 1, main () at so.cpp:52
52 ++reader;
1: reader = 59 ';'
2: line.cend() = 0 '\000'
3: ing = {first = "Vinagre De Vino", second = 10}
(gdb)
Continuing.
-> Sal 1
Breakpoint 1, main () at so.cpp:52
52 ++reader;
1: reader = 0 '\000'
2: line.cend() = 0 '\000'
3: ing = {first = "Sal", second = 1}
(gdb) n
47 pair<string, unsigned> ing(ing_name, ing_quantity);
1: reader = 0 '\000'
2: line.cend() = 0 '\000'
3: ing = {first = "Sal", second = 1}
(gdb)
29 string ing_name = "";
1: reader = 0 '\000'
2: line.cend() = 0 '\000'
3: ing = {first = "Sal", second = 1}
(gdb)
28 while (reader != line.cend()) {
1: reader = 0 '\000'
2: line.cend() = 0 '\000'
(gdb)
29 string ing_name = "";
1: reader = 0 '\000'
2: line.cend() = 0 '\000'
3: ing = {first = "Sal", second = 1}
As you can see, it shouldn't have re-entered the loop since the iterator and cend() are equal, right?
The inner while increments until either you find ; or cend and in both cases you continue. Only on the next iteration you stop because reader != line.cend() is false but thats already too late.
Also you have to first check if you are at the end, and only then dereference reader:
while (reader != line.cend() && *reader != ';') {
ing_name += *reader;
++reader;
}
if (reader == line.cend()) break;

Output GNU Octave (or Matlab) matrix into a file with C array syntax

I have a big matrix in octave which I need it's data to be imported into my C++ code. The matrix is all numbers and I would like to save it as a C array in a header file.
example :
> # octave:
results =
-3.3408e+01 -5.0227e+00 4.3760e+01 3.2487e+01 1.0167e+01 4.1076e+01 6.3226e+00 -3.7095e+01 1.3318e+01 3.8582e+01
-2.1087e+01 -6.1606e+00 4.8704e+01 3.1324e+01 3.0287e+01 4.0114e+01 1.5457e+01 -3.6283e+01 2.6035e+01 4.0112e+01
Needed output:
/* In some foo.h */
static const float results = {
3.3408e+01,-5.0227e+00,4.3760e+01,3.2487e+01,1.0167e+01,4.1076e+01,6.3226e+00,-3.7095e+01,1.3318e+01,3.8582e+01,
2.1087e+01,-6.1606e+00,4.8704e+01,3.1324e+01,3.0287e+01,4.0114e+01,1.5457e+01,-3.6283e+01,2.6035e+01,4.0112e+01,
};
For vectors, try this function
function str = convertarraytoc(B, type, precision, varName)
if nargin < 2
type = 'float';
end
if nargin < 3
precision = 35;
end
if nargin < 4
varName = 'B';
end
str = sprintf('%s %s[%d] = {', type, varName, length(B));
for iB=1:length(B)
if strcmpi(type, 'float')
str = [ str sprintf( ['%1.' int2str(precision) 'ff'], B(iB)) ];
else
str = [ str sprintf('%d', B(iB)) ];
end
if iB ~= length(B)
str = [ str sprintf(',') ];
end
if mod(iB, 501) == 0, str = [ str sprintf('\n') ]; end
end
str = [ str sprintf('};\n') ];
fprintf('%s', str);
For example
convertarraytoc(rand(1,5), 'float', 8, 'test')
ans =
'float test[5] ={0.84627244f,0.63743734f,0.19773495f,0.85582346f,0.24452902f};'
The function would need to be adapted to process Matlab arrays.

this pointer and all arguments are null after call (but ok before)

I am having a strange problem I do not know how to debug:
I have the following (C++11) class method:
void RamCloud::write(uint32_t tableId, uint64_t id, const void* buf,
uint32_t length,
uint64_t* version, bool async)
{
btree::node_cache& cache = btree::node_cache::instance(104857600);
cache.write(tableId, id, buf, length);
theCloud->write(tableId, id, buf, length, nullptr, version, async);
}
(don't thing too much what the code does, it does not really matter here).
Most of the time this works, but there is one case where it does fail. If I break at the last line using gdb, I can do the following:
(gdb) p theCloud
$3 = (RAMCloud::RamCloud *) 0x7fbe14009e90
(gdb) p tableId
$5 = 3
(gdb) p id
$6 = 3
(gdb) p buf
$7 = (const void *) 0x7fbe253a22d0
(gdb) p length
$8 = 31496
(gdb) p version
$9 = (uint64_t *) 0x0
(gdb) p async
$10 = false
(gdb) s
#0 0x00007fbe220344aa in RAMCloud::RamCloud::write (this=0x0, tableId=0, id=0, buf=0x0, length=0, rejectRules=0x0, version=0x0, async=false) at /local/mpilman/ramcloudarch/ramcloud/src/RamCloud.cc:260
(gdb) p this
$11 = (RAMCloud::RamCloud * const) 0x0
(gdb) p tableId
$12 = 0
(gdb) p id
$13 = 0
(gdb) p buf
$14 = (const void *) 0x0
(gdb) p length
$15 = 0
(gdb) p rejectRules
$16 = (const RAMCloud::RejectRules *) 0x0
(gdb) p version
$17 = (uint64_t *) 0x0
(gdb) p async
$18 = false
So right before the call everything seems ok, but after the call, all arguments (including the this pointer) switch to null. When I try to continue I get of course a segfault...
So my question: what could be here the problem? The caller is in another library than the callee, but these libraries are linked statically (and everything is compiled with the same compiler).
gcc version is 4.6.1. Does anyone have an idea where I could start debugging?
Thanks for any help!
It looks like your stack is being smashed. Tools like Valgrind on *nix or Application Verifier on Windows can be used to find the cause of these memory-related problems.