/*--------------------------------------------------------------------*/ /*--- 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-2015 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 ---*/ /*--------------------------------------------------------------------*/