diff options
-rw-r--r-- | Makefile.android | 1 | ||||
-rw-r--r-- | android/utils/mapfile.c | 250 | ||||
-rw-r--r-- | android/utils/mapfile.h | 133 | ||||
-rw-r--r-- | elff/elf.h | 16 | ||||
-rw-r--r-- | elff/elf_file.cc | 92 | ||||
-rw-r--r-- | elff/elf_file.h | 3 | ||||
-rw-r--r-- | elff/elf_mapped_section.cc | 75 | ||||
-rw-r--r-- | elff/elf_mapped_section.h | 3 |
8 files changed, 414 insertions, 159 deletions
diff --git a/Makefile.android b/Makefile.android index 1929cb3..0b719e0 100644 --- a/Makefile.android +++ b/Makefile.android @@ -604,6 +604,7 @@ VL_SOURCES := vl-android.c osdep.c cutils.c \ android/utils/system.c \ android/utils/tempfile.c \ android/utils/timezone.c \ + android/utils/mapfile.c \ android/avd/hw-config.c \ android/avd/info.c \ diff --git a/android/utils/mapfile.c b/android/utils/mapfile.c new file mode 100644 index 0000000..f964d38 --- /dev/null +++ b/android/utils/mapfile.c @@ -0,0 +1,250 @@ +/* Copyright (C) 2007-2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** 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. +*/ + +/* + * Contains implementation of routines that implement platform-independent + * file I/O. + */ + +#include "stddef.h" +#include "sys/types.h" +#include "errno.h" +#ifdef WIN32 +#include "Windows.h" +#else // WIN32 +#include <sys/mman.h> +#endif // WIN32 +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "mapfile.h" + +MapFile* +mapfile_open(const char* path, int oflag, int share_mode) +{ +#ifdef WIN32 + DWORD win32_share; + DWORD win32_desired_access; + DWORD win32_disposition; + DWORD win32_flags; + + /* Convert to Win32 desired access. */ + if ((oflag & O_RDWR) == O_RDWR) { + win32_desired_access = GENERIC_READ | GENERIC_WRITE; + } else if ((oflag & O_ACCMODE) == O_RDONLY) { + win32_desired_access = GENERIC_READ; + } else if ((oflag & O_WRONLY) == O_WRONLY) { + win32_desired_access = GENERIC_WRITE; + } + + /* Convert to Win32 sharing. */ + win32_share = 0; + if ((share_mode & S_IWRITE) != 0) { + win32_share |= FILE_SHARE_WRITE; + } + if ((share_mode & S_IREAD) != 0) { + win32_share |= FILE_SHARE_READ; + } + + /* Convert to Win32 disposition. */ + if ((oflag & O_CREAT) == O_CREAT) { + if ((oflag & O_EXCL) == O_EXCL) { + win32_disposition = CREATE_NEW; + } else { + win32_disposition = OPEN_ALWAYS; + } + } if ((oflag & O_TRUNC) == O_TRUNC) { + win32_desired_access = TRUNCATE_EXISTING; + } else { + win32_disposition = OPEN_EXISTING; + } + + /* Convert to Win32 flags. */ + win32_flags = 0; +#if defined(O_DSYNC) + if ((oflag & O_DSYNC) == O_DSYNC || + (oflag & O_RSYNC) == O_RSYNC || + (oflag & O_RSYNC) == O_SYNC) { + win32_flags |= FILE_FLAG_WRITE_THROUGH; + } +#endif // O_DSYNC + + HANDLE file_handle = CreateFile(path, win32_desired_access, win32_share, + NULL, win32_disposition, win32_flags, NULL); + if (file_handle == INVALID_HANDLE_VALUE) { + errno = GetLastError(); + } +#else // WIN32 + int file_handle = open(path, oflag, share_mode); +#endif // WIN32 + + return (MapFile*)file_handle; +} + +int +mapfile_close(MapFile* handle) +{ +#ifdef WIN32 + if (CloseHandle(handle)) { + return 0; + } else { + errno = GetLastError(); + return -1; + } +#else // WIN32 + return close((int)handle); +#endif // WIN32 +} + +ssize_t +mapfile_read(MapFile* handle, void* buf, size_t nbyte) +{ +#ifdef WIN32 + ssize_t ret_bytes; + DWORD read_bytes; + if (ReadFile(handle, buf, nbyte, &read_bytes, NULL)) { + ret_bytes = (ssize_t)read_bytes; + } else { + errno = GetLastError(); + ret_bytes = -1; + } + return ret_bytes; +#else // WIN32 + ssize_t ret; + do { + ret = read((int)handle, buf, nbyte); + } while (ret < 0 && errno == EINTR); + return ret; +#endif // WIN32 +} + +ssize_t +mapfile_read_at(MapFile* handle, size_t offset, void* buf, size_t nbyte) +{ +#ifdef WIN32 + LARGE_INTEGER convert; + convert.QuadPart = offset; + if ((SetFilePointer(handle, convert.LowPart, &convert.HighPart, + FILE_BEGIN) == INVALID_SET_FILE_POINTER) && + (GetLastError() != NO_ERROR)) { + errno = GetLastError(); + return -1; + } + return mapfile_read(handle, buf, nbyte); +#else // WIN32 + ssize_t res = lseek((int)handle, offset, SEEK_SET); + return res >= 0 ? mapfile_read(handle, buf, nbyte) : res; +#endif // WIN32 +} + +void* +mapfile_map(MapFile* handle, + size_t offset, + size_t size, + int prot, + void** mapped_offset, + size_t* mapped_size) +{ + void* mapped_at = NULL; + size_t align_mask; + size_t map_offset; + size_t map_size; + + /* Get the mask for mapping offset alignment. */ +#ifdef WIN32 + DWORD win32_prot; + DWORD win32_map; + HANDLE map_handle; + LARGE_INTEGER converter; + SYSTEM_INFO sys_info; + GetSystemInfo(&sys_info); + align_mask = sys_info.dwAllocationGranularity - 1; +#else // WIN32 + align_mask = getpagesize() - 1; +#endif // WIN32 + + /* Adjust mapping offset and mapping size accordingly to + * the mapping alignment requirements. */ + map_offset = offset & ~align_mask; + map_size = (size_t)(offset - map_offset + size); + + /* Make sure mapping size doesn't exceed 4G. */ + if (map_size < size) { + errno = EFBIG; + return NULL; + } + + /* Map the section. */ +#ifdef WIN32 + /* Convert to Win32 page protection and mapping type. */ + win32_prot = PAGE_READONLY; + win32_map = FILE_MAP_READ; + if (prot != PROT_NONE) { + if ((prot & (PROT_WRITE | PROT_EXEC)) == 0) { + win32_prot = PAGE_READONLY; + win32_map = FILE_MAP_READ; + } else if ((prot & (PROT_WRITE | PROT_EXEC)) == + (PROT_WRITE | PROT_EXEC)) { + win32_prot = PAGE_EXECUTE_READWRITE; + win32_map = FILE_MAP_WRITE; + } else if ((prot & PROT_WRITE) == PROT_WRITE) { + win32_prot = PAGE_READWRITE; + win32_map = FILE_MAP_WRITE; + } else if ((prot & PROT_EXEC) == PROT_EXEC) { + win32_prot = PAGE_EXECUTE_READ; + win32_map = FILE_MAP_READ; + } + } + + converter.QuadPart = map_offset + map_size; + map_handle = CreateFileMapping(handle, NULL, win32_prot, + converter.HighPart, converter.LowPart, NULL); + if (map_handle != NULL) { + converter.QuadPart = map_offset; + mapped_at = MapViewOfFile(map_handle, win32_map, converter.HighPart, + converter.LowPart, map_size); + /* Memory mapping (if successful) will hold extra references to the + * mapping, so we can close it right after we mapped file view. */ + CloseHandle(map_handle); + } + if (mapped_at == NULL) { + errno = GetLastError(); + return NULL; + } +#else // WIN32 + mapped_at = + mmap(0, map_size, PROT_READ, MAP_SHARED, (int)handle, map_offset); + if (mapped_at == MAP_FAILED) { + return NULL; + } +#endif // WIN32 + + *mapped_offset = (char*)mapped_at + (offset - map_offset); + *mapped_size = size; + + return mapped_at; +} + +int +mapfile_unmap(void* mapped_at, size_t len) +{ +#ifdef WIN32 + if (!UnmapViewOfFile(mapped_at)) { + errno = GetLastError(); + return -1; + } + return 0; +#else // WIN32 + return munmap(mapped_at, len); +#endif // WIN32 +} diff --git a/android/utils/mapfile.h b/android/utils/mapfile.h new file mode 100644 index 0000000..c125337 --- /dev/null +++ b/android/utils/mapfile.h @@ -0,0 +1,133 @@ +/* Copyright (C) 2007-2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** 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. +*/ + +/* + * Contains declarations of routines that implement platform-independent + * file I/O. + */ + +#ifndef _ANDROID_UTILS_FILEIO_H +#define _ANDROID_UTILS_FILEIO_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MapFile MapFile; + +#ifdef WIN32 +/* Declare constants that are missing in Win32 headers. */ +#define PROT_READ 0x1 +#define PROT_WRITE 0x2 +#define PROT_EXEC 0x4 +#define PROT_NONE 0x0 +#endif + +/* Checks if file handle is a valid one. + * Return: + * boolean: 1 if handle is valid, or 0 if it's not valid. + */ +static inline int +mapfile_is_valid(MapFile* handle) +{ + return (int)handle != -1; +} + +/* Opens file in selected mode. + * Param: + * path - Path to the file to open. + * oflag - Defines mode in which file is to be opened. This value follows the + * symantics of O_XXX flags defined for standard open routine. + * share_mode Defines sharing mode for the opened file. This value follows the + * symantics of S_IXXX flags defined for standard open routine. + * Return: + * A valid handle to the opened file on success, or an invalid value on + * failure. In case of failure errno contains error code. + */ +extern MapFile* mapfile_open(const char* path, int oflag, int share_mode); + +/* Closes a file handle opened with mapfile_open routine. + * Param: + * handle - A handle to a file previously obtained via successful call to + * mapfile_open routine. + * Return: + * 0 on success, or -1 on failure with errno containing the error code. + */ +extern int mapfile_close(MapFile* handle); + +/* Reads from a file opened with mapfile_open routine. + * Except for handle parameter, semantics of this call are the same as for + * the regualar read routine. + * Param: + * handle - A handle to a file previously obtained via successful call to + * mapfile_open routine. + */ +extern ssize_t mapfile_read(MapFile* handle, void* buf, size_t nbyte); + +/* Reads from a specific offset in a file opened with mapfile_open routine. + * Param: + * handle - A handle to a file previously obtained via successful call to + * mapfile_open routine. + * offset - Offset in the file where to start reading from. + * Rest of the parameters and return value are the same as in file_read. + */ +extern ssize_t mapfile_read_at(MapFile* handle, + size_t offset, + void* buf, + size_t nbyte); + +/* Maps a section of a file to memory. + * Param: + * handle - A handle to a file previously obtained via successful call to + * mapfile_open routine. + * offset - Offset in the file where mapping should begin. + * size - Number of bytes starting with offset that should be mapped. + * prot - Determines whether read, write, execute, or some combination of + * accesses are permitted to the data being mapped. This parameter has the + * same semantics as in regular mmap routene. + * mapped_offset - Upon success, contains pointer to the requested offset + * within the mapped section of the file. + * size - Upon success, contains total number of bytes that were actually + * mapped. + * Return: + * Upon successful completion returns pointer to the beginning of memory + * mapping, containing mapping of the requested section of a file. Note that + * value returned from this routine doesn't necessarily points to the beginning + * of the requested section mapping. Use value returned in mapped_offset + * parameter to get actual pointer to the beginning of the requested section + * mapping. Value returned from this routine must eventually be passed to + * file_unmap_section reoutine to unmap section mapped with this routine. + * This routine returns NULL on failure and sets errno to indicate the error. + */ +extern void* mapfile_map(MapFile* handle, + size_t offset, + size_t size, + int prot, + void** mapped_offset, + size_t* mapped_size); + +/* Umaps section of a file previously mapped with mapfile_map routine. + * Param: + * mapped_at - A pointer to the base address of the mapped section of a file + * that is to be unmapped. + * len - Byte size of the section that is to be unmapped. + * Return: + * Upon successful completion returns 0. Otherwise, returns -1 and sets + * errno to indicate the error. + */ +extern int mapfile_unmap(void* mapped_at, size_t len); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif // _ANDROID_UTILS_FILEIO_H @@ -27,22 +27,6 @@ extern "C" { // ELF file definitions //============================================================================= -#ifdef WIN32 -typedef HANDLE ELF_FILE_HANDLE; -#define INVALID_ELF_FILE_HANDLE INVALID_HANDLE_VALUE -#define close_elf_file_handle CloseHandle -#else // WIN32 -typedef int ELF_FILE_HANDLE; -#define INVALID_ELF_FILE_HANDLE -1 -#define close_elf_file_handle close -#endif // WIN32 - -/* Checks if ELF file handle is valid. */ -static inline bool -elfhandle_is_valid(ELF_FILE_HANDLE handle) { - return handle != INVALID_ELF_FILE_HANDLE; -} - /* * ELF format documentation uses Elf##_Xxx notation for data types, where * ## stands for CPU architecture (32, or 64 bit), and Xxx stands for a diff --git a/elff/elf_file.cc b/elff/elf_file.cc index 70ed81c..39aa371 100644 --- a/elff/elf_file.cc +++ b/elff/elf_file.cc @@ -43,7 +43,7 @@ ElfFile::ElfFile() allocator_(NULL),
fixed_base_address_(0),
is_exec_(0),
- elf_handle_(INVALID_ELF_FILE_HANDLE),
+ elf_handle_((MapFile*)-1),
sec_entry_size_(0) {
}
@@ -55,8 +55,8 @@ ElfFile::~ElfFile() { cu_to_del = next_cu_to_del;
}
- if (elfhandle_is_valid(elf_handle_)) {
- close_elf_file_handle(elf_handle_);
+ if (mapfile_is_valid(elf_handle_)) {
+ mapfile_close(elf_handle_);
}
if (elf_file_path_ != NULL) {
@@ -88,33 +88,12 @@ ElfFile* ElfFile::Create(const char* path) { /*
* Open ELF file, and read its header (the largest one possible).
*/
-
-#ifdef WIN32
- HANDLE file_handle = CreateFile(path, GENERIC_READ,
- FILE_SHARE_READ, NULL, OPEN_EXISTING,
- FILE_FLAG_RANDOM_ACCESS, NULL);
- assert(file_handle != INVALID_HANDLE_VALUE);
- if (file_handle == INVALID_HANDLE_VALUE) {
- _set_errno(GetLastError());
- return NULL;
- }
-
- DWORD read_bytes;
- BOOL res = ReadFile(file_handle, &header, sizeof(header), &read_bytes, NULL);
- CloseHandle(file_handle);
- assert(res && read_bytes == sizeof(header));
- if (!res || read_bytes != sizeof(header)) {
- _set_errno(GetLastError());
- return NULL;
- }
-#else // WIN32
- int file_handle = open(path, O_RDONLY | O_BINARY, 0);
- assert(file_handle >= 0);
- if (file_handle < 0) {
+ MapFile* file_handle = mapfile_open(path, O_RDONLY | O_BINARY, 0);
+ if (!mapfile_is_valid(file_handle)) {
return NULL;
}
- const ssize_t read_bytes = read(file_handle, &header, sizeof(header));
- close(file_handle);
+ const ssize_t read_bytes = mapfile_read(file_handle, &header, sizeof(header));
+ mapfile_close(file_handle);
assert(read_bytes != -1 && read_bytes == sizeof(header));
if (read_bytes == -1 || read_bytes != sizeof(header)) {
if (read_bytes != -1) {
@@ -122,7 +101,6 @@ ElfFile* ElfFile::Create(const char* path) { }
return NULL;
}
-#endif // WIN32
/* Lets see if this is an ELF file at all. */
if (memcmp(elf_hdr->e_ident, ELFMAG, SELFMAG) != 0) {
@@ -186,25 +164,8 @@ bool ElfFile::initialize(const Elf_CommonHdr* elf_hdr, const char* path) { is_exec_ = elf_hdr->e_type == 2;
/* Reopen file for further reads and mappings. */
-#ifdef WIN32
- elf_handle_ = CreateFile(elf_file_path_, GENERIC_READ,
- FILE_SHARE_READ, NULL, OPEN_EXISTING,
- FILE_FLAG_RANDOM_ACCESS, NULL);
- assert(elf_handle_ != INVALID_HANDLE_VALUE);
- if (elf_handle_ == INVALID_HANDLE_VALUE) {
- _set_errno(GetLastError());
- return false;
- }
-#else // WIN32
- elf_handle_ = open(elf_file_path_, O_RDONLY | O_BINARY, 0);
- assert(elf_handle_ >= 0);
- if (elf_handle_ < 0) {
- elf_handle_ = INVALID_ELF_FILE_HANDLE;
- return false;
- }
-#endif // WIN32
-
- return true;
+ elf_handle_ = mapfile_open(elf_file_path_, O_RDONLY | O_BINARY, 0);
+ return mapfile_is_valid(elf_handle_);
}
bool ElfFile::get_pc_address_info(Elf_Xword address,
@@ -386,39 +347,10 @@ bool ElfFileImpl<Elf_Addr, Elf_Off>::initialize(const Elf_CommonHdr* elf_hdr, _set_errno(ENOMEM);
return false;
}
-#ifdef WIN32
- LARGE_INTEGER convert;
- convert.QuadPart = sec_table_off;
- if ((SetFilePointer(elf_handle_, convert.LowPart,
- &convert.HighPart,
- FILE_BEGIN) == INVALID_SET_FILE_POINTER) &&
- (GetLastError() != NO_ERROR)) {
- _set_errno(GetLastError());
- return false;
- }
- DWORD read_bytes;
- BOOL res =
- ReadFile(elf_handle_, sec_table_, sec_table_size, &read_bytes, NULL);
- assert(res && read_bytes == sec_table_size);
- if (!res || read_bytes != sec_table_size) {
- _set_errno(GetLastError());
- return false;
- }
-#else // WIN32
- ssize_t res = lseek(elf_handle_, sec_table_off, SEEK_SET);
- assert(res != -1);
- if (res == -1) {
- return false;
- }
- res = read(elf_handle_, sec_table_, sec_table_size);
- assert(res != -1 && res == sec_table_size);
- if (res == -1 || res != sec_table_size) {
- if (res != -1) {
- _set_errno(EINVAL);
- }
- return false;
+ if (mapfile_read_at(elf_handle_, sec_table_off, sec_table_,
+ sec_table_size) < 0) {
+ return false;
}
-#endif // WIN32
/* Map ELF's string section (must have one!). */
const Elf_Half str_sec_index = pull_val(header->e_shstrndx);
diff --git a/elff/elf_file.h b/elff/elf_file.h index 6c57bde..c92fdfb 100644 --- a/elff/elf_file.h +++ b/elff/elf_file.h @@ -20,6 +20,7 @@ #include "dwarf_die.h"
#include "elf_mapped_section.h"
#include "elff_api.h"
+#include "android/utils/mapfile.h"
/* Encapsulates architecture-independent functionality of an ELF file.
*
@@ -510,7 +511,7 @@ class ElfFile { Elf_Xword fixed_base_address_;
/* Handle to the ELF file represented with this instance. */
- ELF_FILE_HANDLE elf_handle_;
+ MapFile* elf_handle_;
/* Path to the ELF file represented with this instance. */
char* elf_file_path_;
diff --git a/elff/elf_mapped_section.cc b/elff/elf_mapped_section.cc index 46fc6b6..60cd21f 100644 --- a/elff/elf_mapped_section.cc +++ b/elff/elf_mapped_section.cc @@ -26,70 +26,23 @@ ElfMappedSection::ElfMappedSection() ElfMappedSection::~ElfMappedSection() {
if (mapped_at_ != NULL) {
-#ifdef WIN32
- UnmapViewOfFile(mapped_at_);
-#else // WIN32
- munmap(mapped_at_, diff_ptr(mapped_at_, data_) + size_);
-#endif // WIN32
+ mapfile_unmap(mapped_at_, diff_ptr(mapped_at_, data_) + size_);
}
}
-bool ElfMappedSection::map(ELF_FILE_HANDLE handle,
+bool ElfMappedSection::map(MapFile* handle,
Elf_Xword offset,
Elf_Word size) {
- /* Get the mask for mapping offset alignment. */
-#ifdef WIN32
- SYSTEM_INFO sys_info;
- GetSystemInfo(&sys_info);
- const Elf_Xword align_mask = sys_info.dwAllocationGranularity - 1;
-#else // WIN32
- const Elf_Xword align_mask = getpagesize() - 1;
-#endif // WIN32
-
- /* Adjust mapping offset and mapping size accordingly to
- * the mapping alignment requirements. */
- const Elf_Xword map_offset = offset & ~align_mask;
- const Elf_Word map_size = static_cast<Elf_Word>(offset - map_offset + size);
-
- /* Make sure mapping size doesn't exceed 4G: may happen on 64-bit ELFs, if
- * section size is close to 4G, while section offset is badly misaligned. */
- assert(map_size >= size);
- if (map_size < size) {
- _set_errno(EFBIG);
- return false;
- }
-
- /* Map the section. */
-#ifdef WIN32
- LARGE_INTEGER converter;
- converter.QuadPart = map_offset + map_size;
- HANDLE map_handle = CreateFileMapping(handle, NULL, PAGE_READONLY,
- converter.HighPart, converter.LowPart,
- NULL);
- assert(map_handle != NULL);
- if (map_handle != NULL) {
- converter.QuadPart = map_offset;
- mapped_at_ = MapViewOfFile(map_handle, FILE_MAP_READ, converter.HighPart,
- converter.LowPart, map_size);
- assert(mapped_at_ != NULL);
- /* Memory mapping (if successful) will hold extra references to the
- * mapping, so we can close it right after we mapped file view. */
- CloseHandle(map_handle);
- }
- if (mapped_at_ == NULL) {
- _set_errno(GetLastError());
- return false;
- }
-#else // WIN32
- mapped_at_ = mmap(0, map_size, PROT_READ, MAP_SHARED, handle, map_offset);
- assert(mapped_at_ != MAP_FAILED);
- if (mapped_at_ == MAP_FAILED) {
- return false;
- }
-#endif // WIN32
-
- data_ = INC_CPTR(mapped_at_, offset - map_offset);
- size_ = size;
-
- return true;
+ void* section_ptr;
+ size_t mapped_bytes;
+ mapped_at_ = mapfile_map(handle, offset, size, PROT_READ,
+ §ion_ptr, &mapped_bytes);
+ if (mapped_at_ == NULL) {
+ return false;
+ }
+
+ data_ = section_ptr;
+ size_ = (Elf_Word)mapped_bytes;
+
+ return true;
}
diff --git a/elff/elf_mapped_section.h b/elff/elf_mapped_section.h index 2f3ca56..7da608d 100644 --- a/elff/elf_mapped_section.h +++ b/elff/elf_mapped_section.h @@ -19,6 +19,7 @@ #define ELFF_ELF_MAPPED_SECTION_H_
#include "elf_defs.h"
+#include "android/utils/mapfile.h"
/* Encapsulates a section of an ELF file, mapped to memory. */
class ElfMappedSection {
@@ -45,7 +46,7 @@ class ElfMappedSection { * NOTE: if section has already been mapped, this method immediately
* returns with success.
*/
- bool map(ELF_FILE_HANDLE handle, Elf_Xword offset, Elf_Word size);
+ bool map(MapFile* handle, Elf_Xword offset, Elf_Word size);
/* Checks if section has been mapped. */
bool is_mapped() const {
|