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.
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 aroundwrite(fd, ....)
statement instrace
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With