|
From: Samuel B. <na...@gm...> - 2009-07-27 21:33:38
|
Hi. I'm thinking about maybe implementing an ltrace-like skin for valgrind, or possibly extending an existing skin with functionality like that of ltrace. I assume most of you know this already, but ltrace is a tool for tracing calls to shared libraries on Linux (and perhaps other ELF-based systems) which can print the arguments passed to the traced function calls (using information from configuration files). Unfortunately, the way it works means that it can only catch calls through symbols that are actually included in the import table of the calling executable (or, theoretically, the calling library) -- not arbitrary calls. This is because it works by setting breakpoints in the PLT entries for the imported functions. It seems that the simplest way to avoid this problem is to actually trace the executed machine code, and implementing it in valgrind seems the simplest approach to that. So, my question is basically: if I want to do this, should I extend an existing skin to support it, create a new skin, or what? (I realize that there is no way this is going to be in the next release ;-) |
|
From: Josef W. <Jos...@gm...> - 2009-07-27 21:54:14
|
On Monday 27 July 2009, Samuel Bronson wrote: > So, my question is basically: if I want to do this, should I extend an > existing skin to support it, create a new skin, or what? Checkout Callgrind with the option "--ct-verbose=1". And then use the debug info module of Valgrind to add type, name and value information for the arguments and the return type/value (perhaps this needs improving the debug info reader?). Josef > > (I realize that there is no way this is going to be in the next > release ;-) > > ------------------------------------------------------------------------------ > Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day > trial. Simplify your report design, integration and deployment - and focus on > what you do best, core application coding. Discover what's new with > Crystal Reports now. http://p.sf.net/sfu/bobj-july > _______________________________________________ > Valgrind-developers mailing list > Val...@li... > https://lists.sourceforge.net/lists/listinfo/valgrind-developers > |
|
From: Nicholas N. <n.n...@gm...> - 2009-07-27 22:33:52
|
On Tue, Jul 28, 2009 at 7:53 AM, Josef Weidendorfer<Jos...@gm...> wrote: > On Monday 27 July 2009, Samuel Bronson wrote: >> So, my question is basically: if I want to do this, should I extend an >> existing skin to support it, create a new skin, or what? The preferred terminology these days is "tool", we haven't used "skin" for several years. > Checkout Callgrind with the option "--ct-verbose=1". > > And then use the debug info module of Valgrind to add type, name > and value information for the arguments and the return type/value > (perhaps this needs improving the debug info reader?). This might be possible, but I suspect it will not be easy, and may be hard to make robust. The problem is that Valgrind works mostly at the binary level, in terms of memory addresses, registers, system calls, etc. And your tool needs to operate at the source code level. Mapping from binary to source is difficult; you can use debug info for a lot of it... but think about things like working out where function arguments are -- they might usually be on the stack but depending on compiler optimisations they might be passed in registers. Maybe debug info can tell you that precisely (I guess GDB has to know that stuff) but whether Valgrind's debug info reading gives enough info I don't know. Nick |
|
From: Samuel B. <na...@gm...> - 2009-07-28 04:00:40
|
At Tue, 28 Jul 2009 08:33:39 +1000,
Nicholas Nethercote wrote:
>
> On Tue, Jul 28, 2009 at 7:53 AM, Josef
> Weidendorfer<Jos...@gm...> wrote:
> > And then use the debug info module of Valgrind to add type, name
> > and value information for the arguments and the return type/value
> > (perhaps this needs improving the debug info reader?).
>
> This might be possible, but I suspect it will not be easy, and may be
> hard to make robust. The problem is that Valgrind works mostly at the
> binary level, in terms of memory addresses, registers, system calls,
> etc. And your tool needs to operate at the source code level.
> Mapping from binary to source is difficult; you can use debug info
> for a lot of it... but think about things like working out where
> function arguments are -- they might usually be on the stack but
> depending on compiler optimisations they might be passed in registers.
> Maybe debug info can tell you that precisely (I guess GDB has to know
> that stuff) but whether Valgrind's debug info reading gives enough
> info I don't know.
It shouldn't be hard to at least do as well as ltrace does here; what
it does is all based on config files like this:
; ltrace.conf
;
; ~/.ltrace.conf will also be read, if it exists. The -F option may be
; used to suppress the automatic inclusion of both this file and
; ~/.ltrace.conf, and load a different config file or config files
; instead.
; Argument types:
; + == May vary (ie, is a returned value) (prefix)
; void
; int
; uint == (unsigned int)
; long
; ulong == (unsigned long)
; octal == (unsigned) [written in octal]
; char
; short == (short)
; ushort == (unsigned short)
; addr == (void *) [unsigned, written in hexa]
; file == (FILE *) [TODO]
; format == ((const char *), ...) [printf() like] [TODO]
; string == (char *)
; string[argN] == (char *) [N>0] [show only up to (arg N) bytes]
; string[eltN] == (char *) [N>0] [show only up to (elt N) bytes]
; string[retval] == (char *) [show only up to (return val) bytes]
; string[arg0] == (char *) [same as string[retval]]
; string[N] == (char *) [N>0] [show only up to N bytes]
; type* == (type *) [pointer to any other type]
; enum (key=value,key=value,...) [enumeration, see below]
; array(type,argN)
; == (type[SIZE]) [array of (arg N) elements]
; array(type,eltN)
; == (type[SIZE]) [array of (struct element N) elements]
; array(type,N) == (type[N]) [array of N elements]
; struct(type,type,...)
; == (struct {...}) [struct of several types]
;
; Backwards-compatibility:
; string0 == (char *) [same as string[retval]]
; stringN == (char *) [N>0] [same as string[argN]]
; Typedefs
;
; To make it easier to specify argument lists, you can use 'typedef'
; directives to avoid repeating complex parameter descriptors:
;
; typedef color = enum(RED=1,BLUE=2,GREEN=3)
; void draw_line(color,int,int,int,int)
; void draw_square(color,int,int,int,int)
;
; Enumerations
;
; The syntax is a parenthesized list of key=value assignments, like so:
; enum (F_DUPFD=0,F_GETFD=1,F_SETFD=2)
; an example usage might look like
; int fcntl(int,enum (F_DUPFD=0,F_GETFD=1,F_SETFD=2))
;
; Arrays
;
; NOTE: Uses of array(...) alone are very rare. You almost always
; want array(...)*. The exceptions are when you have a fixed-size
; array.
;
; Structs
;
; NOTE: Uses of struct(...) alone are very rare. You almost always
; want struct(...)* (a pointer to a struct) anyway. Most compilers
; pass structs as pointers anyway, and those that don't are not yet
; supported. The one time when you want to use a non-pointer
; struct(...) type are when you have an array of structs, or a struct
; containing another struct.
;
; For example, if you have
; struct s1 {
; int y_size;
; int * y;
; int z[3];
; struct { char c; } a;
; struct { char c; } * b;
; }
; and a function
; void f(struct s1*)
; then the corresponding ltrace spec is
; void f(struct(int,array(int,elt0),array(int,3),struct(char),struct(char)*)*)
; which, formatted similarly to the C declaration, looks like
; void f(struct(
; int,
; array(int,elt0),
; array(int,3),
; struct(char),
; struct(char)*
; )*
; )
; arpa/inet.h
int inet_aton(string,addr);
string inet_ntoa(addr); ; It isn't an ADDR but an hexa number...
addr inet_addr(string);
; bfd.h
void bfd_init(void);
int bfd_set_default_target(string);
addr bfd_scan_vma(string, addr, int);
addr bfd_openr(string,string);
int bfd_check_format(addr,int);
; ctype.h
char tolower(char);
char toupper(char);
addr __ctype_b_loc(void);
addr __ctype_tolower_loc(void);
addr __ctype_toupper_loc(void);
; curses.h
int waddch(addr, char);
int mvprintw(int, int, format);
int wmove(addr, int, int);
int waddnstr(addr, string, int);
string tgoto(string, int, int);
; dirent.h
int closedir(addr);
addr opendir(string);
addr readdir(addr);
addr readdir64(addr);
; dlfcn.h
addr dlopen(string, int);
string dlerror(void);
addr dlsym(addr, string);
int dlclose(addr);
; errno.h
addr __errno_location(void);
; fcntl.h
int open(string,int,octal); ; WARNING: 3rd argument may not be there
int open64(string,int,octal); ; WARNING: 3rd argument may not be there
; fnmatch.h
int fnmatch(string, string, int);
; getopt.h
int getopt_long(int,addr,string,addr,int*);
int getopt_long_only(int,addr,string,addr,addr);
; grp.h
void endgrent(void);
addr getgrnam(string);
void setgrent(void);
addr getgrent(void);
; libintl.h
string __dcgettext(string,string,int);
string bindtextdomain(string, string);
string textdomain(string);
; libio.h
char _IO_getc(file);
int _IO_putc(char,file);
; locale.h
string setlocale(int, string);
; mcheck.h
void mtrace(void);
void muntrace(void);
|
|
From: Josef W. <Jos...@gm...> - 2009-07-28 12:33:03
|
On Tuesday 28 July 2009, Samuel Bronson wrote: > It shouldn't be hard to at least do as well as ltrace does here; what > it does is all based on config files like this: > > ... > ; ctype.h > char tolower(char); > char toupper(char); > ... No. ltrace has one big advantage: it only logs exported symbols, which have to adhere to the ABI, ie. to a fixed convention on the given platform. For other symbols, nothing is guaranteed. Especially, argument passing for the same function could change with different compilation options. Thus, a config file can not work. You have to use debug information here. Josef |
|
From: Samuel B. <na...@gm...> - 2009-07-28 19:41:30
|
At Tue, 28 Jul 2009 14:12:50 +0200, Josef Weidendorfer wrote: > On Tuesday 28 July 2009, Samuel Bronson wrote: > > It shouldn't be hard to at least do as well as ltrace does here; what > > it does is all based on config files like this: > > > > ... > > ; ctype.h > > char tolower(char); > > char toupper(char); > > ... > > No. ltrace has one big advantage: it only logs exported symbols, > which have to adhere to the ABI, ie. to a fixed convention on the > given platform. I'd be fairly happy even with such a restriction -- the restrictions of ltrace that I'm not happy with are: * That it only traces calls performed through the PLT, not through a dynamic mechanism like dlopen()/dlsym() or through callbacks, no matter what t you put in your config files. This seems to be a fundamental limitation of ltrace, since there is no way to tell whether a given symbol represents code or data just from the symbol. * That it currently only traces calls from the main executable. This is not a fundamental limitation, but it would still probably be a pain to lift. > For other symbols, nothing is guaranteed. Especially, argument > passing for the same function could change with different > compilation options. Thus, a config file can not work. You have to > use debug information here. Well, that could certainly be added at some point, but it's not something I desire particularly strongly at this point, and I'm guessing that valgrind doesn't currently parse type information? The most interesting calls to trace are those to public APIs (or from public APIs to callbacks), anyway ;-). |