blob: 083ed784dbe1233a8afa4add5dc96f76369755d1 [file] [log] [blame]
/*--------------------------------------------------------------------*/
/*--- An abstraction that provides a file-reading mechanism. ---*/
/*--- priv_image.h ---*/
/*--------------------------------------------------------------------*/
/*
This file is part of Valgrind, a dynamic binary instrumentation
framework.
Copyright (C) 2013-2013 Mozilla Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307, USA.
The GNU General Public License is contained in the file COPYING.
*/
/* Contributed by Julian Seward <jseward@acm.org> */
#ifndef __PRIV_IMAGE_H
#define __PRIV_IMAGE_H
#include "pub_core_basics.h" // ULong
#include "priv_misc.h" // ML_(dinfo_zalloc)
/*------------------------------------------------------------*/
/*--- DiImage -- abstract images ---*/
/*------------------------------------------------------------*/
/* The basic type, containing an abstractified memory area that can be
read from. This is an abstract type since there can be more than
one implementation of it. */
/* abstract */
typedef struct _DiImage DiImage;
/* an offset in the image */
typedef ULong DiOffT;
/* This denotes an invalid DiOffT value. Except where otherwise
noted, you must never pass this to any of the ML_(image_*)
functions -- they will assert. That does mean though that they can
be used for signalling other conditions, for example that some
expected part of the image is missing. */
#define DiOffT_INVALID ((DiOffT)(0xFFFFFFFFFFFFFFFFULL))
/* Create an image from a file in the local filesysem. Returns NULL
if it fails, for whatever reason. */
DiImage* ML_(img_from_local_file)(const HChar* fullpath);
/* Create an image by connecting to a Valgrind debuginfo server
(auxprogs/valgrind-di-server.c). |filename| contains the object
name to ask for; it must be a plain filename, not absolute, not a
path. |serverAddr| must be of the form either "d.d.d.d" or
"d.d.d.d:d" where d is one or more digits. These specify the IPv4
address and (in the second case) port number for the server. In
the first case, port 1500 is assumed. */
DiImage* ML_(img_from_di_server)(const HChar* filename,
const HChar* serverAddr);
/* Destroy an existing image. */
void ML_(img_done)(DiImage*);
/* How big is the image? */
DiOffT ML_(img_size)(const DiImage* img);
/* Does the section [offset, +size) exist in the image? */
Bool ML_(img_valid)(const DiImage* img, DiOffT offset, SizeT size);
/* Get info out of an image. If any part of the section denoted by
[offset, +size) is invalid, does not return. */
void ML_(img_get)(/*OUT*/void* dst,
DiImage* img, DiOffT offset, SizeT size);
/* A version of ML_(img_get) that is significantly cheaper when
fetching a lot of data, at the cost of being more difficult to use.
Fetches between 1 and |size| bytes from |img| at |offset| and
places them in |dst|. |size| must be at least 1. The number of
bytes read is returned, and the caller must be able to deal with
any number between 1 and |size|. |offset| must be a valid offset
in the image; if not the function will not return. This function
will not read off the end of the image. */
SizeT ML_(img_get_some)(/*OUT*/void* dst,
DiImage* img, DiOffT offset, SizeT size);
/* Copy a C string out of the image, into ML_(dinfo_zalloc)'d space.
The caller owns the string and must free it with ML_(dinfo_free).
|offset| may be DiOffT_INVALID, in which case this returns NULL. */
HChar* ML_(img_strdup)(DiImage* img, const HChar* cc, DiOffT offset);
/* Do strcmp on two C strings in the image. Chars are cast to HChar
before comparison. */
Int ML_(img_strcmp)(DiImage* img, DiOffT off1, DiOffT off2);
/* Do strcmp of a C string in the image vs a normal one. Chars are
cast to HChar before comparison. */
Int ML_(img_strcmp_c)(DiImage* img, DiOffT off1, const HChar* str2);
/* Do strlen of a C string in the image. */
SizeT ML_(img_strlen)(DiImage* img, DiOffT off);
/* Fetch various sized primitive types from the image. These operate
at the endianness and word size of the host. */
UChar ML_(img_get_UChar) (DiImage* img, DiOffT offset);
UShort ML_(img_get_UShort)(DiImage* img, DiOffT offset);
UInt ML_(img_get_UInt) (DiImage* img, DiOffT offset);
ULong ML_(img_get_ULong) (DiImage* img, DiOffT offset);
/* Calculate the "GNU Debuglink CRC" for the image. This
unfortunately has to be done as part of the DiImage implementation
because it involves reading the entire image, and is therefore
something that needs to be handed off to the remote server -- since
to do it otherwise would imply pulling the entire image across the
connection, making the client/server split pointless. */
UInt ML_(img_calc_gnu_debuglink_crc32)(DiImage* img);
/*------------------------------------------------------------*/
/*--- DiCursor -- cursors for reading images ---*/
/*------------------------------------------------------------*/
/* A type built on DiImage. It contains a DiImage and a 'current
offset' in the image, and is useful for building low level readers
of images. In the functions section below, "read" means "read data
at the cursor without moving it along", and "step" means "read data
at the cursor and move it along by the size of the item read". */
typedef
struct { DiImage* img; DiOffT ioff; }
DiCursor;
/* An invalid cursor. You can't use it for anything. */
#define DiCursor_INVALID ((DiCursor){NULL,DiOffT_INVALID})
static inline DiCursor mk_DiCursor ( DiImage* img, DiOffT ioff ) {
return (DiCursor){img, ioff};
}
static inline Bool ML_(cur_is_valid)(DiCursor c) {
return c.img != NULL;
}
/*------------------------------------------------------------*/
/*--- DiSlice -- subranges within DiImages ---*/
/*------------------------------------------------------------*/
/* Another type built on top of DiImage. It denotes a subrange of an
image and is useful for representing (eg) exactly the part of an
image that is a specific ELF section. */
typedef
struct { DiImage* img; DiOffT ioff; DiOffT szB; }
DiSlice;
/* A DiSlice can also be INVALID, meaning it does not refer to any
part of any image. */
#define DiSlice_INVALID ((DiSlice){NULL,DiOffT_INVALID,0})
static inline DiSlice mk_DiSlice ( DiImage* img, DiOffT ioff, DiOffT szB ) {
return (DiSlice){img, ioff, szB};
}
static inline Bool ML_(sli_is_valid)( DiSlice sli ) {
return sli.img != NULL;
}
/* Create a slice from a combination of a cursor and a length. The
maximum implied offset must not exceed the size of the underlying
image; this is asserted for. */
static inline DiSlice ML_(sli_from_cur)( DiCursor cur, DiOffT size ) {
if (ML_(cur_is_valid)(cur)) {
vg_assert(size != DiOffT_INVALID);
vg_assert(cur.ioff + size <= ML_(img_size)(cur.img));
return mk_DiSlice(cur.img, cur.ioff, size);
} else {
return DiSlice_INVALID;
}
}
/* Create a slice which exactly covers the given image. */
static inline DiSlice ML_(sli_from_img)( DiImage* img ) {
if (img) {
return mk_DiSlice(img, 0, ML_(img_size)(img));
} else {
return DiSlice_INVALID;
}
}
/*------------------------------------------------------------*/
/*--- Functions that operate on DiCursors ---*/
/*------------------------------------------------------------*/
/* Create a cursor from a slice, referring to the first byte of the
slice. */
static inline DiCursor ML_(cur_from_sli)( DiSlice sl ) {
if (ML_(sli_is_valid)(sl)) {
DiCursor c;
c.img = sl.img;
c.ioff = sl.ioff;
return c;
} else {
return DiCursor_INVALID;
}
}
static inline Bool ML_(cur_cmpLT)( DiCursor c1, DiCursor c2 ) {
vg_assert(c1.img == c2.img);
return c1.ioff < c2.ioff;
}
static inline Bool ML_(cur_cmpEQ)( DiCursor c1, DiCursor c2 ) {
vg_assert(c1.img == c2.img);
return c1.ioff == c2.ioff;
}
static inline Bool ML_(cur_cmpGT)( DiCursor c1, DiCursor c2 ) {
vg_assert(c1.img == c2.img);
return c1.ioff > c2.ioff;
}
static inline DiCursor ML_(cur_plus)( DiCursor c, Long n ) {
c.ioff += (DiOffT)n;
return c;
}
/* Asserts that c1 and c2 refer to the same image. Returns the difference
in offsets (c1.ioff - c2.ioff). */
static inline Long ML_(cur_minus)( DiCursor c1, DiCursor c2 ) {
vg_assert(c1.img == c2.img);
return (Long)(c1.ioff) - (Long)(c2.ioff);
}
static inline SizeT ML_(cur_strlen)( DiCursor c ) {
return ML_(img_strlen)( c.img, c.ioff );
}
// strdup from the given cursor. Caller must ML_(dinfo_free) the
// resulting string.
static inline HChar* ML_(cur_read_strdup)( DiCursor c, const HChar* cc ) {
vg_assert(c.ioff != DiOffT_INVALID);
HChar* res = ML_(img_strdup)(c.img, cc, c.ioff);
return res;
}
// strdup from the given cursor and advance it. Caller must
// ML_(dinfo_free) the resulting string.
static inline HChar* ML_(cur_step_strdup)( DiCursor* c, const HChar* cc ) {
vg_assert(c->ioff != DiOffT_INVALID);
HChar* res = ML_(img_strdup)(c->img, cc, c->ioff);
c->ioff += VG_(strlen)(res) + 1;
return res;
}
// Fetch an arbitrary number of bytes from the cursor.
static inline void ML_(cur_read_get) ( /*OUT*/void* dst,
DiCursor c, SizeT size) {
ML_(img_get)(dst, c.img, c.ioff, size);
}
// Fetch an arbitrary number of bytes from the cursor, and advance it.
static inline void ML_(cur_step_get) ( /*OUT*/void* dst,
DiCursor* c, SizeT size) {
ML_(img_get)(dst, c->img, c->ioff, size);
c->ioff += size;
}
// memdup from the given cursor. Caller must ML_(dinfo_free) the
// resulting block.
static inline UChar* ML_(cur_read_memdup)( DiCursor c, SizeT size,
const HChar* cc )
{
UChar* dst = ML_(dinfo_zalloc)(cc, size);
if (size > 0)
ML_(cur_read_get)(dst, c, size);
return dst;
}
static inline UChar ML_(cur_read_UChar) ( DiCursor c ) {
UChar r = ML_(img_get_UChar)( c.img, c.ioff );
return r;
}
static inline UChar ML_(cur_step_UChar)( DiCursor* c ) {
UChar r = ML_(img_get_UChar)( c->img, c->ioff );
c->ioff += sizeof(UChar);
return r;
}
static inline UShort ML_(cur_read_UShort) ( DiCursor c ) {
UShort r = ML_(img_get_UShort)( c.img, c.ioff );
return r;
}
static inline UShort ML_(cur_step_UShort) ( DiCursor* c ) {
UShort r = ML_(img_get_UShort)( c->img, c->ioff );
c->ioff += sizeof(UShort);
return r;
}
static inline Short ML_(cur_step_Short) ( DiCursor* c ) {
return (Short)ML_(cur_step_UShort)( c );
}
static inline UInt ML_(cur_read_UInt) ( DiCursor c ) {
UInt r = ML_(img_get_UInt)( c.img, c.ioff );
return r;
}
static inline UInt ML_(cur_step_UInt) ( DiCursor* c ) {
UInt r = ML_(img_get_UInt)( c->img, c->ioff );
c->ioff += sizeof(UInt);
return r;
}
static inline Int ML_(cur_step_Int) ( DiCursor* c ) {
return (Int)ML_(cur_step_UInt)( c );
}
static inline ULong ML_(cur_read_ULong) ( DiCursor c ) {
ULong r = ML_(img_get_ULong)( c.img, c.ioff );
return r;
}
static inline ULong ML_(cur_step_ULong) ( DiCursor* c ) {
ULong r = ML_(img_get_ULong)( c->img, c->ioff );
c->ioff += sizeof(ULong);
return r;
}
static inline Long ML_(cur_step_Long) ( DiCursor* c ) {
return (Long)ML_(cur_step_ULong)( c );
}
static inline Addr ML_(cur_step_Addr) ( DiCursor* c ) {
if (sizeof(Addr) == sizeof(UInt)) {
return ML_(cur_step_UInt)(c);
} else if (sizeof(Addr) == sizeof(ULong)) {
return ML_(cur_step_ULong)(c);
} else {
vg_assert(0);
}
}
#endif /* ndef __PRIV_IMAGE_H */
/*--------------------------------------------------------------------*/
/*--- end priv_image.h ---*/
/*--------------------------------------------------------------------*/