As promised in last post, this entry is about fpathconf test. This is first test I was working on in range of developmental part of coverage. My mentor, Dr. Joel Sherril suggested me to take this function to cover first - as it should be quite simple to cover it. So I started my research. It gives not only full coverage of fpathconf but also discover some lacks in covoar - coverage tool in RTEMS coverage analysis.
What is fpathconf() function? This function is defined in POSIX standard and as described here:
The fpathconf() and pathconf() functions determine the current value of a configurable limit or option (variable) that is associated with a file or directory.For pathconf(), the path argument points to the pathname of a file or directory.For fpathconf(), the fildes argument is an open file descriptor.
fpathconf() is declared as:
#include <unistd.h>
long fpathconf(int fildes, int name);
As parameter name you have to provide one of possible options descirbed here:
_PC_LINK_MAX returns the maximum number of links to the file. If fd or path refer
to a directory, then the value applies to the whole directory. The
corresponding macro is _POSIX_LINK_MAX.
_PC_MAX_CANON returns the maximum length of a formatted input line, where fd or path must refer to a terminal. The corresponding macro is _POSIX_MAX_CANON.
_PC_MAX_INPUT returns the maximum length of an input line, where fd or path must
refer to a terminal. The corresponding macro is _POSIX_MAX_INPUT.
_PC_NAME_MAX returns the maximum length of a filename in the directory path or fd that the process is allowed to create. The corresponding macro is
_POSIX_NAME_MAX.
_PC_PATH_MAX returns the maximum length of a relative pathname when path or fd is
the current working directory. The corresponding macro is
_POSIX_PATH_MAX.
_PC_PIPE_BUF returns the size of the pipe buffer, where fd must refer to a pipe or
FIFO and path must refer to a FIFO. The corresponding macro is
_POSIX_PIPE_BUF.
_PC_CHOWN_RESTRICTED returns nonzero if the chown call may not be used on this file. If
fd or path refer to a directory, then this applies to all files in that
directory. The corresponding macro is _POSIX_CHOWN_RESTRICTED.
_PC_NO_TRUNC returns nonzero if accessing filenames longer than _POSIX_NAME_MAX generates an error. The corresponding macro is _POSIX_NO_TRUNC.
_PC_VDISABLE returns nonzero if special character processing can be disabled, where
fd or path must refer to a terminal.
The corresponding macros defined in <unistd.h> are minimum values; if an application wants to take advantage of values which may change, a call to fpathconf() or pathconf() can be made, which may yield more liberal results.
So, where were uncovered ranges in fpathconf() ? Look at the report: http://www.rtems.org/ftp/pub/rtems/people/joel/coverage/pc386/pc386-O2PD-20120912-2118/annotated.html#range252
There are two uncovered ranges in fpathconf(). First one contains 13 instructions, and second one contains 38 instructions. When looking at this report it seems to never execute almost all code. Look at this part:
rtems_libio_check_fd(fd);
10ad9b: 3b 05 9c ad 12 00 cmp 0x12ad9c,%eax
10ada1: 0f 83 a1 00 00 00 jae 10ae48 <fpathconf+0xb4> <== ALWAYS TAKEN
It was sure to me, that I have to look under the hood of rtems_libio_check_fd. It is macro defined in libio_.h:
/*
* rtems_libio_check_fd
*
* Macro to check if a file descriptor number is valid.
*/
#define rtems_libio_check_fd(_fd) \
do { \
if ((uint32_t) (_fd) >= rtems_libio_number_iops) { \
errno = EBADF; \
return -1; \
} \
} while (0)
Looking at assembler version of this code it is obvious that every time fpathconf was invoked, file descriptor was invalid. So I had to invoke this with valid descriptor and I was sure it should help.
Looking at second range I saw that it is simply switch statement with all possible name parameter options. My task was really simple. Invoke fpathconf() with valid file descriptor and with each possible option + one invalid option to cause every case to execute.
Git patch of test can be found here.
Although all switch cases were executed, there appear 9 uncovered ranges - each 2 bytes , 1 instructions in size. What the hell??
When looking on assembly version of code you can see some similarities:
case _PC_PRIO_IO: return_value = the_limits->posix_prio_io;
10adec: 8b 40 24 mov 0x24(%eax),%eax <== NOT EXECUTED
break;
10adef: eb eb jmp 10addc <fpathconf+0x48> <== NOT EXECUTED 10adf1: 8d 76 00 lea 0x0(%esi),%esi <== NOT EXECUTED
break; case _PC_VDISABLE: return_value = the_limits->posix_vdisable; break; case _PC_ASYNC_IO: return_value = the_limits->posix_async_io;
10adf4: 8b 40 18 mov 0x18(%eax),%eax <== NOT EXECUTED
break;
10adf7: eb e3 jmp 10addc <fpathconf+0x48> <== NOT EXECUTED 10adf9: 8d 76 00 lea 0x0(%esi),%esi <== NOT EXECUTED
break; case _PC_NO_TRUNC: return_value = the_limits->posix_no_trunc; break; case _PC_VDISABLE: return_value = the_limits->posix_vdisable;
10adfc: 8b 40 2c mov 0x2c(%eax),%eax <== NOT EXECUTED
break;
10adff: eb db jmp 10addc <fpathconf+0x48> <== NOT EXECUTED 10ae01: 8d 76 00 lea 0x0(%esi),%esi <== NOT EXECUTED
Every case statement consist of mov, jmp and lea instructions. But wait... jmp is unconditional jump! So you don't have any chance to execute lea instructions! It surprised me a lot. What is purpose of this instructions? I asked dr Joel - my mentor - and he explained me that compiler adds such trailing instructions - nop, lea, xor, xchg etc. at the end for aligning the entry of the next method in physical memory. Such lines are removed in covoar, but in this case it failed. Covoar cutted off only such trailing nops at the end of function and not in the medium - such as here. I pointed this notes to dr Joel and he fixed this bug in covoar :)
Covoar fixing patch by dr Joel is here, and here.
Brak komentarzy:
Prześlij komentarz