How to execute a GDB command from a string variable? - scripting

Say the debugged process has a string variable as follows:
char* cmd_str = "set confirm on";
How to execute the command from cmd_str in GDB?
(gdb) $cmd = cmd_str
(gdb) ???

You can use gdb's eval command, which runs printf on its arguments and then evaluates the result as a command.
(gdb) list
1 #include <stdlib.h>
2 main()
3 {
4 char *a = "set confirm off";
5
6 pause();
7 }
(gdb) break 6
Breakpoint 1 at 0x400540: file cmdtest.c, line 6.
(gdb) run
Starting program: ./cmdtest
Breakpoint 1, main () at cmd.c:6
6 pause();
(gdb) show confirm
Whether to confirm potentially dangerous operations is on.
(gdb) printf "%s", a
set confirm off(gdb)
(gdb) eval "%s", a
(gdb) show confirm
Whether to confirm potentially dangerous operations is off.

Related

Lex and Yacc to make compiler?

I am starting a toy compiler, and I am making the simplest thing I can imagine, but it won't work.
Lex compiles, and Yacc compiles, and they link together, but the outputted program does not do what I expected.
Lex:
%{
#include <stdlib.h>
void yyerror(char *);
#include "y.tab.h"
%}
%%
a {
yylval = atoi(yytext);
return AAA;
}
. yyerror("invalid character");
%%
int yywrap(void) {
return 1;
}
Yacc:
%{
void yyerror(char *);
int yylex(void);
int sym[26];
#include <stdio.h>
%}
%token AAA
%%
daaaa:
AAA {printf("%d\n", $1);}
%%
void yyerror(char *s) {
fprintf(stderr, "%s\n", s);
}
int main(void) {
yyparse();
return 0;
}
The program I am trying to compile with this compiler is a file containing: a. that's it.
I don't know what's happened!
Clarification: What I expected the compiled compiler to do was to accept a file into it, process the file, and spit out a compiled version of that file.
Can you explain, maybe in an answer, exactly what you did, and how it worked, because as far as I can tell, and as far as I have tested the question, it shouldn't work as you say.
I took your code verbatim, creating files grammar.y and lexer.l. I then compiled the code. I'm working on Mac OS X 10.11.4, using GCC 6.1.0, Bison 2.3 (disguised as yacc) and Flex 2.5.35 (disguised as lex).
$ yacc -d grammar.y
$ lex lexer.l
$ gcc -o gl y.tab.c lex.yy.c
$ ./gl <<< 'a'
0
$
I subsequently made two changes. In grammar.y, I changed main() to:
int main(void) {
#if YYDEBUG
yydebug = 1;
#endif
yyparse();
return 0;
}
and in lexer.l, I changed the default character rule to:
\n|. yyerror("invalid character");
(The . doesn't match newline, so the newline after the a in the input was echoed by default in the original output.)
With a similar compilation, the output becomes:
$ ./gl <<< 'a'
0
invalid character
$
With the compilation specifying -DYYDEBUG too:
$ gcc -DYYDEBUG -o gl lex.yy.c y.tab.c
$
the output includes useful debugging information:
$ ./gl <<< 'a'
Starting parse
Entering state 0
Reading a token: Next token is token AAA ()
Shifting token AAA ()
Entering state 1
Reducing stack by rule 1 (line 12):
$1 = token AAA ()
0
-> $$ = nterm daaaa ()
Stack now 0
Entering state 2
Reading a token: invalid character
Now at end of input.
Stack now 0 2
Cleanup: popping nterm daaaa ()
$ ./gl <<< 'aa'
Starting parse
Entering state 0
Reading a token: Next token is token AAA ()
Shifting token AAA ()
Entering state 1
Reducing stack by rule 1 (line 12):
$1 = token AAA ()
0
-> $$ = nterm daaaa ()
Stack now 0
Entering state 2
Reading a token: Next token is token AAA ()
syntax error
Error: popping nterm daaaa ()
Stack now 0
Cleanup: discarding lookahead token AAA ()
Stack now 0
$
The second a in the input correctly triggers a syntax error (it isn't allowed by the grammar). Other characters are permitted, generate a 'invalid character' message, and are otherwise ignored (so ./gl <<< 'abc' generates 3 invalid character messages, one for the b, one for the c, and one for the newline).
Changing the assignment to yylval in lexer.l to:
yylval = 'a'; // atoi(yytext);
changes the number printed from 0 to 97, which is the character code for 'a' in ASCII, ISO 8859-1, Unicode, etc.
I've been using a here string as the source of data. It would be equally feasible to have used a file as the input:
$ echo a > program
$ cat program
a
$ ./gl < a
Starting parse
Entering state 0
Reading a token: Next token is token AAA ()
Shifting token AAA ()
Entering state 1
Reducing stack by rule 1 (line 12):
$1 = token AAA ()
97
-> $$ = nterm daaaa ()
Stack now 0
Entering state 2
Reading a token: invalid character
Now at end of input.
Stack now 0 2
Cleanup: popping nterm daaaa ()
$
If you want to read files specified by name on the command line, you have to write more code in main() to process those files.
The program does not accept a file because it was not told to.
In the Yacc program,
extern FILE *yyin; must be added in the definitions section.
I believe that's it.

Memcheck reports unitialised values when accessing local variables down the stack

I encountered a problem that Memcheck reports uninitialized values and I think these are perfectly legal. I managed to create a small example program that exhibits this behavior. I would like to know if Memcheck is really wrong and what can be done about it. (Is there any solution besides adding the errors into a suppression file?)
To reproduce this, I made the program below. It runs function go that puts 0x42 on the stack, calls og (this pushes the address of the next instruction leave on the stack), then in og it stores esp+4 into global variable a.
The stack looks like this:
| address of `leave` instruction | pc = a[-1]
| 0x42 | a points here, answer = a[0]
If I build it and run Valgrind,
gcc -g -m32 main.c go.S -o main
valgrind --track-origins=yes ./main
Valgrind thinks that the value in variable pc (and answer, if you put it in the if instead) is undefined. I checked with debugger that the values there actually are what I wanted.
==14160== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==14160== Command: ./main
==14160==
==14160== Conditional jump or move depends on uninitialised value(s)
==14160== at 0x804847D: print (main.c:18)
==14160== by 0x80484B0: ??? (go.S:19)
==14160== by 0x8048440: main (main.c:8)
==14160== Uninitialised value was created by a stack allocation
==14160== at 0x80484AC: ??? (go.S:19)
==14160==
==14160== Use of uninitialised value of size 4
==14160== at 0x80484B1: ??? (go.S:20)
==14160== by 0x8048440: main (main.c:8)
==14160== Uninitialised value was created by a stack allocation
==14160== at 0x80484AC: ??? (go.S:19)
If I debug from Valgrind with --vgdb-error=0 and print the definedness, it says that all the bits are undefined.
(gdb) p &pc
$1 = (int *) 0xfea5e4a8
(gdb) mo xb 0xfea5e4a8 4
ff ff ff ff
0xFEA5E4A8: 0x9e 0x84 0x04 0x08
The value at 0xfea5e4a8 is
(gdb) x/x 0xfea5e4a8
0xfea5e4a8: 0x0804849e
and
(gdb) x/i 0x0804849e
0x804849e <go+10>: leave
(gdb)
main.c
#include<stdio.h>
int *a;
extern void go();
int main() {
go();
printf("finito\n");
return 0;
}
int print() {
int answer = a[0];
int pc = a[-1];
// use the vars
if (pc == 0x42) {
printf("%d\n", 0);
}
}
go.S
.text
.globl go
go:
pushl %ebp
movl %esp, %ebp
pushl $0x42
call og
leave
ret
og:
addl $4, %esp
movl %esp, a
sub $4, %esp
call print
ret
The problem is this sequence of code:
addl $4, %esp
movl %esp, a
sub $4, %esp
When you move %esp up valgrind will mark everything below the new stack pointer position as undefined, and it will stay that way even after you move it back.
It's not safe anyway, because if a signal hit between the add and sub then that stack really might get overwritten (in 32 bit code - in 64 bit code there is a "red zone" below the pointer that is safe but valgrind knows about that).

awk command to run a C++ code and input several times

Say, I have a C code which I compile like:
$ gcc code.c -o f.out
$ ./f.out inputfile outputfile
Then the code asks for input
$ enter mass:
Now if I need to run this code for example 200 times and the input files have name : 0c.txt, 1c.txt, ....., 199c.txt etc and I want to use same value of mass every time (e.g. mass=6) then how do I write an "awk" command for that? Thanks for your help.
You don't specify your outputfile name. I'll assume 0c.out, 1c.out, ...
I'm also assuming that the f.out program reads the mass from stdin instead of anything more complicated.
#!/usr/bin/gawk -f
BEGIN {
mass = 6
for (i=0; i<200; i++) {
cmd = sprintf("./f.out %dc.txt %dc.out", i, i)
print mass |& cmd
close(cmd, "to")
while ((cmd |& getline out) > 0) {
do something with each line of output from ./f.out
}
close(cmd)
}
}
ref http://www.gnu.org/software/gawk/manual/html_node/Two_002dway-I_002fO.html
In bash, you'd write:
for i in $(seq 0 199); do
echo 6 | ./f.out ${i}c.txt ${i}c.out
done

Capturing pretty-printed string output, to display multiple variables on a single line in gdb?

In my gdb session, I have typed this:
(gdb) p arg1
$17 = (svn_revnum_t *) 0xbfffea0c
(gdb) p *(arg1)
$18 = -1
Now, I would like the "pretty-printed" output for both commands to be shown in a single line, as in:
$19 = (svn_revnum_t *) 0xbfffea0c ; -1
... so I try something like this:
(gdb) p arg1, ";", *(arg1)
$19 = -1
... but obviously, it doesn't work.
Is there a way to do something like this?
I guess, if it was possible to somehow "capture" the pretty-printed output of print as a string, then I could use printf "%s ; %s" to format my output; but how would one capture the print output, then?
I think the simplest way to do this is to write a new Python command that does what you want.
Alternatively you could write a Python convenience function that uses str on its argument. Then, use that with printf.

Calling fgets() on popen() of 'ssh' is flushing the beginning of stdin of the calling process (ptty issue)

I have now whittled this down to a minimal test case. Thus far I have been able to determine that this is an issue related to pseudo-terminals which come about with the pipe of ssh. Adding the '-t -t' to the ssh call improved things, in that now, it takes a second call to fgets() to cause the issue. I suspect that the stderr output of the ssh command somehow works into the issue, for now I have redirected stderr to stdout in the ssh code to execute. I do wonder if the "tcgetattr: Invalid argument" error is part of the problem, but am not sure how to get rid of that. It seems to come from the -t -t being present. I believe the -t -t is moving in the right direction, but I have to set up the pseudo terminal for stderr somehow and perhaps the test will work properly?
The Makefile:
test:
gcc -g -DBUILD_MACHINE='"$(shell hostname)"' -c -o test.o test.c
gcc -g -o test test.o
.PHONY: clean
clean:
rm -rf test.o test
The test.c source file:
#include <unistd.h>
#include <string.h>
#include <stdio.h>
int
main(int argc, char *argv[])
{
const unsigned int bufSize = 32;
char buf1[bufSize];
char buf2[bufSize];
int ssh = argv[1][0] == 'y';
const char *cmd = ssh ? "ssh -t -t " BUILD_MACHINE " \"ls\" 2>&1" : "ls";
FILE *fPtr = popen(cmd, "r");
if (fPtr == NULL) {
fprintf(stderr,"Unable to spawn command.\n");
perror("popen(3)");
exit(1);
}
printf("Command: %s\n", cmd);
if (feof(fPtr) == 0 && fgets(buf2, bufSize, fPtr) != NULL) {
printf("First result: %s\n", buf2);
if (feof(fPtr) == 0 && fgets(buf2, bufSize, fPtr) != NULL) {
printf("Second result: %s\n", buf2);
int nRead = read(fileno(stdin), buf1, bufSize);
if (nRead == 0) {
printf("???? popen() of ssh consumed the beginning of stdin ????\n");
} else if (nRead > 0) {
if (strncmp("The quick brown fox jumped", buf1, 26) != 0) {
printf("??? Failed ???\n");
} else {
printf("!!!!!!! Without ssh popen() did not consume stdin !!!!!!!\n");
}
}
}
}
}
This shows it running the passing way:
> echo "The quick brown fox jumped" | ./test n
Command: ls
First result: ARCH.linux_26_i86
Second result: Makefile
!!!!!!! Without ssh popen() did not consume stdin !!!!!!!
This shows it running the failing way:
> echo "The quick brown fox jumped" | ./test y
Command: ssh -t -t hostname "ls" 2>&1
First result: tcgetattr: Invalid argument
Second result: %backup%~ gmon.out
???? popen() of ssh consumed the beginning of stdin ????
Okay, I have got this working finally. The secret was to supply /dev/null as the input to my ssh command as follows from the test case above:
const char *cmd
= ssh ? "ssh -t -t " BUILD_MACHINE " \"ls\" 2>&1 < /dev/null" : "ls";
However, while the code works correctly, I get a nasty message which apparently I can ignore for my purposes (although I'd like to make the message go away):
tcgetattr: Inappropriate ioctl for device