Can I change the binding of RET in gdb? - gdb

I'd like to disable the gdb behavior where typing a carriage return repeats execution of the last command entered. I'd just like it to do nothing. Is this possible?

It seems that repeating most commmands is a default gdb's behavior and there is no setting to change it. This is how it looks in gdb's source:
/* Handle a complete line of input. This is called by the callback
mechanism within the readline library. Deal with incomplete
commands as well, by saving the partial input in a global
buffer. */
static void
command_line_handler (char *rl)
{
...
int repeat = (instream == stdin);
So as you can see repeat is assigned 1 if instream is STDIN. There is no other way to assign repeat a different value.
So what you can do is to build your own gdb executable on your machine from gdb`s source (http://ftp.gnu.org/gnu/gdb/). But before building change a little the line 591 in gdb/event-top.c. Instead of
int repeat = (instream == stdin);
write
int repeat = 0;

One possible trick that might work -- I didn't try it -- would be to use Python to set the prompt callback to invoke "dont-repeat".
It seems like a reasonable feature request to me that gdb have a setting to disable command repetition.

Related

How to make a console app that excutes a command only when called

I am working on a project that has some functionality similar to windows task manager but as a console app. So far I managed to make the app present menus and, according to the user's choice, the app runs a specific functionality.
Now, I am thinking of letting the app do some function using commands for example, let's say we have the command close -all. This is supposed to close all the open windows.
In fact, I have some information about how I can process the command and call the corresponding function, I think using a lexer to produce tokens and then use a parser to call the functions, please correct me if I am mistaken.
However I can use the commands only if my application is running in cmd. what I want is to call a command like wg close all (wg being the app name) at any time and then maybe continue running other cmd commands like mkdir or cd.
This sounds like you need the basic functionality of a C++ program which is provided by the main(int argc, char* argv[]) method (refer to this documentation if needed: https://en.cppreference.com/w/cpp/language/main_function).
With argc being the number of arguments and argv being an array with the values of arguments. I assume that your application builds up a GUI with Qt or some library, which you would not need to fire up if ran in batch mode.
Depending on the complexity of the arguments you need to handle, you might do the trick with a very basic structure to parse the arguments.
Example Pseudo-Code
main(argc, argv) {
if (argc == 0) {
startProgramInNormalGUIMode();
exit(0);
}
// This could be a sub method "parse(argc, argv)"
String parameter="";
Boolean executed=false;
for (i=0; i < argc; ++i) {
if element == "close" {
set parameter = argv[i+1];
i++; // skip next element which was the parameter
// myCloseOperation would check if parameter is
// "all" for example and closes all windows
// or treat any other value as window title for
// example and closes only the matching window.
myCloseOperation(parameter);
set executed = true;
}
if element == "operation2" {
set parameter = argv[i+1];
i++;
myOperation2Method(parameter);
set executed = true;
}
}
if (executed == false) {
showSyntaxErrorMessage();
exit(1);
}
exit(0);
}
The pseudo code above assumes that every operation has an identifying name and only one parameter following it. You could alter the code to also allow zero parameters or more than one and change the i incrementation accordingly.
You could also add a check if a parameter or operation string starts with a dash or slash or some other prefix you want.
Also it is assumed that an operation and its parameter(s) may occur more than once in the command line and every occurance would be executed. For example wg close aWindowTitle close anotherWindowTitle close all would be parsed as valid and three close operations would be performed.

GDB: disable printing of current line after every step

The GNU gdb commandline debugger prints the line it is currently on after every step and next command. Consider the following gdb session where I step through some code:
...
Temporary breakpoint 1, main (argc=1, argv=0x7fffffffd848)
at src/main.cc:3
3 int main(int argc, char **argv){
(gdb) next
4 Printf("Hello World\n"); // <--- disable this
(gdb)
5 printf("Hello World 2\n"); // <--- disable this
(gdb)
Is there a gdb setting to disable this printing? I know this is technically possible because the gdb TUI has exactly the behaviour i'm looking for (accessible through gdb command set enable tui).
Thanks!
I achieved it through redirection:
define n
set logging file /dev/null
set logging redirect on
set logging on
next
set logging off
display
end
I found that capturing the output of next did not work using gdb.execute (gdb's python API). I expect that this is the case because the source line is not printed by next itself, but by the stop event that is triggered.
There is no straightforward way to do this when using the gdb CLI. The code that handles printing the "stop" to the user does not check anything that the user can set.
One way you could try solving this would be to alias n to a command that runs the command using a different interpreter, like interpreter-exec tui next. I am not sure if this will actually work.
Another way to accomplish this would be to write a Python command named n that uses gdb.execute to invoke next -- while capturing the output and ignoring it. This approach is somewhat dangerous because sometimes you probably do want some of the stop message, just not the source display.
The best approach would be to modify gdb to add a new set command to disable the source printing. This is easy to do.

Execute a C++ program and copy the cmd output using Perl

I am trying to code a perl script which would compile a C++ program and then execute it by passing in the required values. After the execution, I need whatever is printed on the cmd for comparison with a sample code.
Right now my code compiles the cpp code perfectly and correctly executes it, but completes without passing in the values.
All I am doing right now is use system commands
system("cl E:\\checker\\Perl\\temp.cpp");
system("temp.exe");
system("10");
system("20");
system("30");
system("40");
system("50");
The C++ Code is something like this
cin >> a;
cin >> b;
cin >> c;
cin >> d;
cin >> e;
The code correctly compiles and exectues, but the following values (which are inputs to the C++ code which is using cin) doesn't seem to work
Please note I am using the Visual Studio compiler. Also can someone tell me how I can extract the information outputted by the C++ code into maybe a perl array for comparison.
You can use IPC::Open2 to establish bidirectional communication between your Perl script and the other program, e.g.
use IPC::Open2;
use autodie;
my ($chld_out, $chld_in);
my $pid = open2(
$chld_out,
$chld_in,
q(bc -lq)
);
$chld_in->print("1+1\n");
my $answer = <$chld_out>;
print $answer;
kill 'SIGINT', $pid; # I don't believe waitpid() works on Win32. Possibly with Cygwin.
Unfortunately, buffering can make this approach a lot harder than one would hope. You'll also have to manually wait and reap the child process. An alternative would be to use a module like IO::Pty or Expect to create a pseudo-tty environment to simulate user interaction (but I believe these two only work in a Cygwin environment on Windows). There's also IPC::Run, a more fully-featured alternative to IPC::Open2/3.
See also: perlipc and perlfaq8.
The correct syntax for system is either
system('command', 'arg1', 'arg2', ... , 'argn');
Or all as a single string, which allows shell interpretation (which you may not want):
system('command arg1 arg2');
system does not capture output. Instead, use the backticks operator:
my $command_output = `command args`;
or its generic form qx. (If you assign to an array, the output will be split on $/ and pushed onto the array one line at a time).
There is also the pipe form of open (open my $pipeh, '-|', 'command', 'arg1', ..., 'argn') or die $!;) and the readpipe function.

pidof from a background script for another background process

I wrote a c++ program to check if a process is running or not . this process is independently launched at background . my program works fine when I run it on foreground but when I time schedule it, it do not work .
int PID= ReadCommanOutput("pidof /root/test/testProg1"); /// also tested with pidof -m
I made a script in /etc/cron.d/myscript to time schedule it as follows :-
45 15 * * * root /root/ProgramMonitor/./testBkg > /root/ProgramMonitor/OutPut.txt
what could be the reason for this ?
string ReadCommanOutput(string command)
{
string output="";
int its=system((command+" > /root/ProgramMonitor/macinfo.txt").c_str());
if(its==0)
{
ifstream reader1("/root/ProgramMonitor/macinfo.txt",fstream::in);
if(!reader1.fail())
{
while(!reader1.eof())
{
string line;
getline(reader1,line);
if(reader1.fail())// for last read
break;
if(!line.empty())
{
stringstream ss(line.c_str());
ss>>output;
cout<<command<<" output = ["<<output<<"]"<<endl;
break;
}
}
reader1.close();
remove("/root/ProgramMonitor/macinfo.txt");
}
else
cout<<"/root/ProgramMonitor/macinfo.txt not found !"<<endl;
}
else
cout<<"ERROR: code = "<<its<<endl;
return output;
}
its output coming as "ERROR: code = 256"
thanks in advacee .
If you really wanted to pipe(2), fork(2), execve(2) then read the output of a pidof command, you should at least use popen(3) since ReadCommandOutput is not in the Posix API; at the very least
pid_t thepid = 0;
FILE* fpidof = popen("pidof /root/test/testProg1");
if (fpidof) {
int p=0;
if (fscanf(fpidof, "%d", &p)>0 && p>0)
thepid = (pid_t)p;
pclose(fpidof);
}
BTW, you did not specify what should happen if several processes (or none) are running the testProg1....; you also need to check the result of pclose
But you don't need to; actually you'll want to build, perhaps using snprintf, the pidof command (and you should be scared of code injection into that command, so quote arguments appropriately). You could simply find your command by accessing the proc(5) file system: you would opendir(3) on "/proc/", then loop on readdir(3) and for every entry which has a numerical name like 1234 (starts with a digit) readlink(2) its exe entry like e.g. /proc/1234/exe ...). Don't forget the closedir and test every syscall.
Please read Advanced Linux Programming
Notice that libraries like Poco or toolkits like Qt (which has a layer QCore without any GUI, and providing QProcess ....) could be useful to you.
As to why your pidof is failing, we can't guess (perhaps a permission issue, or perhaps there is no more any process like you want). Try to run it as root in another terminal at least. Test its exit code, and display both its stdout & stderr at least for debugging purposes.
Also, a better way (assuming that testProg1 is some kind of a server application, to be run in at most one single process) might be to define different conventions. Your testProg1 might start by writing its own pid into /var/run/testProg1.pid and your current application might then read the pid from that file and check, with kill(2) and a 0 signal number, that the process is still existing.
BTW, you could also improve your crontab(5) entry. You could make it run some shell script which uses logger(1) and (for debugging) runs pidof with its output redirected elsewhere. You might also read the mail perhaps sent to root by cron.
Finally I solved this problem by using su command
I have used
ReadCommanOutput("su -c 'pidof /root/test/testProg1' - root");
insteadof
ReadCommanOutput("pidof /root/test/testProg1");

C++: How to escape user input for safe system calls?

On a Linux platform, I have C++ code that goes like this:
// ...
std::string myDir;
myDir = argv[1]; // myDir is initialized using user input from the command line.
std::string command;
command = "mkdir " + myDir;
if (system(command.c_str()) != 0) {
return 1;
}
// continue....
Is passing user input to a system() call safe at all?
Should the user input be escaped / sanitized?
How?
How could the above code be exploited for malicious purposes?
Thanks.
Just don't use system. Prefer execl.
execl ("/bin/mkdir", "mkdir", myDir, (char *)0);
That way, myDir is always passed as a single argument to mkdir, and the shell isn't involved. Note that you need to fork if you use this method.
But if this is not just an example, you should use the mkdir C function:
mkdir(myDir, someMode);
Using system() call with command line parameters without sanitizing the input can be highly insecure.
The potential security threat could be a user passing the following as directory name
somedir ; rm -rf /
To prevent this , use a mixture of the following
use getopt to ensure your input is
sanitized
sanitize the input
use execl instead of system to execute
the command
The best option would be to use all three
Further to Matthew's answer, don't spawn a shell process unless you absolutely need it. If you use a fork/execl combination, individual parameters will never be parsed so don't need to be escaped. Beware of null characters however which will still prematurely terminate the parameter (this is not a security problem in some cases).
I assume mkdir is just an example, as mkdir can trivially be called from C++ much more easily than these subprocess suggestions.
Reviving this ancient question as I ran into the same problem and the top answers, based on fork() + execl(), weren't working for me. (They create a separate process, whereas I wanted to use async to launch the command in a thread and have the system call stay in-process to share state more easily.) So I'll give an alternative solution.
It's not usually safe to pass user input as-is, especially if the utility is designed to be sudo'd; in order to sanitize it, instead of composing the string to be executed yourself, use environment variables, which the shell has built-in escape mechanisms for.
For your example:
// ...
std::string myDir;
myDir = argv[1]; // myDir is initialized using user input from the command line.
setenv("MY_DIR", myDir, 1);
if (system("mkdir \"${MY_DIR}\"") != 0) {
return 1;
}
// continue....