how should I use strace to snif the serial port?

2020-07-13 11:15发布

I am writing an application in linux and need to access the serial port. For debugging purposes I need to snif what comes and/or goes through the serial port.

I looked around and found out I can use strace to do that. So I tried the following:

-I print the file_descriptor of the serial device that I use.

(after restarting my application a few times, I reassured myself that the file_descriptor number my application gets from kernel is "4"

-if i start my application as strace -e write=4 ./myapp , I would expect to get messages in the terminal, from file_descriptor "4" only. instead I get looots of output:

read(5, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0(\0\1\0\0\0\300Q\254C4\0\0\0"..., 52
fstat64(5, {st_mode=S_IFREG|0644, st_size=1448930, ...}) = 0                    
mmap2(0x43ab8000, 153816, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 5, 0)0
mprotect(0x43ad6000, 28672, PROT_NONE)  = 0                                     
mmap2(0x43add000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRI0
close(5)                                = 0                                     
munmap(0x2ab4c000, 38409)               = 0                                     
exit(0)   

from several different file_descriptors.

If I run my app with strace -e trace=write -e write=4 ./myapp

I'll get far less message, even though they will still be many, and or file_descriptor "1".

write(1, "GPIO data bank:0x8, data: 0x80 a"..., 52GPIO data bank:0x8, data: 0x81) = 52                                                                          
write(1, "\n", 1)   = 1                                                     
write(1, "--> Version: 0677 <--\n", 22--> Version: 0677 <-- ) = 22                                                                          
serial fd = 4 

what you see above are some printf statements. The extremely weird part is that the line serial fd = 4 is also a printf statement, but for some reason it is not wrapped around write(fd, ....) statement in strace output. Can someone explain that, too?

thank you for your help.

1条回答
乱世女痞
2楼-- · 2020-07-13 12:08

Try it out with someting simple.

strace -e write=1 echo foo

This will write all syscalls, and in addition to these, the data written to fd 1.

strace -e trace=none -e write=1 echo foo

This will generate no output except for the output from the program itself. It seems you have to trace write if you want to see its data.

strace -e trace=write -e write=1 echo foo

This will print all write syscalls, for any file descriptor. In addition to that, it will print a dump of the data sent to descriptor 1. The output will look like this:

write(1, "foo\n", 4foo
)                    = 4
 | 00000  66 6f 6f 0a                                       foo.             |
+++ exited with 0 +++

The syscall starts in the first line. After the list of arguments, the syscall is actually executed, and prints foo followed by a newline. Then the syscall return value is printed by strace. After that, we have the data dump.

I'd suggest using -e trace=write -e write=4 -o write4.txt followed by grep '^ |' write4.txt or something like that. If you want to see data in real time, you can use a bash redirection like this:

strace -e trace=write -e write=4 -o >(grep '^ |') ./myapp

This will send output from strace to grep, where you can strip the write syscalls and concentrate on the data dumps.

The extremely weird part is that the line serial fd = 4 is also a printf statement, but for some reason it is not wrapped around write(fd, ....) statement in strace output. Can someone explain that, too?

I'd say that line is output not from strace, but from some application. That's the reason it is not wrapped. The fact that no wrapped version of this appears in addition to that unwrapped one (like in my foo example output above) suggests that the output might originate in a child process lainced by myapp. Perhaps you want to add -f so you follow child process creation?

Notice that a child might decide to rename its file descriptors, e.g. redirect its standard output to that serial port opened by the parent. If that happens, write=4 won't be appropriate any more. To be on the safe side, I'd write the whole -f -e trace=write output to a file, and look at that to see where the data actually gets written. Then adjust things to home in on that data.

查看更多
登录 后发表回答