@@ -428,6 +428,7 @@ AC_CHECK_DECLS([memrchr, rawmemchr],[],[],
[#define _GNU_SOURCE
#include <string.h>])
AC_CHECK_DECLS([powerof2],[],[],[#include <sys/param.h>])
+AC_CHECK_DECLS([mmap],[],[],[#include <sys/mman.h>])
AC_CHECK_DECLS([mempcpy],[],[],
[#define _GNU_SOURCE
#include <string.h>])
@@ -40,21 +40,78 @@
#include <stdlib.h>
/* System dependend headers */
+#if !defined(_WIN32)
#include <byteswap.h>
#include <endian.h>
-#include <sys/mman.h>
+#endif
+
+#if defined(_MSC_VER)
+#include <basetsd.h>
+#include <io.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/types.h>
+typedef SSIZE_T ssize_t;
+#else
#include <sys/param.h>
#include <unistd.h>
+#endif
+
+#if HAVE_DECL_MMAP
+#include <sys/mman.h>
+#endif
#if defined(HAVE_ERROR_H)
#include <error.h>
-#elif defined(HAVE_ERR_H)
+#elif defined(HAVE_ERR_H) || defined(_MSC_VER)
extern int error_message_count;
void error(int status, int errnum, const char *format, ...);
#else
#error "err.h or error.h must be available"
#endif
+#if defined(_MSC_VER)
+#define BIG_ENDIAN 4321
+#define LITTLE_ENDIAN 1234
+#define BYTE_ORDER LITTLE_ENDIAN
+static inline int ftruncate(int fd, off_t length)
+{
+ return _chsize_s(fd, length);
+}
+#endif /* defined(_MSC_VER) */
+
+#if defined(_WIN32)
+static inline uint16_t bswap_16(uint16_t x) {
+ return ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8));
+}
+
+static inline uint32_t bswap_32(uint32_t x) {
+ return (
+ (((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) |
+ (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)
+ );
+}
+
+static inline uint64_t bswap_64(uint64_t x) {
+ return (
+ (((x) & 0xff00000000000000ull) >> 56) |
+ (((x) & 0x00ff000000000000ull) >> 40) |
+ (((x) & 0x0000ff0000000000ull) >> 24) |
+ (((x) & 0x000000ff00000000ull) >> 8) |
+ (((x) & 0x00000000ff000000ull) << 8) |
+ (((x) & 0x0000000000ff0000ull) << 24) |
+ (((x) & 0x000000000000ff00ull) << 40) |
+ (((x) & 0x00000000000000ffull) << 56)
+ );
+}
+
+#define htobe64(x) bswap_64(x)
+#define be64toh(x) bswap_64(x)
+
+ssize_t pread(int fd, void *buf, size_t count, off_t offset);
+ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
+#endif /* defined(_WIN32) */
+
/* error (EXIT_FAILURE, ...) should be noreturn but on some systems it
isn't. This may cause warnings about code that should not be reachable.
So have an explicit error_exit wrapper that is noreturn (because it
new file mode 100644
@@ -0,0 +1,162 @@
+/* Copyright (C) 2022 Yonggang Luo
+ This file is part of elfutils.
+
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of either
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at
+ your option) any later version
+
+ or
+
+ * 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
+
+ or both in parallel, as here.
+
+ elfutils 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 copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include "system.h"
+
+#include <windows.h>
+
+static const struct
+{
+ DWORD winerr;
+ int doserr;
+} doserrors[] =
+
+ {
+ {ERROR_INVALID_FUNCTION, EINVAL},
+ {ERROR_FILE_NOT_FOUND, ENOENT},
+ {ERROR_PATH_NOT_FOUND, ENOENT},
+ {ERROR_TOO_MANY_OPEN_FILES, EMFILE},
+ {ERROR_ACCESS_DENIED, EACCES},
+ {ERROR_INVALID_HANDLE, EBADF},
+ {ERROR_ARENA_TRASHED, ENOMEM},
+ {ERROR_NOT_ENOUGH_MEMORY, ENOMEM},
+ {ERROR_INVALID_BLOCK, ENOMEM},
+ {ERROR_BAD_ENVIRONMENT, E2BIG},
+ {ERROR_BAD_FORMAT, ENOEXEC},
+ {ERROR_INVALID_ACCESS, EINVAL},
+ {ERROR_INVALID_DATA, EINVAL},
+ {ERROR_INVALID_DRIVE, ENOENT},
+ {ERROR_CURRENT_DIRECTORY, EACCES},
+ {ERROR_NOT_SAME_DEVICE, EXDEV},
+ {ERROR_NO_MORE_FILES, ENOENT},
+ {ERROR_LOCK_VIOLATION, EACCES},
+ {ERROR_SHARING_VIOLATION, EACCES},
+ {ERROR_BAD_NETPATH, ENOENT},
+ {ERROR_NETWORK_ACCESS_DENIED, EACCES},
+ {ERROR_BAD_NET_NAME, ENOENT},
+ {ERROR_FILE_EXISTS, EEXIST},
+ {ERROR_CANNOT_MAKE, EACCES},
+ {ERROR_FAIL_I24, EACCES},
+ {ERROR_INVALID_PARAMETER, EINVAL},
+ {ERROR_NO_PROC_SLOTS, EAGAIN},
+ {ERROR_DRIVE_LOCKED, EACCES},
+ {ERROR_BROKEN_PIPE, EPIPE},
+ {ERROR_DISK_FULL, ENOSPC},
+ {ERROR_INVALID_TARGET_HANDLE, EBADF},
+ {ERROR_INVALID_HANDLE, EINVAL},
+ {ERROR_WAIT_NO_CHILDREN, ECHILD},
+ {ERROR_CHILD_NOT_COMPLETE, ECHILD},
+ {ERROR_DIRECT_ACCESS_HANDLE, EBADF},
+ {ERROR_NEGATIVE_SEEK, EINVAL},
+ {ERROR_SEEK_ON_DEVICE, EACCES},
+ {ERROR_DIR_NOT_EMPTY, ENOTEMPTY},
+ {ERROR_NOT_LOCKED, EACCES},
+ {ERROR_BAD_PATHNAME, ENOENT},
+ {ERROR_MAX_THRDS_REACHED, EAGAIN},
+ {ERROR_LOCK_FAILED, EACCES},
+ {ERROR_ALREADY_EXISTS, EEXIST},
+ {ERROR_FILENAME_EXCED_RANGE, ENOENT},
+ {ERROR_NESTING_NOT_ALLOWED, EAGAIN},
+ {ERROR_NOT_ENOUGH_QUOTA, ENOMEM},
+ {ERROR_DELETE_PENDING, ENOENT}};
+
+static void
+_dosmaperr(unsigned long e)
+{
+ int i;
+
+ if (e == 0)
+ {
+ errno = 0;
+ return;
+ }
+
+ for (i = 0; i < sizeof(doserrors) / sizeof(doserrors[0]); i++)
+ {
+ if (doserrors[i].winerr == e)
+ {
+ int doserr = doserrors[i].doserr;
+
+ errno = doserr;
+ return;
+ }
+ }
+
+ errno = EINVAL;
+}
+
+ssize_t
+pread(int fd, void *buf, size_t count, off_t offset)
+{
+ OVERLAPPED overlapped = {0};
+ HANDLE h;
+ DWORD ret;
+
+ h = (HANDLE)_get_osfhandle(fd);
+ if (h == INVALID_HANDLE_VALUE)
+ {
+ errno = EBADF;
+ return -1;
+ }
+
+ overlapped.Offset = offset;
+ if (!ReadFile(h, buf, count, &ret, &overlapped))
+ {
+ if (GetLastError() == ERROR_HANDLE_EOF)
+ return 0;
+
+ _dosmaperr(GetLastError());
+ return -1;
+ }
+
+ return ret;
+}
+
+ssize_t
+pwrite(int fd, const void *buf, size_t count, off_t offset)
+{
+ OVERLAPPED overlapped = {0};
+ HANDLE h;
+ DWORD ret;
+
+ h = (HANDLE)_get_osfhandle(fd);
+ if (h == INVALID_HANDLE_VALUE)
+ {
+ errno = EBADF;
+ return -1;
+ }
+
+ overlapped.Offset = offset;
+ if (!WriteFile(h, buf, count, &ret, &overlapped))
+ {
+ _dosmaperr(GetLastError());
+ return -1;
+ }
+
+ return ret;
+}
@@ -96,7 +96,7 @@ sort_sections (Elf_Scn **scns, Elf_ScnList *list)
qsort (scns, scnp - scns, sizeof (*scns), compare_sections);
}
-
+#if HAVE_DECL_MMAP
static inline void
fill_mmap (size_t offset, char *last_position, char *scn_start,
char *const shdr_start, char *const shdr_end)
@@ -482,6 +482,7 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
return 0;
}
+#endif
/* Size of the buffer we use to generate the blocks of fill bytes. */
@@ -645,10 +645,12 @@ static struct Elf *
read_file (int fildes, int64_t offset, size_t maxsize,
Elf_Cmd cmd, Elf *parent)
{
+#if HAVE_DECL_MMAP
void *map_address = NULL;
int use_mmap = (cmd == ELF_C_READ_MMAP || cmd == ELF_C_RDWR_MMAP
|| cmd == ELF_C_WRITE_MMAP
|| cmd == ELF_C_READ_MMAP_PRIVATE);
+#endif
if (parent == NULL)
{
@@ -669,7 +671,7 @@ read_file (int fildes, int64_t offset, size_t maxsize,
/* The parent is already loaded. Use it. */
assert (maxsize != ~((size_t) 0));
}
-
+#if HAVE_DECL_MMAP
if (use_mmap)
{
if (parent == NULL)
@@ -713,6 +715,7 @@ read_file (int fildes, int64_t offset, size_t maxsize,
return result;
}
+#endif
/* Otherwise we have to do it the hard way. We read as much as necessary
from the file whenever we need information which is not available. */
@@ -1160,12 +1163,14 @@ elf_begin (int fildes, Elf_Cmd cmd, Elf *ref)
if (ref != NULL)
/* Make sure the descriptor is not suddenly going away. */
rwlock_rdlock (ref->lock);
+#if defined(F_GETFD)
else if (unlikely (fcntl (fildes, F_GETFD) == -1 && errno == EBADF))
{
/* We cannot do anything productive without a file descriptor. */
__libelf_seterrno (ELF_E_INVALID_FILE);
return NULL;
}
+#endif
switch (cmd)
{
@@ -222,8 +222,10 @@ elf_end (Elf *elf)
/* The file was read or mapped for this descriptor. */
if ((elf->flags & ELF_F_MALLOCED) != 0)
free (elf->map_address);
+#if HAVE_DECL_MMAP
else if ((elf->flags & ELF_F_MMAPPED) != 0)
munmap (elf->map_address, elf->maximum_size);
+#endif
}
rwlock_unlock (elf->lock);
@@ -64,7 +64,7 @@ write_file (Elf *elf, int64_t size, int change_bo, size_t shnum)
__libelf_seterrno (ELF_E_WRITE_ERROR);
return -1;
}
-
+#if HAVE_DECL_MMAP
/* Try to map the file if this isn't done yet. */
if (elf->map_address == NULL && elf->cmd == ELF_C_WRITE_MMAP)
{
@@ -125,6 +125,7 @@ write_file (Elf *elf, int64_t size, int change_bo, size_t shnum)
size = -1;
}
else
+#endif
{
/* The file is not mmaped. */
if ((class == ELFCLASS32
@@ -145,6 +146,7 @@ write_file (Elf *elf, int64_t size, int change_bo, size_t shnum)
size = -1;
}
+#if HAVE_DECL_MMAP
/* POSIX says that ftruncate and write may clear the S_ISUID and S_ISGID
mode bits. So make sure we restore them afterwards if they were set.
This is not atomic if someone else chmod's the file while we operate. */
@@ -156,6 +158,7 @@ write_file (Elf *elf, int64_t size, int change_bo, size_t shnum)
__libelf_seterrno (ELF_E_WRITE_ERROR);
size = -1;
}
+#endif
if (size != -1 && elf->parent == NULL)
elf->maximum_size = size;
@@ -195,9 +195,15 @@ typedef struct
{
char *ar_name; /* Name of archive member. */
time_t ar_date; /* File date. */
+#if defined(_WIN32)
+ long ar_uid;
+ long ar_gid;
+ unsigned long ar_mode;
+#else
uid_t ar_uid; /* User ID. */
gid_t ar_gid; /* Group ID. */
mode_t ar_mode; /* File mode. */
+#endif
int64_t ar_size; /* File size. */
char *ar_rawname; /* Original name of archive member. */
} Elf_Arhdr;
@@ -30,7 +30,11 @@
#ifndef _LIBELFP_H
#define _LIBELFP_H 1
+#if defined(_WIN32)
+#include "win32/ar.h"
+#else
#include <ar.h>
+#endif
#include <gelf.h>
#include <errno.h>
new file mode 100644
@@ -0,0 +1,52 @@
+/* Copyright (C) 2022 Yonggang Luo
+ This file is part of elfutils.
+
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of either
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at
+ your option) any later version
+
+ or
+
+ * 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
+
+ or both in parallel, as here.
+
+ elfutils 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 copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef _AR_H
+#define _AR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ARMAG "!<arch>\n"
+#define SARMAG 8
+#define ARFMAG "`\n"
+
+struct ar_hdr {
+ char ar_name[16];
+ char ar_date[12];
+ char ar_uid[6], ar_gid[6];
+ char ar_mode[8];
+ char ar_size[10];
+ char ar_fmag[2];
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif