Compare commits

...

19 Commits

Author SHA1 Message Date
Chris Webb
f38ceb5a8a Merge from upstream libelf 0.194 2025-10-27 20:39:21 +00:00
Chris Webb
6188fbeb25 Update upstream files from elfutils 0.194 2025-10-27 20:39:21 +00:00
Chris Webb
288355d104 Merge from upstream libelf 0.193 2025-04-26 11:09:35 +01:00
Chris Webb
e12821ffb2 Update upstream files from elfutils 0.193 2025-04-26 11:09:35 +01:00
Chris Webb
b5edd4a1e4 Merge from upstream libelf 0.192 2024-10-20 10:25:43 +01:00
Chris Webb
4015076fe6 Add missing upstream eu-search.c from elfutils 0.192 2024-10-20 09:18:18 +01:00
Chris Webb
c682a83511 Include missing eu-search.c from upstream 2024-10-20 09:14:49 +01:00
Chris Webb
bc189e2914 Update upstream files from elfutils 0.192 2024-10-19 14:32:37 +01:00
Chris Webb
f918d99c1e Merge from upstream libelf 0.192 2024-10-19 14:32:37 +01:00
Chris Webb
95564b26d3 Include upstream eu-search.h and locks.h 2024-10-19 14:32:25 +01:00
Chris Webb
b3ab1bd9a4 Add maintainer update script
This script captures my process for merging changes from new upstream
elfutils releases. It isn't obfuscated for portability as it is only
intended for maintainer use and documentation.
2024-07-18 10:48:35 +01:00
Chris Webb
b80c36da9d Merge from upstream libelf 0.191 2024-03-02 08:56:42 +00:00
Chris Webb
bc9698efd5 Update upstream files from elfutils 0.191 2024-03-02 08:49:32 +00:00
Chris Webb
a75f3a59d7 Update minor version to 0.190 in Makefile 2024-01-11 22:06:55 +00:00
Chris Webb
97a43e81a7 Merge from upstream libelf 0.190 2023-11-03 19:42:30 +00:00
Chris Webb
4a1923298d Update upstream files from elfutils 0.190 2023-11-03 19:41:05 +00:00
Chris Webb
520244d664 Enable zstd support by default 2023-03-03 18:21:18 +00:00
Chris Webb
4afb73a7af Merge from upstream libelf 0.189 2023-03-03 18:07:48 +00:00
Chris Webb
a78fcc53c1 Update upstream files from elfutils 0.189 2023-03-03 18:04:20 +00:00
46 changed files with 1520 additions and 399 deletions

View File

@ -3,10 +3,10 @@ LIBDIR = $(PREFIX)/lib
CFLAGS = -O2 -Wall
LDFLAGS =
LDLIBS = -lz
LDLIBS = -lz -lzstd
MAJOR = 1
MINOR = 0.187
MINOR = 0.194
HEADERS = $(wildcard include/*.h src/*.h)
SOURCES = $(wildcard src/*.c)
@ -23,7 +23,7 @@ clean:
libelf.a: $(LIBOBJS) Makefile
$(AR) rcs $@ $(LIBOBJS)
libelf.so: $(PICOBJS) Makefile
libelf.so: $(PICOBJS) Makefile
$(CC) $(LDFLAGS) -shared -Wl,-soname,libelf.so.$(MAJOR) \
-o $@ $(PICOBJS) $(LDLIBS)

7
README
View File

@ -7,7 +7,8 @@ elfutils, along with a simple Makefile to build and install it.
Unlike the upstream package, this libelf builds cleanly on both musl and
glibc, using either clang or gcc. Users are spared the joy of autotools,
and on musl systems it does not require extra libraries for argp, fts or
obstack. The sole dependency is zlib for handling compressed ELF sections.
obstack. The sole dependencies are zlib and (by default) zstd for handling
compressed ELF sections.
The elfutils tools, libdwarf and libasm are not included: you will need the
full upstream distribution to build those. However, they are a much more
@ -28,7 +29,9 @@ similarly the install-shared target installs only the shared library.
The build should work out of the box on reasonably recent musl/glibc and
clang/gcc. On very old or non-Linux systems, some manual adjustment of
src/config.h may be needed.
src/config.h may be needed. For example, to build without zstd support,
remove the definitions of USE_ZSTD and USE_ZSTD_COMPRESS from config.h and
drop -lzstd from LDLIBS in the Makefile.
Please report any problems or bugs to Chris Webb <chris@arachsys.com> rather
than to the upstream elfutils maintainers, who are not to blame for issues

View File

@ -82,6 +82,9 @@ typedef Elf64_Rel GElf_Rel;
/* Relocation table entry with addend (in section of type SHT_RELA). */
typedef Elf64_Rela GElf_Rela;
/* Relative relocation entry (in section of type SHT_RELR). */
typedef Elf64_Relr GElf_Relr;
/* Program segment header. */
typedef Elf64_Phdr GElf_Phdr;

View File

@ -64,6 +64,24 @@
#define ELFCOMPRESS_HIPROC 0x7fffffff /* End of processor-specific. */
#endif
#ifndef ELFCOMPRESS_ZSTD
/* So ZSTD compression can be used even with an old system elf.h. */
#define ELFCOMPRESS_ZSTD 2 /* Zstandard algorithm. */
#endif
#ifndef SHT_RELR
/* So RELR defines/typedefs can be used even with an old system elf.h. */
#define SHT_RELR 19 /* RELR relative relocations */
/* RELR relocation table entry */
typedef Elf32_Word Elf32_Relr;
typedef Elf64_Xword Elf64_Relr;
#define DT_RELRSZ 35 /* Total size of RELR relative relocations */
#define DT_RELR 36 /* Address of RELR relative relocations */
#define DT_RELRENT 37 /* Size of one RELR relative relocaction */
#endif
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
# define __nonnull_attribute__(...) __attribute__ ((__nonnull__ (__VA_ARGS__)))
# define __deprecated_attribute__ __attribute__ ((__deprecated__))
@ -119,6 +137,7 @@ typedef enum
ELF_T_CHDR, /* Compressed, Elf32_Chdr, Elf64_Chdr, ... */
ELF_T_NHDR8, /* Special GNU Properties note. Same as Nhdr,
except padding. */
ELF_T_RELR, /* Relative relocation entry. */
/* Keep this the last entry. */
ELF_T_NUM
} Elf_Type;
@ -283,7 +302,7 @@ extern Elf_Scn *elf_getscn (Elf *__elf, size_t __index);
/* Get section at OFFSET. */
extern Elf_Scn *elf32_offscn (Elf *__elf, Elf32_Off __offset);
/* Similar bug this time the binary calls is ELFCLASS64. */
/* Similar but this time the binary calls is ELFCLASS64. */
extern Elf_Scn *elf64_offscn (Elf *__elf, Elf64_Off __offset);
/* Get index of section. */
@ -296,7 +315,14 @@ extern Elf_Scn *elf_nextscn (Elf *__elf, Elf_Scn *__scn);
extern Elf_Scn *elf_newscn (Elf *__elf);
/* Get the section index of the extended section index table for the
given symbol table. */
given symbol table. Returns -1 when the given Elf_Scn is NULL or
if an error occurred during lookup, elf_errno will be set. Returns
0 if the given Elf_Scn isn't a symbol table (sh_type is not
SHT_SYMTAB) or no extended section index table could be
found. Otherwise the section index of the extended section index
table for the given Elf_Scn is returned. An extended index table
has a sh_type of SHT_SYMTAB_SHNDX and a sh_link equal to the given
symbol table section index. */
extern int elf_scnshndx (Elf_Scn *__scn);
/* Get the number of sections in the ELF file. If the file uses more
@ -348,10 +374,10 @@ extern Elf64_Chdr *elf64_getchdr (Elf_Scn *__scn);
elf_compress takes a compression type that should be either zero to
decompress or an ELFCOMPRESS algorithm to use for compression.
Currently only ELFCOMPRESS_ZLIB is supported. elf_compress_gnu
will compress in the traditional GNU compression format when
compress is one and decompress the section data when compress is
zero.
Currently ELFCOMPRESS_ZLIB and ELFCOMPRESS_ZSTD are supported.
elf_compress_gnu will compress in the traditional GNU compression
format when compress is one and decompress the section data when
compress is zero.
The FLAGS argument can be zero or ELF_CHF_FORCE. If FLAGS contains
ELF_CHF_FORCE then it will always compress the section, even if

View File

@ -89,30 +89,34 @@ allocate_elf (int fildes, void *map_address, int64_t offset, size_t maxsize,
}
/* Acquire lock for the descriptor and all children. */
/* Caller must hold a lock for ELF. If there are children then a lock
will be acquired for each of them (recursively). */
static void
__attribute__ ((unused))
libelf_acquire_all (Elf *elf)
libelf_acquire_all_children (Elf *elf)
{
rwlock_wrlock (elf->lock);
if (elf->kind == ELF_K_AR)
{
Elf *child = elf->state.ar.children;
while (child != NULL)
{
rwlock_wrlock (child->lock);
if (child->ref_count != 0)
libelf_acquire_all (child);
libelf_acquire_all_children (child);
child = child->next;
}
}
}
/* Release own lock and those of the children. */
/* Caller must hold a lock for ELF. If there are children then a lock
will be released for each of them (recursively). */
static void
__attribute__ ((unused))
libelf_release_all (Elf *elf)
libelf_release_all_children (Elf *elf)
{
if (elf->kind == ELF_K_AR)
{
@ -121,12 +125,12 @@ libelf_release_all (Elf *elf)
while (child != NULL)
{
if (child->ref_count != 0)
libelf_release_all (child);
libelf_release_all_children (child);
rwlock_unlock (child->lock);
child = child->next;
}
}
rwlock_unlock (elf->lock);
}

View File

@ -7,6 +7,8 @@
#define HAVE_DECL_RAWMEMCHR 0
#define HAVE_DECL_REALLOCARRAY 1
#define HAVE_VISIBILITY 1
#define USE_ZSTD 1
#define USE_ZSTD_COMPRESS 1
#undef HAVE_GCC_STRUCT
#undef USE_LOCKS

View File

@ -25,7 +25,7 @@
the GNU Lesser General Public License along with this program. If
not, see <http://www.gnu.org/licenses/>. */
#if HAVE_CONFIG_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

View File

@ -98,4 +98,136 @@
#define GNU_BUILD_ATTRIBUTE_PIC 7
#define GNU_BUILD_ATTRIBUTE_SHORT_ENUM 8
/* Hexagon specific declarations. */
/* Processor specific flags for the Ehdr e_flags field. */
#define EF_HEXAGON_MACH_V2 0x00000001 /* Hexagon V2 */
#define EF_HEXAGON_MACH_V3 0x00000002 /* Hexagon V3 */
#define EF_HEXAGON_MACH_V4 0x00000003 /* Hexagon V4 */
#define EF_HEXAGON_MACH_V5 0x00000004 /* Hexagon V5 */
#define EF_HEXAGON_MACH_V55 0x00000005 /* Hexagon V55 */
#define EF_HEXAGON_MACH_V60 0x00000060 /* Hexagon V60 */
#define EF_HEXAGON_MACH_V61 0x00000061 /* Hexagon V61 */
#define EF_HEXAGON_MACH_V62 0x00000062 /* Hexagon V62 */
#define EF_HEXAGON_MACH_V65 0x00000065 /* Hexagon V65 */
#define EF_HEXAGON_MACH_V66 0x00000066 /* Hexagon V66 */
#define EF_HEXAGON_MACH_V67 0x00000067 /* Hexagon V67 */
#define EF_HEXAGON_MACH_V67T 0x00008067 /* Hexagon V67T */
#define EF_HEXAGON_MACH_V68 0x00000068 /* Hexagon V68 */
#define EF_HEXAGON_MACH_V69 0x00000069 /* Hexagon V68 */
#define EF_HEXAGON_MACH_V71 0x00000071 /* Hexagon V71 */
#define EF_HEXAGON_MACH_V71T 0x00008071 /* Hexagon V71T */
#define EF_HEXAGON_MACH_V73 0x00000073 /* Hexagon V73 */
#define EF_HEXAGON_MACH 0x000003ff /* Hexagon V.. */
#define EF_HEXAGON_TINY 0x00008000 /* Hexagon V..T */
/* Special section indices. */
#define SHN_HEXAGON_SCOMMON 0xff00 /* Other access sizes */
#define SHN_HEXAGON_SCOMMON_1 0xff01 /* Byte-sized access */
#define SHN_HEXAGON_SCOMMON_2 0xff02 /* Half-word-sized access */
#define SHN_HEXAGON_SCOMMON_4 0xff03 /* Word-sized access */
#define SHN_HEXAGON_SCOMMON_8 0xff04 /* Double-word-size access */
/* Hexagon specific relocs. */
#define R_HEX_NONE 0
#define R_HEX_B22_PCREL 1
#define R_HEX_B15_PCREL 2
#define R_HEX_B7_PCREL 3
#define R_HEX_LO16 4
#define R_HEX_HI16 5
#define R_HEX_32 6
#define R_HEX_16 7
#define R_HEX_8 8
#define R_HEX_GPREL16_0 9
#define R_HEX_GPREL16_1 10
#define R_HEX_GPREL16_2 11
#define R_HEX_GPREL16_3 12
#define R_HEX_HL16 13
#define R_HEX_B13_PCREL 14
#define R_HEX_B9_PCREL 15
#define R_HEX_B32_PCREL_X 16
#define R_HEX_32_6_X 17
#define R_HEX_B22_PCREL_X 18
#define R_HEX_B15_PCREL_X 19
#define R_HEX_B13_PCREL_X 20
#define R_HEX_B9_PCREL_X 21
#define R_HEX_B7_PCREL_X 22
#define R_HEX_16_X 23
#define R_HEX_12_X 24
#define R_HEX_11_X 25
#define R_HEX_10_X 26
#define R_HEX_9_X 27
#define R_HEX_8_X 28
#define R_HEX_7_X 29
#define R_HEX_6_X 30
#define R_HEX_32_PCREL 31
#define R_HEX_COPY 32
#define R_HEX_GLOB_DAT 33
#define R_HEX_JMP_SLOT 34
#define R_HEX_RELATIVE 35
#define R_HEX_PLT_B22_PCREL 36
#define R_HEX_GOTREL_LO16 37
#define R_HEX_GOTREL_HI16 38
#define R_HEX_GOTREL_32 39
#define R_HEX_GOT_LO16 40
#define R_HEX_GOT_HI16 41
#define R_HEX_GOT_32 42
#define R_HEX_GOT_16 43
#define R_HEX_DTPMOD_32 44
#define R_HEX_DTPREL_LO16 45
#define R_HEX_DTPREL_HI16 46
#define R_HEX_DTPREL_32 47
#define R_HEX_DTPREL_16 48
#define R_HEX_GD_PLT_B22_PCREL 49
#define R_HEX_GD_GOT_LO16 50
#define R_HEX_GD_GOT_HI16 51
#define R_HEX_GD_GOT_32 52
#define R_HEX_GD_GOT_16 53
#define R_HEX_IE_LO16 54
#define R_HEX_IE_HI16 55
#define R_HEX_IE_32 56
#define R_HEX_IE_GOT_LO16 57
#define R_HEX_IE_GOT_HI16 58
#define R_HEX_IE_GOT_32 59
#define R_HEX_IE_GOT_16 60
#define R_HEX_TPREL_LO16 61
#define R_HEX_TPREL_HI16 62
#define R_HEX_TPREL_32 63
#define R_HEX_TPREL_16 64
#define R_HEX_6_PCREL_X 65
#define R_HEX_GOTREL_32_6_X 66
#define R_HEX_GOTREL_16_X 67
#define R_HEX_GOTREL_11_X 68
#define R_HEX_GOT_32_6_X 69
#define R_HEX_GOT_16_X 70
#define R_HEX_GOT_11_X 71
#define R_HEX_DTPREL_32_6_X 72
#define R_HEX_DTPREL_16_X 73
#define R_HEX_DTPREL_11_X 74
#define R_HEX_GD_GOT_32_6_X 75
#define R_HEX_GD_GOT_16_X 76
#define R_HEX_GD_GOT_11_X 77
#define R_HEX_IE_32_6_X 78
#define R_HEX_IE_16_X 79
#define R_HEX_IE_GOT_32_6_X 80
#define R_HEX_IE_GOT_16_X 81
#define R_HEX_IE_GOT_11_X 82
#define R_HEX_TPREL_32_6_X 83
#define R_HEX_TPREL_16_X 84
#define R_HEX_TPREL_11_X 85
#define R_HEX_LD_PLT_B22_PCREL 86
#define R_HEX_LD_GOT_LO16 87
#define R_HEX_LD_GOT_HI16 88
#define R_HEX_LD_GOT_32 89
#define R_HEX_LD_GOT_16 90
#define R_HEX_LD_GOT_32_6_X 91
#define R_HEX_LD_GOT_16_X 92
#define R_HEX_LD_GOT_11_X 93
#define R_HEX_23_REG 94
#define R_HEX_GD_PLT_B22_PCREL_X 95
#define R_HEX_GD_PLT_B32_PCREL_X 96
#define R_HEX_LD_PLT_B22_PCREL_X 97
#define R_HEX_LD_PLT_B32_PCREL_X 98
#define R_HEX_27_REG 99
#endif /* elf-knowledge.h */

254
src/elf.h
View File

@ -1,5 +1,5 @@
/* This file defines standard ELF types, structures, and macros.
Copyright (C) 1995-2022 Free Software Foundation, Inc.
Copyright (C) 1995-2024 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@ -210,7 +210,7 @@ typedef struct
#define EM_68HC12 53 /* Motorola M68HC12 */
#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator */
#define EM_PCP 55 /* Siemens PCP */
#define EM_NCPU 56 /* Sony nCPU embeeded RISC */
#define EM_NCPU 56 /* Sony nCPU embedded RISC */
#define EM_NDR1 57 /* Denso NDR1 microprocessor */
#define EM_STARCORE 58 /* Motorola Start*Core processor */
#define EM_ME16 59 /* Toyota ME16 processor */
@ -559,7 +559,7 @@ typedef struct
/* Possible bitmasks for si_flags. */
#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */
#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */
#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-through symbol for translator */
#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */
#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy
loaded */
@ -728,6 +728,7 @@ typedef struct
#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */
#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */
#define PT_GNU_PROPERTY 0x6474e553 /* GNU property */
#define PT_GNU_SFRAME 0x6474e554 /* SFrame segment. */
#define PT_LOSUNW 0x6ffffffa
#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */
#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */
@ -790,9 +791,12 @@ typedef struct
Register */
#define NT_PPC_PKEY 0x110 /* Memory Protection Keys
registers. */
#define NT_PPC_DEXCR 0x111 /* PowerPC DEXCR registers. */
#define NT_PPC_HASHKEYR 0x112 /* PowerPC HASHKEYR register. */
#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */
#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */
#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */
#define NT_X86_SHSTK 0x204 /* x86 SHSTK state */
#define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves */
#define NT_S390_TIMER 0x301 /* s390 timer register */
#define NT_S390_TODCMP 0x302 /* s390 TOD clock comparator register */
@ -827,10 +831,16 @@ typedef struct
control. */
#define NT_ARM_PAC_ENABLED_KEYS 0x40a /* AArch64 pointer authentication
enabled keys. */
#define NT_ARM_SSVE 0x40b /* ARM Streaming SVE registers. */
#define NT_ARM_ZA 0x40c /* ARM SME ZA registers. */
#define NT_ARM_ZT 0x40d /* ARM SME ZT registers. */
#define NT_ARM_FPMR 0x40e /* ARM floating point mode register. */
#define NT_VMCOREDD 0x700 /* Vmcore Device Dump Note. */
#define NT_MIPS_DSP 0x800 /* MIPS DSP ASE registers. */
#define NT_MIPS_FP_MODE 0x801 /* MIPS floating-point mode. */
#define NT_MIPS_MSA 0x802 /* MIPS SIMD registers. */
#define NT_RISCV_CSR 0x900 /* RISC-V Control and Status Registers */
#define NT_RISCV_VECTOR 0x901 /* RISC-V vector registers */
#define NT_LOONGARCH_CPUCFG 0xa00 /* LoongArch CPU config registers. */
#define NT_LOONGARCH_CSR 0xa01 /* LoongArch control and
status registers. */
@ -840,6 +850,8 @@ typedef struct
SIMD Extension registers. */
#define NT_LOONGARCH_LBT 0xa04 /* LoongArch Loongson Binary
Translation registers. */
#define NT_LOONGARCH_HW_BREAK 0xa05 /* LoongArch hardware breakpoint registers */
#define NT_LOONGARCH_HW_WATCH 0xa06 /* LoongArch hardware watchpoint registers */
/* Legal values for the note segment descriptor types for object files. */
@ -1223,6 +1235,13 @@ typedef struct
#define AT_HWCAP2 26 /* More machine-dependent hints about
processor capabilities. */
#define AT_RSEQ_FEATURE_SIZE 27 /* rseq supported feature size. */
#define AT_RSEQ_ALIGN 28 /* rseq allocation alignment. */
/* More machine-dependent hints about processor capabilities. */
#define AT_HWCAP3 29 /* extension of AT_HWCAP. */
#define AT_HWCAP4 30 /* extension of AT_HWCAP. */
#define AT_EXECFN 31 /* Filename of executable. */
/* Pointer to the global system page used for system calls and other
@ -1322,9 +1341,13 @@ typedef struct
#define NT_GNU_PROPERTY_TYPE_0 5
/* Packaging metadata as defined on
https://systemd.io/COREDUMP_PACKAGE_METADATA/ */
https://systemd.io/ELF_PACKAGE_METADATA/ */
#define NT_FDO_PACKAGING_METADATA 0xcafe1a7e
/* dlopen metadata as defined on
https://systemd.io/ELF_DLOPEN_METADATA/ */
#define NT_FDO_DLOPEN_METADATA 0x407c0c0a
/* Note section name of program property. */
#define NOTE_GNU_PROPERTY_SECTION_NAME ".note.gnu.property"
@ -1681,11 +1704,25 @@ typedef struct
#define EF_MIPS_PIC 2 /* Contains PIC code. */
#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence. */
#define EF_MIPS_XGOT 8
#define EF_MIPS_64BIT_WHIRL 16
#define EF_MIPS_UCODE 16
#define EF_MIPS_ABI2 32
#define EF_MIPS_ABI_ON32 64
#define EF_MIPS_OPTIONS_FIRST 0x00000080 /* Process the .MIPS.options
section first by ld. */
#define EF_MIPS_32BITMODE 0x00000100 /* Indicates code compiled for
a 64-bit machine in 32-bit
mode (regs are 32-bits
wide). */
#define EF_MIPS_FP64 512 /* Uses FP64 (12 callee-saved). */
#define EF_MIPS_NAN2008 1024 /* Uses IEEE 754-2008 NaN encoding. */
#define EF_MIPS_ARCH_ASE 0x0f000000 /* Architectural Extensions
used by this file. */
#define EF_MIPS_ARCH_ASE_MDMX 0x08000000 /* Use MDMX multimedia
extensions. */
#define EF_MIPS_ARCH_ASE_M16 0x04000000 /* Use MIPS-16 ISA
extensions. */
#define EF_MIPS_ARCH_ASE_MICROMIPS 0x02000000 /* Use MICROMIPS ISA
extensions. */
#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level. */
/* Legal values for MIPS architecture level. */
@ -1699,6 +1736,38 @@ typedef struct
#define EF_MIPS_ARCH_64 0x60000000 /* MIPS64 code. */
#define EF_MIPS_ARCH_32R2 0x70000000 /* MIPS32r2 code. */
#define EF_MIPS_ARCH_64R2 0x80000000 /* MIPS64r2 code. */
#define EF_MIPS_ARCH_32R6 0x90000000 /* MIPS32r6 code. */
#define EF_MIPS_ARCH_64R6 0xa0000000 /* MIPS64r6 code. */
#define EF_MIPS_ABI 0x0000F000 /* The ABI of the file. Also
see EF_MIPS_ABI2 above. */
#define EF_MIPS_ABI_O32 0x00001000 /* The original o32 abi. */
#define EF_MIPS_ABI_O64 0x00002000 /* O32 extended to work on
64 bit architectures. */
#define EF_MIPS_ABI_EABI32 0x00003000 /* EABI in 32 bit mode. */
#define EF_MIPS_ABI_EABI64 0x00004000 /* EABI in 64 bit mode. */
#define EF_MIPS_MACH 0x00FF0000
#define EF_MIPS_MACH_3900 0x00810000
#define EF_MIPS_MACH_4010 0x00820000
#define EF_MIPS_MACH_4100 0x00830000
#define EF_MIPS_MACH_ALLEGREX 0x00840000
#define EF_MIPS_MACH_4650 0x00850000
#define EF_MIPS_MACH_4120 0x00870000
#define EF_MIPS_MACH_4111 0x00880000
#define EF_MIPS_MACH_SB1 0x008a0000
#define EF_MIPS_MACH_OCTEON 0x008b0000
#define EF_MIPS_MACH_XLR 0x008c0000
#define EF_MIPS_MACH_OCTEON2 0x008d0000
#define EF_MIPS_MACH_OCTEON3 0x008e0000
#define EF_MIPS_MACH_5400 0x00910000
#define EF_MIPS_MACH_5900 0x00920000
#define EF_MIPS_MACH_IAMR2 0x00930000
#define EF_MIPS_MACH_5500 0x00980000
#define EF_MIPS_MACH_9000 0x00990000
#define EF_MIPS_MACH_LS2E 0x00A00000
#define EF_MIPS_MACH_LS2F 0x00A10000
#define EF_MIPS_MACH_GS464 0x00A20000
#define EF_MIPS_MACH_GS464E 0x00A30000
#define EF_MIPS_MACH_GS264E 0x00A40000
/* The following are unofficial names and should not be used. */
@ -1759,6 +1828,7 @@ typedef struct
#define SHT_MIPS_EH_REGION 0x70000027
#define SHT_MIPS_XLATE_OLD 0x70000028
#define SHT_MIPS_PDR_EXCEPTION 0x70000029
#define SHT_MIPS_ABIFLAGS 0x7000002a
#define SHT_MIPS_XHASH 0x7000002b
/* Legal values for sh_flags field of Elf32_Shdr. */
@ -1927,10 +1997,68 @@ typedef struct
#define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */
#define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */
#define R_MIPS_GLOB_DAT 51
#define R_MIPS_PC21_S2 60
#define R_MIPS_PC26_S2 61
#define R_MIPS_PC18_S3 62
#define R_MIPS_PC19_S2 63
#define R_MIPS_PCHI16 64
#define R_MIPS_PCLO16 65
#define R_MIPS16_26 100
#define R_MIPS16_GPREL 101
#define R_MIPS16_GOT16 102
#define R_MIPS16_CALL16 103
#define R_MIPS16_HI16 104
#define R_MIPS16_LO16 105
#define R_MIPS16_TLS_GD 106
#define R_MIPS16_TLS_LDM 107
#define R_MIPS16_TLS_DTPREL_HI16 108
#define R_MIPS16_TLS_DTPREL_LO16 109
#define R_MIPS16_TLS_GOTTPREL 110
#define R_MIPS16_TLS_TPREL_HI16 111
#define R_MIPS16_TLS_TPREL_LO16 112
#define R_MIPS16_PC16_S1 113
#define R_MIPS_COPY 126
#define R_MIPS_JUMP_SLOT 127
#define R_MIPS_RELATIVE 128
#define R_MICROMIPS_26_S1 133
#define R_MICROMIPS_HI16 134
#define R_MICROMIPS_LO16 135
#define R_MICROMIPS_GPREL16 136
#define R_MICROMIPS_LITERAL 137
#define R_MICROMIPS_GOT16 138
#define R_MICROMIPS_PC7_S1 139
#define R_MICROMIPS_PC10_S1 140
#define R_MICROMIPS_PC16_S1 141
#define R_MICROMIPS_CALL16 142
#define R_MICROMIPS_GOT_DISP 145
#define R_MICROMIPS_GOT_PAGE 146
#define R_MICROMIPS_GOT_OFST 147
#define R_MICROMIPS_GOT_HI16 148
#define R_MICROMIPS_GOT_LO16 149
#define R_MICROMIPS_SUB 150
#define R_MICROMIPS_HIGHER 151
#define R_MICROMIPS_HIGHEST 152
#define R_MICROMIPS_CALL_HI16 153
#define R_MICROMIPS_CALL_LO16 154
#define R_MICROMIPS_SCN_DISP 155
#define R_MICROMIPS_JALR 156
#define R_MICROMIPS_HI0_LO16 157
#define R_MICROMIPS_TLS_GD 162
#define R_MICROMIPS_TLS_LDM 163
#define R_MICROMIPS_TLS_DTPREL_HI16 164
#define R_MICROMIPS_TLS_DTPREL_LO16 165
#define R_MICROMIPS_TLS_GOTTPREL 166
#define R_MICROMIPS_TLS_TPREL_HI16 169
#define R_MICROMIPS_TLS_TPREL_LO16 170
#define R_MICROMIPS_GPREL7_S2 172
#define R_MICROMIPS_PC23_S2 173
#define R_MIPS_PC32 248
#define R_MIPS_EH 249
#define R_MIPS_GNU_REL16_S2 250
#define R_MIPS_GNU_VTINHERIT 253
#define R_MIPS_GNU_VTENTRY 254
/* Keep this the last entry. */
#define R_MIPS_NUM 128
#define R_MIPS_NUM 255
/* Legal values for p_type field of Elf32_Phdr. */
@ -3523,6 +3651,11 @@ enum
/* x86-64 sh_type values. */
#define SHT_X86_64_UNWIND 0x70000001 /* Unwind information. */
/* x86-64 d_tag values. */
#define DT_X86_64_PLT (DT_LOPROC + 0)
#define DT_X86_64_PLTSZ (DT_LOPROC + 1)
#define DT_X86_64_PLTENT (DT_LOPROC + 3)
#define DT_X86_64_NUM 4
/* AM33 relocations. */
#define R_MN10300_NONE 0 /* No reloc. */
@ -3998,8 +4131,11 @@ enum
#define R_RISCV_SET32 56
#define R_RISCV_32_PCREL 57
#define R_RISCV_IRELATIVE 58
#define R_RISCV_PLT32 59
#define R_RISCV_SET_ULEB128 60
#define R_RISCV_SUB_ULEB128 61
#define R_RISCV_NUM 59
#define R_RISCV_NUM 62
/* RISC-V specific values for the st_other field. */
#define STO_RISCV_VARIANT_CC 0x80 /* Function uses variant calling
@ -4093,8 +4229,11 @@ enum
#define R_NDS32_TLS_DESC 119
/* LoongArch ELF Flags */
#define EF_LARCH_ABI 0x07
#define EF_LARCH_ABI_LP64D 0x03
#define EF_LARCH_ABI_MODIFIER_MASK 0x07
#define EF_LARCH_ABI_SOFT_FLOAT 0x01
#define EF_LARCH_ABI_SINGLE_FLOAT 0x02
#define EF_LARCH_ABI_DOUBLE_FLOAT 0x03
#define EF_LARCH_OBJABI_V1 0x40
/* LoongArch specific dynamic relocations */
#define R_LARCH_NONE 0
@ -4110,6 +4249,8 @@ enum
#define R_LARCH_TLS_TPREL32 10
#define R_LARCH_TLS_TPREL64 11
#define R_LARCH_IRELATIVE 12
#define R_LARCH_TLS_DESC32 13
#define R_LARCH_TLS_DESC64 14
/* Reserved for future relocs that the dynamic linker must understand. */
@ -4156,6 +4297,81 @@ enum
#define R_LARCH_GNU_VTINHERIT 57
#define R_LARCH_GNU_VTENTRY 58
/* reserved 59-63 */
#define R_LARCH_B16 64
#define R_LARCH_B21 65
#define R_LARCH_B26 66
#define R_LARCH_ABS_HI20 67
#define R_LARCH_ABS_LO12 68
#define R_LARCH_ABS64_LO20 69
#define R_LARCH_ABS64_HI12 70
#define R_LARCH_PCALA_HI20 71
#define R_LARCH_PCALA_LO12 72
#define R_LARCH_PCALA64_LO20 73
#define R_LARCH_PCALA64_HI12 74
#define R_LARCH_GOT_PC_HI20 75
#define R_LARCH_GOT_PC_LO12 76
#define R_LARCH_GOT64_PC_LO20 77
#define R_LARCH_GOT64_PC_HI12 78
#define R_LARCH_GOT_HI20 79
#define R_LARCH_GOT_LO12 80
#define R_LARCH_GOT64_LO20 81
#define R_LARCH_GOT64_HI12 82
#define R_LARCH_TLS_LE_HI20 83
#define R_LARCH_TLS_LE_LO12 84
#define R_LARCH_TLS_LE64_LO20 85
#define R_LARCH_TLS_LE64_HI12 86
#define R_LARCH_TLS_IE_PC_HI20 87
#define R_LARCH_TLS_IE_PC_LO12 88
#define R_LARCH_TLS_IE64_PC_LO20 89
#define R_LARCH_TLS_IE64_PC_HI12 90
#define R_LARCH_TLS_IE_HI20 91
#define R_LARCH_TLS_IE_LO12 92
#define R_LARCH_TLS_IE64_LO20 93
#define R_LARCH_TLS_IE64_HI12 94
#define R_LARCH_TLS_LD_PC_HI20 95
#define R_LARCH_TLS_LD_HI20 96
#define R_LARCH_TLS_GD_PC_HI20 97
#define R_LARCH_TLS_GD_HI20 98
#define R_LARCH_32_PCREL 99
#define R_LARCH_RELAX 100
#define R_LARCH_DELETE 101
#define R_LARCH_ALIGN 102
#define R_LARCH_PCREL20_S2 103
#define R_LARCH_CFA 104
#define R_LARCH_ADD6 105
#define R_LARCH_SUB6 106
#define R_LARCH_ADD_ULEB128 107
#define R_LARCH_SUB_ULEB128 108
#define R_LARCH_64_PCREL 109
#define R_LARCH_CALL36 110
#define R_LARCH_TLS_DESC_PC_HI20 111
#define R_LARCH_TLS_DESC_PC_LO12 112
#define R_LARCH_TLS_DESC64_PC_LO20 113
#define R_LARCH_TLS_DESC64_PC_HI12 114
#define R_LARCH_TLS_DESC_HI20 115
#define R_LARCH_TLS_DESC_LO12 116
#define R_LARCH_TLS_DESC64_LO20 117
#define R_LARCH_TLS_DESC64_HI12 118
#define R_LARCH_TLS_DESC_LD 119
#define R_LARCH_TLS_DESC_CALL 120
#define R_LARCH_TLS_LE_HI20_R 121
#define R_LARCH_TLS_LE_ADD_R 122
#define R_LARCH_TLS_LE_LO12_R 123
#define R_LARCH_TLS_LD_PCREL20_S2 124
#define R_LARCH_TLS_GD_PCREL20_S2 125
#define R_LARCH_TLS_DESC_PCREL20_S2 126
/* ARC specific declarations. */
/* Processor specific flags for the Ehdr e_flags field. */
#define EF_ARC_MACH_MSK 0x000000ff
#define EF_ARC_OSABI_MSK 0x00000f00
#define EF_ARC_ALL_MSK (EF_ARC_MACH_MSK | EF_ARC_OSABI_MSK)
/* Processor specific values for the Shdr sh_type field. */
#define SHT_ARC_ATTRIBUTES (SHT_LOPROC + 1) /* ARC attributes section. */
/* ARCompact/ARCv2 specific relocs. */
#define R_ARC_NONE 0x0
@ -4163,7 +4379,7 @@ enum
#define R_ARC_16 0x2
#define R_ARC_24 0x3
#define R_ARC_32 0x4
#define R_ARC_B26 0x5
#define R_ARC_B22_PCREL 0x6
#define R_ARC_H30 0x7
#define R_ARC_N8 0x8
@ -4203,16 +4419,23 @@ enum
#define R_ARC_SECTOFF_ME_2 0x2A
#define R_ARC_SECTOFF_1 0x2B
#define R_ARC_SECTOFF_2 0x2C
#define R_ARC_SDA_12 0x2D
#define R_ARC_SDA16_ST2 0x30
#define R_ARC_32_PCREL 0x31
#define R_ARC_PC32 0x32
#define R_ARC_GOTPC32 0x33
#define R_ARC_PLT32 0x34
#define R_ARC_COPY 0x35
#define R_ARC_GLOB_DAT 0x36
#define R_ARC_JUMP_SLOT 0x37
#define R_ARC_JMP_SLOT 0x37
#define R_ARC_RELATIVE 0x38
#define R_ARC_GOTOFF 0x39
#define R_ARC_GOTPC 0x3A
#define R_ARC_GOT32 0x3B
#define R_ARC_S21W_PCREL_PLT 0x3C
#define R_ARC_S25H_PCREL_PLT 0x3D
#define R_ARC_JLI_SECTOFF 0x3F
#define R_ARC_TLS_DTPMOD 0x42
#define R_ARC_TLS_DTPOFF 0x43
@ -4221,9 +4444,12 @@ enum
#define R_ARC_TLS_GD_LD 0x46
#define R_ARC_TLS_GD_CALL 0x47
#define R_ARC_TLS_IE_GOT 0x48
#define R_ARC_TLS_DTPOFF_S9 0x4a
#define R_ARC_TLS_LE_S9 0x4a
#define R_ARC_TLS_LE_32 0x4b
#define R_ARC_TLS_DTPOFF_S9 0x49
#define R_ARC_TLS_LE_S9 0x4A
#define R_ARC_TLS_LE_32 0x4B
#define R_ARC_S25W_PCREL_PLT 0x4C
#define R_ARC_S21H_PCREL_PLT 0x4D
#define R_ARC_NPS_CMEM16 0x4E
/* OpenRISC 1000 specific relocs. */
#define R_OR1K_NONE 0

View File

@ -38,46 +38,8 @@
# define LIBELFBITS 32
#endif
#define ELF_WRLOCK_HELD 1
#include "elf32_getchdr.h"
ElfW2(LIBELFBITS,Chdr) *
elfw2(LIBELFBITS,getchdr) (Elf_Scn *scn)
{
ElfW2(LIBELFBITS,Shdr) *shdr = elfw2(LIBELFBITS,getshdr) (scn);
if (shdr == NULL)
return NULL;
/* Must have SHF_COMPRESSED flag set. Allocated or no bits sections
can never be compressed. */
if ((shdr->sh_flags & SHF_ALLOC) != 0)
{
__libelf_seterrno (ELF_E_INVALID_SECTION_FLAGS);
return NULL;
}
if (shdr->sh_type == SHT_NULL
|| shdr->sh_type == SHT_NOBITS)
{
__libelf_seterrno (ELF_E_INVALID_SECTION_TYPE);
return NULL;
}
if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
{
__libelf_seterrno (ELF_E_NOT_COMPRESSED);
return NULL;
}
/* This makes sure the data is in the correct format, so we don't
need to swap fields. */
Elf_Data *d = elf_getdata (scn, NULL);
if (d == NULL)
return NULL;
if (d->d_size < sizeof (ElfW2(LIBELFBITS,Chdr)) || d->d_buf == NULL)
{
__libelf_seterrno (ELF_E_INVALID_DATA);
return NULL;
}
return (ElfW2(LIBELFBITS,Chdr) *) d->d_buf;
}
#define ELF_WRLOCK_HELD 0
#include "elf32_getchdr.h"

61
src/elf32_getchdr.h Normal file
View File

@ -0,0 +1,61 @@
#undef ADD_ROUTINE_PREFIX
#undef ADD_ROUTINE_SUFFIX
#if ELF_WRLOCK_HELD
#define CONCAT(x,y) x##y
#define ADD_ROUTINE_PREFIX(y) CONCAT(__,y)
#define ADD_ROUTINE_SUFFIX(x) x ## _wrlock
#define INTERNAL internal_function
#else
#define ADD_ROUTINE_PREFIX(y) y
#define ADD_ROUTINE_SUFFIX(x) x
#define INTERNAL
#endif
ElfW2(LIBELFBITS,Chdr) *
INTERNAL
ADD_ROUTINE_PREFIX(elfw2(LIBELFBITS, ADD_ROUTINE_SUFFIX(getchdr))) (Elf_Scn *scn)
{
ElfW2(LIBELFBITS,Shdr) *shdr = ADD_ROUTINE_PREFIX(elfw2(LIBELFBITS, ADD_ROUTINE_SUFFIX(getshdr)))(scn);
if (shdr == NULL)
return NULL;
/* Must have SHF_COMPRESSED flag set. Allocated or no bits sections
can never be compressed. */
if ((shdr->sh_flags & SHF_ALLOC) != 0)
{
__libelf_seterrno (ELF_E_INVALID_SECTION_FLAGS);
return NULL;
}
if (shdr->sh_type == SHT_NULL
|| shdr->sh_type == SHT_NOBITS)
{
__libelf_seterrno (ELF_E_INVALID_SECTION_TYPE);
return NULL;
}
if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
{
__libelf_seterrno (ELF_E_NOT_COMPRESSED);
return NULL;
}
/* This makes sure the data is in the correct format, so we don't
need to swap fields. */
Elf_Data *d = ADD_ROUTINE_PREFIX(ADD_ROUTINE_SUFFIX(elf_getdata)) (scn, NULL);
if (d == NULL)
return NULL;
if (d->d_size < sizeof (ElfW2(LIBELFBITS,Chdr)) || d->d_buf == NULL)
{
__libelf_seterrno (ELF_E_INVALID_DATA);
return NULL;
}
return (ElfW2(LIBELFBITS,Chdr) *) d->d_buf;
}
#undef INTERNAL
#undef ELF_WRLOCK_HELD

View File

@ -126,7 +126,7 @@ load_shdr_wrlock (Elf_Scn *scn)
if (unlikely (notcvt == NULL))
{
__libelf_seterrno (ELF_E_NOMEM);
goto out;
goto free_and_out;
}
memcpy (notcvt, ((char *) elf->map_address
+ elf->start_offset + ehdr->e_shoff),
@ -146,20 +146,6 @@ load_shdr_wrlock (Elf_Scn *scn)
CONVERT_TO (shdr[cnt].sh_addralign,
notcvt[cnt].sh_addralign);
CONVERT_TO (shdr[cnt].sh_entsize, notcvt[cnt].sh_entsize);
/* If this is a section with an extended index add a
reference in the section which uses the extended
index. */
if (shdr[cnt].sh_type == SHT_SYMTAB_SHNDX
&& shdr[cnt].sh_link < shnum)
elf->state.ELFW(elf,LIBELFBITS).scns.data[shdr[cnt].sh_link].shndx_index
= cnt;
/* Set the own shndx_index field in case it has not yet
been set. */
if (elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index == 0)
elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index
= -1;
}
if (copy)

View File

@ -73,14 +73,15 @@ elfw2(LIBELFBITS,offscn) (Elf *elf, ElfW2(LIBELFBITS,Off) offset)
for (unsigned int i = 0; i < runp->cnt; ++i)
if (runp->data[i].shdr.ELFW(e,LIBELFBITS)->sh_offset == offset)
{
result = &runp->data[i];
/* If this section is empty, the following one has the same
sh_offset. We presume the caller is looking for a nonempty
section, so keep looking if this one is empty. */
if (runp->data[i].shdr.ELFW(e,LIBELFBITS)->sh_size != 0
&& runp->data[i].shdr.ELFW(e,LIBELFBITS)->sh_type != SHT_NOBITS)
goto out;
{
result = &runp->data[i];
goto out;
}
}
runp = runp->next;

View File

@ -135,7 +135,8 @@ __elfw2(LIBELFBITS,updatenull_wrlock) (Elf *elf, int *change_bop, size_t shnum)
ehdr = __elfw2(LIBELFBITS,getehdr_wrlock) (elf);
/* Set the default values. */
if (ELFW(default_ehdr,LIBELFBITS) (elf, ehdr, shnum, change_bop) != 0)
if (ehdr == NULL
|| ELFW(default_ehdr,LIBELFBITS) (elf, ehdr, shnum, change_bop) != 0)
return -1;
/* At least the ELF header is there. */
@ -256,6 +257,9 @@ __elfw2(LIBELFBITS,updatenull_wrlock) (Elf *elf, int *change_bop, size_t shnum)
case SHT_SUNW_syminfo:
sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYMINFO, 1);
break;
case SHT_RELR:
sh_entsize = elf_typesize (LIBELFBITS, ELF_T_RELR, 1);
break;
default:
break;
}
@ -404,7 +408,7 @@ __elfw2(LIBELFBITS,updatenull_wrlock) (Elf *elf, int *change_bop, size_t shnum)
else
{
ElfW2(LIBELFBITS,Chdr) *chdr;
chdr = elfw2(LIBELFBITS,getchdr) (scn);
chdr = __elfw2(LIBELFBITS,getchdr_wrlock) (scn);
if (unlikely (chdr == NULL))
return -1;
sh_size = chdr->ch_size;

View File

@ -45,13 +45,26 @@ Elf_Data *
elfw2(LIBELFBITS, xlatetof) (Elf_Data *dest, const Elf_Data *src,
unsigned int encode)
{
if (src == NULL || dest == NULL)
return NULL;
if (src->d_type >= ELF_T_NUM)
{
__libelf_seterrno (ELF_E_UNKNOWN_TYPE);
return NULL;
}
/* First test whether the input data is really suitable for this
type. This means, whether there is an integer number of records.
Note that for this implementation the memory and file size of the
data types are identical. */
size_t recsize = __libelf_type_sizes[ELFW(ELFCLASS,LIBELFBITS) - 1][src->d_type];
if (src->d_size % recsize != 0)
/* We shouldn't require integer number of records when processing
notes. Payload bytes follow the header immediately, it's not an
array of records as is the case otherwise. */
if (src->d_type != ELF_T_NHDR && src->d_type != ELF_T_NHDR8
&& src->d_size % recsize != 0)
{
__libelf_seterrno (ELF_E_INVALID_DATA);
return NULL;

View File

@ -45,6 +45,15 @@ Elf_Data *
elfw2(LIBELFBITS, xlatetom) (Elf_Data *dest, const Elf_Data *src,
unsigned int encode)
{
if (src == NULL || dest == NULL)
return NULL;
if (src->d_type >= ELF_T_NUM)
{
__libelf_seterrno (ELF_E_UNKNOWN_TYPE);
return NULL;
}
/* First test whether the input data is really suitable for this
type. This means, whether there is an integer number of records.
Note that for this implementation the memory and file size of the

View File

@ -38,6 +38,7 @@
#include <fcntl.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <sys/stat.h>
@ -61,7 +62,7 @@ file_read_ar (int fildes, void *map_address, off_t offset, size_t maxsize,
happen on demand. */
elf->state.ar.offset = offset + SARMAG;
elf->state.ar.elf_ar_hdr.ar_rawname = elf->state.ar.raw_name;
elf->state.ar.cur_ar_hdr.ar_rawname = elf->state.ar.raw_name;
}
return elf;
@ -341,15 +342,15 @@ file_read_elf (int fildes, void *map_address, unsigned char *e_ident,
{
/* This pointer might not be directly usable if the alignment is
not sufficient for the architecture. */
Elf32_Ehdr *ehdr = (Elf32_Ehdr *) ((char *) map_address + offset);
uintptr_t ehdr = (uintptr_t) map_address + offset;
/* This is a 32-bit binary. */
if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA
&& (ALLOW_UNALIGNED
|| (((uintptr_t) ehdr) & (__alignof__ (Elf32_Ehdr) - 1)) == 0))
|| (ehdr & (__alignof__ (Elf32_Ehdr) - 1)) == 0))
{
/* We can use the mmapped memory. */
elf->state.elf32.ehdr = ehdr;
elf->state.elf32.ehdr = (Elf32_Ehdr *) ehdr;
}
else
{
@ -382,8 +383,7 @@ file_read_elf (int fildes, void *map_address, unsigned char *e_ident,
if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA
&& cmd != ELF_C_READ_MMAP /* We need a copy to be able to write. */
&& (ALLOW_UNALIGNED
|| ((((uintptr_t) ehdr + e_shoff)
& (__alignof__ (Elf32_Shdr) - 1)) == 0)))
|| (((ehdr + e_shoff) & (__alignof__ (Elf32_Shdr) - 1)) == 0)))
{
if (unlikely (scncnt > 0 && e_shoff >= maxsize)
|| unlikely (maxsize - e_shoff
@ -396,8 +396,7 @@ file_read_elf (int fildes, void *map_address, unsigned char *e_ident,
}
if (scncnt > 0)
elf->state.elf32.shdr
= (Elf32_Shdr *) ((char *) ehdr + e_shoff);
elf->state.elf32.shdr = (Elf32_Shdr *) (ehdr + e_shoff);
for (size_t cnt = 0; cnt < scncnt; ++cnt)
{
@ -413,19 +412,6 @@ file_read_elf (int fildes, void *map_address, unsigned char *e_ident,
((char *) map_address + offset
+ elf->state.elf32.shdr[cnt].sh_offset);
elf->state.elf32.scns.data[cnt].list = &elf->state.elf32.scns;
/* If this is a section with an extended index add a
reference in the section which uses the extended
index. */
if (elf->state.elf32.shdr[cnt].sh_type == SHT_SYMTAB_SHNDX
&& elf->state.elf32.shdr[cnt].sh_link < scncnt)
elf->state.elf32.scns.data[elf->state.elf32.shdr[cnt].sh_link].shndx_index
= cnt;
/* Set the own shndx_index field in case it has not yet
been set. */
if (elf->state.elf32.scns.data[cnt].shndx_index == 0)
elf->state.elf32.scns.data[cnt].shndx_index = -1;
}
}
else
@ -440,20 +426,21 @@ file_read_elf (int fildes, void *map_address, unsigned char *e_ident,
/* So far only one block with sections. */
elf->state.elf32.scns_last = &elf->state.elf32.scns;
eu_search_tree_init (&elf->state.elf32.rawchunk_tree);
}
else
{
/* This pointer might not be directly usable if the alignment is
not sufficient for the architecture. */
Elf64_Ehdr *ehdr = (Elf64_Ehdr *) ((char *) map_address + offset);
uintptr_t ehdr = (uintptr_t) map_address + offset;
/* This is a 64-bit binary. */
if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA
&& (ALLOW_UNALIGNED
|| (((uintptr_t) ehdr) & (__alignof__ (Elf64_Ehdr) - 1)) == 0))
|| (ehdr & (__alignof__ (Elf64_Ehdr) - 1)) == 0))
{
/* We can use the mmapped memory. */
elf->state.elf64.ehdr = ehdr;
elf->state.elf64.ehdr = (Elf64_Ehdr *) ehdr;
}
else
{
@ -486,8 +473,7 @@ file_read_elf (int fildes, void *map_address, unsigned char *e_ident,
if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA
&& cmd != ELF_C_READ_MMAP /* We need a copy to be able to write. */
&& (ALLOW_UNALIGNED
|| ((((uintptr_t) ehdr + e_shoff)
& (__alignof__ (Elf64_Shdr) - 1)) == 0)))
|| (((ehdr + e_shoff) & (__alignof__ (Elf64_Shdr) - 1)) == 0)))
{
if (unlikely (scncnt > 0 && e_shoff >= maxsize)
|| unlikely (maxsize - e_shoff
@ -495,8 +481,7 @@ file_read_elf (int fildes, void *map_address, unsigned char *e_ident,
goto free_and_out;
if (scncnt > 0)
elf->state.elf64.shdr
= (Elf64_Shdr *) ((char *) ehdr + e_shoff);
elf->state.elf64.shdr = (Elf64_Shdr *) (ehdr + (ptrdiff_t) e_shoff);
for (size_t cnt = 0; cnt < scncnt; ++cnt)
{
@ -512,19 +497,6 @@ file_read_elf (int fildes, void *map_address, unsigned char *e_ident,
((char *) map_address + offset
+ elf->state.elf64.shdr[cnt].sh_offset);
elf->state.elf64.scns.data[cnt].list = &elf->state.elf64.scns;
/* If this is a section with an extended index add a
reference in the section which uses the extended
index. */
if (elf->state.elf64.shdr[cnt].sh_type == SHT_SYMTAB_SHNDX
&& elf->state.elf64.shdr[cnt].sh_link < scncnt)
elf->state.elf64.scns.data[elf->state.elf64.shdr[cnt].sh_link].shndx_index
= cnt;
/* Set the own shndx_index field in case it has not yet
been set. */
if (elf->state.elf64.scns.data[cnt].shndx_index == 0)
elf->state.elf64.scns.data[cnt].shndx_index = -1;
}
}
else
@ -539,6 +511,7 @@ file_read_elf (int fildes, void *map_address, unsigned char *e_ident,
/* So far only one block with sections. */
elf->state.elf64.scns_last = &elf->state.elf64.scns;
eu_search_tree_init (&elf->state.elf64.rawchunk_tree);
}
return elf;
@ -842,6 +815,50 @@ read_long_names (Elf *elf)
}
/* Copy archive header from parent archive ref to member descriptor elf. */
static int
copy_arhdr (Elf_Arhdr *dest, Elf *ref)
{
Elf_Arhdr *hdr;
hdr = &ref->state.ar.cur_ar_hdr;
char *ar_name = hdr->ar_name;
char *ar_rawname = hdr->ar_rawname;
if (ar_name == NULL || ar_rawname == NULL)
{
/* ref doesn't have an Elf_Arhdr or it was marked as unusable. */
return 0;
}
/* Allocate copies of ar_name and ar_rawname. */
size_t name_len = strlen (ar_name) + 1;
char *name_copy = malloc (MAX (name_len, 16));
if (name_copy == NULL)
{
__libelf_seterrno (ELF_E_NOMEM);
return -1;
}
memcpy (name_copy, ar_name, name_len);
size_t rawname_len = strlen (ar_rawname) + 1;
char *rawname_copy = malloc (MAX (rawname_len, 17));
if (rawname_copy == NULL)
{
free (name_copy);
__libelf_seterrno (ELF_E_NOMEM);
return -1;
}
memcpy (rawname_copy, ar_rawname, rawname_len);
*dest = *hdr;
dest->ar_name = name_copy;
dest->ar_rawname = rawname_copy;
return 0;
}
/* Read the next archive header. */
int
internal_function
@ -889,7 +906,7 @@ __libelf_next_arhdr_wrlock (Elf *elf)
/* Copy the raw name over to a NUL terminated buffer. */
*((char *) mempcpy (elf->state.ar.raw_name, ar_hdr->ar_name, 16)) = '\0';
elf_ar_hdr = &elf->state.ar.elf_ar_hdr;
elf_ar_hdr = &elf->state.ar.cur_ar_hdr;
/* Now convert the `struct ar_hdr' into `Elf_Arhdr'.
Determine whether this is a special entry. */
@ -1082,21 +1099,42 @@ dup_elf (int fildes, Elf_Cmd cmd, Elf *ref)
member the internal pointer of the archive file descriptor is
pointing to. First read the header of the next member if this
has not happened already. */
if (ref->state.ar.elf_ar_hdr.ar_name == NULL
if (ref->state.ar.cur_ar_hdr.ar_name == NULL
&& __libelf_next_arhdr_wrlock (ref) != 0)
/* Something went wrong. Maybe there is no member left. */
return NULL;
/* We have all the information we need about the next archive member.
Now create a descriptor for it. */
result = read_file (fildes, ref->state.ar.offset + sizeof (struct ar_hdr),
ref->state.ar.elf_ar_hdr.ar_size, cmd, ref);
Now create a descriptor for it. Check parent size can contain member. */
if (ref->state.ar.offset < ref->start_offset)
return NULL;
size_t max_size = ref->maximum_size;
size_t offset = (size_t) (ref->state.ar.offset - ref->start_offset);
size_t hdr_size = sizeof (struct ar_hdr);
size_t ar_size = (size_t) ref->state.ar.cur_ar_hdr.ar_size;
if (max_size < hdr_size || max_size - hdr_size < offset)
return NULL;
Elf_Arhdr ar_hdr = {0};
if (copy_arhdr (&ar_hdr, ref) != 0)
/* Out of memory. */
return NULL;
result = read_file (fildes, ref->state.ar.offset + sizeof (struct ar_hdr),
MIN (max_size - hdr_size - offset, ar_size), cmd, ref);
/* Enlist this new descriptor in the list of children. */
if (result != NULL)
{
/* Enlist this new descriptor in the list of children. */
result->next = ref->state.ar.children;
ref->state.ar.children = result;
result->elf_ar_hdr = ar_hdr;
}
else
{
free (ar_hdr.ar_name);
free (ar_hdr.ar_rawname);
}
return result;

View File

@ -42,19 +42,11 @@ elf_cntl (Elf *elf, Elf_Cmd cmd)
if (elf == NULL)
return -1;
if (elf->fildes == -1)
{
__libelf_seterrno (ELF_E_INVALID_HANDLE);
return -1;
}
rwlock_wrlock (elf->lock);
switch (cmd)
{
case ELF_C_FDREAD:
/* If not all of the file is in the memory read it now. */
if (elf->map_address == NULL && __libelf_readall (elf) == NULL)
if (__libelf_readall (elf) == NULL)
{
/* We were not able to read everything. */
result = -1;
@ -64,7 +56,9 @@ elf_cntl (Elf *elf, Elf_Cmd cmd)
case ELF_C_FDDONE:
/* Mark the file descriptor as not usable. */
rwlock_wrlock (elf->lock);
elf->fildes = -1;
rwlock_unlock (elf->lock);
break;
default:
@ -73,7 +67,5 @@ elf_cntl (Elf *elf, Elf_Cmd cmd)
break;
}
rwlock_unlock (elf->lock);
return result;
}

View File

@ -1,5 +1,6 @@
/* Compress or decompress a section.
Copyright (C) 2015, 2016 Red Hat, Inc.
Copyright (C) 2023, Mark J. Wielaard <mark@klomp.org>
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@ -39,6 +40,10 @@
#include <string.h>
#include <zlib.h>
#ifdef USE_ZSTD
#include <zstd.h>
#endif
/* Cleanup and return result. Don't leak memory. */
static void *
do_deflate_cleanup (void *result, z_stream *z, void *out_buf,
@ -54,53 +59,14 @@ do_deflate_cleanup (void *result, z_stream *z, void *out_buf,
#define deflate_cleanup(result, cdata) \
do_deflate_cleanup(result, &z, out_buf, cdata)
/* Given a section, uses the (in-memory) Elf_Data to extract the
original data size (including the given header size) and data
alignment. Returns a buffer that has at least hsize bytes (for the
caller to fill in with a header) plus zlib compressed date. Also
returns the new buffer size in new_size (hsize + compressed data
size). Returns (void *) -1 when FORCE is false and the compressed
data would be bigger than the original data. */
static
void *
internal_function
__libelf_compress (Elf_Scn *scn, size_t hsize, int ei_data,
size_t *orig_size, size_t *orig_addralign,
size_t *new_size, bool force)
__libelf_compress_zlib (Elf_Scn *scn, size_t hsize, int ei_data,
size_t *orig_size, size_t *orig_addralign,
size_t *new_size, bool force,
Elf_Data *data, Elf_Data *next_data,
void *out_buf, size_t out_size, size_t block)
{
/* The compressed data is the on-disk data. We simplify the
implementation a bit by asking for the (converted) in-memory
data (which might be all there is if the user created it with
elf_newdata) and then convert back to raw if needed before
compressing. Should be made a bit more clever to directly
use raw if that is directly available. */
Elf_Data *data = elf_getdata (scn, NULL);
if (data == NULL)
return NULL;
/* When not forced and we immediately know we would use more data by
compressing, because of the header plus zlib overhead (five bytes
per 16 KB block, plus a one-time overhead of six bytes for the
entire stream), don't do anything. */
Elf_Data *next_data = elf_getdata (scn, data);
if (next_data == NULL && !force
&& data->d_size <= hsize + 5 + 6)
return (void *) -1;
*orig_addralign = data->d_align;
*orig_size = data->d_size;
/* Guess an output block size. 1/8th of the original Elf_Data plus
hsize. Make the first chunk twice that size (25%), then increase
by a block (12.5%) when necessary. */
size_t block = (data->d_size / 8) + hsize;
size_t out_size = 2 * block;
void *out_buf = malloc (out_size);
if (out_buf == NULL)
{
__libelf_seterrno (ELF_E_NOMEM);
return NULL;
}
/* Caller gets to fill in the header at the start. Just skip it here. */
size_t used = hsize;
@ -205,9 +171,189 @@ __libelf_compress (Elf_Scn *scn, size_t hsize, int ei_data,
return out_buf;
}
#ifdef USE_ZSTD_COMPRESS
/* Cleanup and return result. Don't leak memory. */
static void *
do_zstd_cleanup (void *result, ZSTD_CCtx * const cctx, void *out_buf,
Elf_Data *cdatap)
{
ZSTD_freeCCtx (cctx);
free (out_buf);
if (cdatap != NULL)
free (cdatap->d_buf);
return result;
}
#define zstd_cleanup(result, cdata) \
do_zstd_cleanup(result, cctx, out_buf, cdata)
static
void *
__libelf_compress_zstd (Elf_Scn *scn, size_t hsize, int ei_data,
size_t *orig_size, size_t *orig_addralign,
size_t *new_size, bool force,
Elf_Data *data, Elf_Data *next_data,
void *out_buf, size_t out_size, size_t block)
{
/* Caller gets to fill in the header at the start. Just skip it here. */
size_t used = hsize;
ZSTD_CCtx* const cctx = ZSTD_createCCtx();
Elf_Data cdata;
cdata.d_buf = NULL;
/* Loop over data buffers. */
ZSTD_EndDirective mode = ZSTD_e_continue;
do
{
/* Convert to raw if different endianness. */
cdata = *data;
bool convert = ei_data != MY_ELFDATA && data->d_size > 0;
if (convert)
{
/* Don't do this conversion in place, we might want to keep
the original data around, caller decides. */
cdata.d_buf = malloc (data->d_size);
if (cdata.d_buf == NULL)
{
__libelf_seterrno (ELF_E_NOMEM);
return zstd_cleanup (NULL, NULL);
}
if (gelf_xlatetof (scn->elf, &cdata, data, ei_data) == NULL)
return zstd_cleanup (NULL, &cdata);
}
ZSTD_inBuffer ib = { cdata.d_buf, cdata.d_size, 0 };
/* Get next buffer to see if this is the last one. */
data = next_data;
if (data != NULL)
{
*orig_addralign = MAX (*orig_addralign, data->d_align);
*orig_size += data->d_size;
next_data = elf_getdata (scn, data);
}
else
mode = ZSTD_e_end;
/* Flush one data buffer. */
for (;;)
{
ZSTD_outBuffer ob = { out_buf + used, out_size - used, 0 };
size_t ret = ZSTD_compressStream2 (cctx, &ob, &ib, mode);
if (ZSTD_isError (ret))
{
__libelf_seterrno (ELF_E_COMPRESS_ERROR);
return zstd_cleanup (NULL, convert ? &cdata : NULL);
}
used += ob.pos;
/* Bail out if we are sure the user doesn't want the
compression forced and we are using more compressed data
than original data. */
if (!force && mode == ZSTD_e_end && used >= *orig_size)
return zstd_cleanup ((void *) -1, convert ? &cdata : NULL);
if (ret > 0)
{
void *bigger = realloc (out_buf, out_size + block);
if (bigger == NULL)
{
__libelf_seterrno (ELF_E_NOMEM);
return zstd_cleanup (NULL, convert ? &cdata : NULL);
}
out_buf = bigger;
out_size += block;
}
else
break;
}
if (convert)
{
free (cdata.d_buf);
cdata.d_buf = NULL;
}
}
while (mode != ZSTD_e_end); /* More data blocks. */
ZSTD_freeCCtx (cctx);
*new_size = used;
return out_buf;
}
#endif
/* Given a section, uses the (in-memory) Elf_Data to extract the
original data size (including the given header size) and data
alignment. Returns a buffer that has at least hsize bytes (for the
caller to fill in with a header) plus zlib compressed date. Also
returns the new buffer size in new_size (hsize + compressed data
size). Returns (void *) -1 when FORCE is false and the compressed
data would be bigger than the original data. */
void *
internal_function
__libelf_decompress (void *buf_in, size_t size_in, size_t size_out)
__libelf_compress (Elf_Scn *scn, size_t hsize, int ei_data,
size_t *orig_size, size_t *orig_addralign,
size_t *new_size, bool force, bool use_zstd)
{
/* The compressed data is the on-disk data. We simplify the
implementation a bit by asking for the (converted) in-memory
data (which might be all there is if the user created it with
elf_newdata) and then convert back to raw if needed before
compressing. Should be made a bit more clever to directly
use raw if that is directly available. */
Elf_Data *data = elf_getdata (scn, NULL);
if (data == NULL)
return NULL;
/* When not forced and we immediately know we would use more data by
compressing, because of the header plus zlib overhead (five bytes
per 16 KB block, plus a one-time overhead of six bytes for the
entire stream), don't do anything.
Size estimation for ZSTD compression would be similar. */
Elf_Data *next_data = elf_getdata (scn, data);
if (next_data == NULL && !force
&& data->d_size <= hsize + 5 + 6)
return (void *) -1;
*orig_addralign = data->d_align;
*orig_size = data->d_size;
/* Guess an output block size. 1/8th of the original Elf_Data plus
hsize. Make the first chunk twice that size (25%), then increase
by a block (12.5%) when necessary. */
size_t block = (data->d_size / 8) + hsize;
size_t out_size = 2 * block;
void *out_buf = malloc (out_size);
if (out_buf == NULL)
{
__libelf_seterrno (ELF_E_NOMEM);
return NULL;
}
if (use_zstd)
{
#ifdef USE_ZSTD_COMPRESS
return __libelf_compress_zstd (scn, hsize, ei_data, orig_size,
orig_addralign, new_size, force,
data, next_data, out_buf, out_size,
block);
#else
__libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE);
return NULL;
#endif
}
else
return __libelf_compress_zlib (scn, hsize, ei_data, orig_size,
orig_addralign, new_size, force,
data, next_data, out_buf, out_size,
block);
}
void *
internal_function
__libelf_decompress_zlib (void *buf_in, size_t size_in, size_t size_out)
{
/* Catch highly unlikely compression ratios so we don't allocate
some giant amount of memory for nothing. The max compression
@ -218,7 +364,7 @@ __libelf_decompress (void *buf_in, size_t size_in, size_t size_out)
return NULL;
}
/* Malloc might return NULL when requestion zero size. This is highly
/* Malloc might return NULL when requesting zero size. This is highly
unlikely, it would only happen when the compression was forced.
But we do need a non-NULL buffer to return and set as result.
Just make sure to always allocate at least 1 byte. */
@ -260,6 +406,50 @@ __libelf_decompress (void *buf_in, size_t size_in, size_t size_out)
return buf_out;
}
#ifdef USE_ZSTD
static void *
__libelf_decompress_zstd (void *buf_in, size_t size_in, size_t size_out)
{
/* Malloc might return NULL when requesting zero size. This is highly
unlikely, it would only happen when the compression was forced.
But we do need a non-NULL buffer to return and set as result.
Just make sure to always allocate at least 1 byte. */
void *buf_out = malloc (size_out ?: 1);
if (unlikely (buf_out == NULL))
{
__libelf_seterrno (ELF_E_NOMEM);
return NULL;
}
size_t ret = ZSTD_decompress (buf_out, size_out, buf_in, size_in);
if (unlikely (ZSTD_isError (ret)) || unlikely (ret != size_out))
{
free (buf_out);
__libelf_seterrno (ELF_E_DECOMPRESS_ERROR);
return NULL;
}
else
return buf_out;
}
#endif
void *
internal_function
__libelf_decompress (int chtype, void *buf_in, size_t size_in, size_t size_out)
{
if (chtype == ELFCOMPRESS_ZLIB)
return __libelf_decompress_zlib (buf_in, size_in, size_out);
else
{
#ifdef USE_ZSTD
return __libelf_decompress_zstd (buf_in, size_in, size_out);
#else
__libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE);
return NULL;
#endif
}
}
void *
internal_function
__libelf_decompress_elf (Elf_Scn *scn, size_t *size_out, size_t *addralign)
@ -268,7 +458,19 @@ __libelf_decompress_elf (Elf_Scn *scn, size_t *size_out, size_t *addralign)
if (gelf_getchdr (scn, &chdr) == NULL)
return NULL;
bool unknown_compression = false;
if (chdr.ch_type != ELFCOMPRESS_ZLIB)
{
if (chdr.ch_type != ELFCOMPRESS_ZSTD)
unknown_compression = true;
#ifndef USE_ZSTD
if (chdr.ch_type == ELFCOMPRESS_ZSTD)
unknown_compression = true;
#endif
}
if (unknown_compression)
{
__libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE);
return NULL;
@ -295,7 +497,9 @@ __libelf_decompress_elf (Elf_Scn *scn, size_t *size_out, size_t *addralign)
? sizeof (Elf32_Chdr) : sizeof (Elf64_Chdr));
size_t size_in = data->d_size - hsize;
void *buf_in = data->d_buf + hsize;
void *buf_out = __libelf_decompress (buf_in, size_in, chdr.ch_size);
void *buf_out
= __libelf_decompress (chdr.ch_type, buf_in, size_in, chdr.ch_size);
*size_out = chdr.ch_size;
*addralign = chdr.ch_addralign;
return buf_out;
@ -315,15 +519,35 @@ __libelf_reset_rawdata (Elf_Scn *scn, void *buf, size_t size, size_t align,
scn->rawdata.d.d_align = align;
scn->rawdata.d.d_type = type;
/* Remove the old data. */
Elf_Data_List *runp = scn->data_list.next;
while (runp != NULL)
{
Elf_Data_List *oldp = runp;
runp = runp->next;
if ((oldp->flags & ELF_F_MALLOCED) != 0)
free (oldp);
}
/* Existing existing data is no longer valid. */
scn->data_list.next = NULL;
scn->data_list_rear = NULL;
if (scn->data_base != scn->rawdata_base)
free (scn->data_base);
scn->data_base = NULL;
if (scn->zdata_base != buf
&& scn->zdata_base != scn->rawdata_base)
{
free (scn->zdata_base);
scn->zdata_base = NULL;
}
if (scn->elf->map_address == NULL
|| scn->rawdata_base == scn->zdata_base
|| (scn->flags & ELF_F_MALLOCED) != 0)
free (scn->rawdata_base);
{
free (scn->rawdata_base);
scn->rawdata_base = NULL;
scn->zdata_base = NULL;
}
scn->rawdata_base = buf;
scn->flags |= ELF_F_MALLOCED;
@ -360,25 +584,30 @@ elf_compress (Elf_Scn *scn, int type, unsigned int flags)
Elf64_Xword sh_flags;
Elf64_Word sh_type;
Elf64_Xword sh_addralign;
union shdr
{
Elf32_Shdr *s32;
Elf64_Shdr *s64;
} shdr;
if (elfclass == ELFCLASS32)
{
Elf32_Shdr *shdr = elf32_getshdr (scn);
if (shdr == NULL)
shdr.s32 = elf32_getshdr (scn);
if (shdr.s32 == NULL)
return -1;
sh_flags = shdr->sh_flags;
sh_type = shdr->sh_type;
sh_addralign = shdr->sh_addralign;
sh_flags = shdr.s32->sh_flags;
sh_type = shdr.s32->sh_type;
sh_addralign = shdr.s32->sh_addralign;
}
else
{
Elf64_Shdr *shdr = elf64_getshdr (scn);
if (shdr == NULL)
shdr.s64 = elf64_getshdr (scn);
if (shdr.s64 == NULL)
return -1;
sh_flags = shdr->sh_flags;
sh_type = shdr->sh_type;
sh_addralign = shdr->sh_addralign;
sh_flags = shdr.s64->sh_flags;
sh_type = shdr.s64->sh_type;
sh_addralign = shdr.s64->sh_addralign;
}
if ((sh_flags & SHF_ALLOC) != 0)
@ -394,7 +623,7 @@ elf_compress (Elf_Scn *scn, int type, unsigned int flags)
}
int compressed = (sh_flags & SHF_COMPRESSED);
if (type == ELFCOMPRESS_ZLIB)
if (type == ELFCOMPRESS_ZLIB || type == ELFCOMPRESS_ZSTD)
{
/* Compress/Deflate. */
if (compressed == 1)
@ -408,7 +637,8 @@ elf_compress (Elf_Scn *scn, int type, unsigned int flags)
size_t orig_size, orig_addralign, new_size;
void *out_buf = __libelf_compress (scn, hsize, elfdata,
&orig_size, &orig_addralign,
&new_size, force);
&new_size, force,
type == ELFCOMPRESS_ZSTD);
/* Compression would make section larger, don't change anything. */
if (out_buf == (void *) -1)
@ -422,7 +652,7 @@ elf_compress (Elf_Scn *scn, int type, unsigned int flags)
if (elfclass == ELFCLASS32)
{
Elf32_Chdr chdr;
chdr.ch_type = ELFCOMPRESS_ZLIB;
chdr.ch_type = type;
chdr.ch_size = orig_size;
chdr.ch_addralign = orig_addralign;
if (elfdata != MY_ELFDATA)
@ -436,7 +666,7 @@ elf_compress (Elf_Scn *scn, int type, unsigned int flags)
else
{
Elf64_Chdr chdr;
chdr.ch_type = ELFCOMPRESS_ZLIB;
chdr.ch_type = type;
chdr.ch_reserved = 0;
chdr.ch_size = orig_size;
chdr.ch_addralign = sh_addralign;
@ -454,17 +684,17 @@ elf_compress (Elf_Scn *scn, int type, unsigned int flags)
correctly and ignored when SHF_COMPRESSED is set. */
if (elfclass == ELFCLASS32)
{
Elf32_Shdr *shdr = elf32_getshdr (scn);
shdr->sh_size = new_size;
shdr->sh_addralign = __libelf_type_align (ELFCLASS32, ELF_T_CHDR);
shdr->sh_flags |= SHF_COMPRESSED;
shdr.s32->sh_size = new_size;
shdr.s32->sh_addralign = __libelf_type_align (ELFCLASS32,
ELF_T_CHDR);
shdr.s32->sh_flags |= SHF_COMPRESSED;
}
else
{
Elf64_Shdr *shdr = elf64_getshdr (scn);
shdr->sh_size = new_size;
shdr->sh_addralign = __libelf_type_align (ELFCLASS64, ELF_T_CHDR);
shdr->sh_flags |= SHF_COMPRESSED;
shdr.s64->sh_size = new_size;
shdr.s64->sh_addralign = __libelf_type_align (ELFCLASS64,
ELF_T_CHDR);
shdr.s64->sh_flags |= SHF_COMPRESSED;
}
__libelf_reset_rawdata (scn, out_buf, new_size, 1, ELF_T_CHDR);
@ -473,6 +703,7 @@ elf_compress (Elf_Scn *scn, int type, unsigned int flags)
data around, but since that might have been multiple Elf_Data
buffers let the user uncompress it explicitly again if they
want it to simplify bookkeeping. */
free (scn->zdata_base);
scn->zdata_base = NULL;
return 1;
@ -505,17 +736,15 @@ elf_compress (Elf_Scn *scn, int type, unsigned int flags)
correctly and ignored when SHF_COMPRESSED is set. */
if (elfclass == ELFCLASS32)
{
Elf32_Shdr *shdr = elf32_getshdr (scn);
shdr->sh_size = scn->zdata_size;
shdr->sh_addralign = scn->zdata_align;
shdr->sh_flags &= ~SHF_COMPRESSED;
shdr.s32->sh_size = scn->zdata_size;
shdr.s32->sh_addralign = scn->zdata_align;
shdr.s32->sh_flags &= ~SHF_COMPRESSED;
}
else
{
Elf64_Shdr *shdr = elf64_getshdr (scn);
shdr->sh_size = scn->zdata_size;
shdr->sh_addralign = scn->zdata_align;
shdr->sh_flags &= ~SHF_COMPRESSED;
shdr.s64->sh_size = scn->zdata_size;
shdr.s64->sh_addralign = scn->zdata_align;
shdr.s64->sh_flags &= ~SHF_COMPRESSED;
}
__libelf_reset_rawdata (scn, scn->zdata_base,

View File

@ -59,25 +59,30 @@ elf_compress_gnu (Elf_Scn *scn, int inflate, unsigned int flags)
Elf64_Xword sh_flags;
Elf64_Word sh_type;
Elf64_Xword sh_addralign;
union shdr
{
Elf32_Shdr *s32;
Elf64_Shdr *s64;
} shdr;
if (elfclass == ELFCLASS32)
{
Elf32_Shdr *shdr = elf32_getshdr (scn);
if (shdr == NULL)
shdr.s32 = elf32_getshdr (scn);
if (shdr.s32 == NULL)
return -1;
sh_flags = shdr->sh_flags;
sh_type = shdr->sh_type;
sh_addralign = shdr->sh_addralign;
sh_flags = shdr.s32->sh_flags;
sh_type = shdr.s32->sh_type;
sh_addralign = shdr.s32->sh_addralign;
}
else
{
Elf64_Shdr *shdr = elf64_getshdr (scn);
if (shdr == NULL)
shdr.s64 = elf64_getshdr (scn);
if (shdr.s64 == NULL)
return -1;
sh_flags = shdr->sh_flags;
sh_type = shdr->sh_type;
sh_addralign = shdr->sh_addralign;
sh_flags = shdr.s64->sh_flags;
sh_type = shdr.s64->sh_type;
sh_addralign = shdr.s64->sh_addralign;
}
/* Allocated sections, or sections that are already are compressed
@ -103,7 +108,8 @@ elf_compress_gnu (Elf_Scn *scn, int inflate, unsigned int flags)
size_t orig_size, new_size, orig_addralign;
void *out_buf = __libelf_compress (scn, hsize, elfdata,
&orig_size, &orig_addralign,
&new_size, force);
&new_size, force,
/* use_zstd */ false);
/* Compression would make section larger, don't change anything. */
if (out_buf == (void *) -1)
@ -121,15 +127,9 @@ elf_compress_gnu (Elf_Scn *scn, int inflate, unsigned int flags)
sh_flags won't have a SHF_COMPRESSED hint in the GNU format.
Just adjust the sh_size. */
if (elfclass == ELFCLASS32)
{
Elf32_Shdr *shdr = elf32_getshdr (scn);
shdr->sh_size = new_size;
}
shdr.s32->sh_size = new_size;
else
{
Elf64_Shdr *shdr = elf64_getshdr (scn);
shdr->sh_size = new_size;
}
shdr.s64->sh_size = new_size;
__libelf_reset_rawdata (scn, out_buf, new_size, 1, ELF_T_BYTE);
@ -178,7 +178,7 @@ elf_compress_gnu (Elf_Scn *scn, int inflate, unsigned int flags)
size_t size = gsize;
size_t size_in = data->d_size - hsize;
void *buf_in = data->d_buf + hsize;
void *buf_out = __libelf_decompress (buf_in, size_in, size);
void *buf_out = __libelf_decompress (ELFCOMPRESS_ZLIB, buf_in, size_in, size);
if (buf_out == NULL)
return -1;
@ -186,15 +186,9 @@ elf_compress_gnu (Elf_Scn *scn, int inflate, unsigned int flags)
sh_flags won't have a SHF_COMPRESSED hint in the GNU format.
Just adjust the sh_size. */
if (elfclass == ELFCLASS32)
{
Elf32_Shdr *shdr = elf32_getshdr (scn);
shdr->sh_size = size;
}
shdr.s32->sh_size = size;
else
{
Elf64_Shdr *shdr = elf64_getshdr (scn);
shdr->sh_size = size;
}
shdr.s64->sh_size = size;
__libelf_reset_rawdata (scn, buf_out, size, sh_addralign,
__libelf_data_type (&ehdr, sh_type,

View File

@ -1,5 +1,6 @@
/* Free resources associated with Elf descriptor.
Copyright (C) 1998,1999,2000,2001,2002,2004,2005,2007,2015,2016 Red Hat, Inc.
Copyright (C) 2023 Mark J. Wielaard <mark@klomp.org>
This file is part of elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 1998.
@ -32,12 +33,22 @@
#endif
#include <assert.h>
#include <search.h>
#include <stddef.h>
#include <stdlib.h>
#include "libelfP.h"
static void
free_chunk (void *n)
{
Elf_Data_Chunk *rawchunk = (Elf_Data_Chunk *)n;
if (rawchunk->dummy_scn.flags & ELF_F_MALLOCED)
free (rawchunk->data.d.d_buf);
free (rawchunk);
}
int
elf_end (Elf *elf)
{
@ -71,7 +82,10 @@ elf_end (Elf *elf)
elf->state.ar.ar_sym = NULL;
if (elf->state.ar.children != NULL)
return 0;
{
rwlock_unlock(elf->lock);
return 0;
}
}
/* Remove this structure from the children list. */
@ -102,6 +116,12 @@ elf_end (Elf *elf)
rwlock_unlock (parent->lock);
}
if (elf->elf_ar_hdr.ar_name != NULL)
free (elf->elf_ar_hdr.ar_name);
if (elf->elf_ar_hdr.ar_rawname != NULL)
free (elf->elf_ar_hdr.ar_rawname);
/* This was the last activation. Free all resources. */
switch (elf->kind)
{
@ -112,20 +132,14 @@ elf_end (Elf *elf)
case ELF_K_ELF:
{
Elf_Data_Chunk *rawchunks
search_tree *rawchunk_tree
= (elf->class == ELFCLASS32
|| (offsetof (struct Elf, state.elf32.rawchunks)
== offsetof (struct Elf, state.elf64.rawchunks))
? elf->state.elf32.rawchunks
: elf->state.elf64.rawchunks);
while (rawchunks != NULL)
{
Elf_Data_Chunk *next = rawchunks->next;
if (rawchunks->dummy_scn.flags & ELF_F_MALLOCED)
free (rawchunks->data.d.d_buf);
free (rawchunks);
rawchunks = next;
}
|| (offsetof (struct Elf, state.elf32.rawchunk_tree)
== offsetof (struct Elf, state.elf64.rawchunk_tree))
? &elf->state.elf32.rawchunk_tree
: &elf->state.elf64.rawchunk_tree);
eu_search_tree_fini (rawchunk_tree, free_chunk);
Elf_ScnList *list = (elf->class == ELFCLASS32
|| (offsetof (struct Elf, state.elf32.scns)
@ -153,7 +167,10 @@ elf_end (Elf *elf)
rawdata_base. If it is already used it will be
freed below. */
if (scn->zdata_base != scn->rawdata_base)
free (scn->zdata_base);
{
free (scn->zdata_base);
scn->zdata_base = NULL;
}
/* If the file has the same byte order and the
architecture doesn't require overly stringent

View File

@ -44,30 +44,12 @@ elf_getarhdr (Elf *elf)
if (elf == NULL)
return NULL;
Elf *parent = elf->parent;
/* Calling this function is not ok for any file type but archives. */
if (parent == NULL)
if (elf->parent == NULL || elf->parent->kind != ELF_K_AR)
{
__libelf_seterrno (ELF_E_INVALID_OP);
return NULL;
}
/* Make sure we have read the archive header. */
if (parent->state.ar.elf_ar_hdr.ar_name == NULL
&& __libelf_next_arhdr_wrlock (parent) != 0)
{
rwlock_wrlock (parent->lock);
int st = __libelf_next_arhdr_wrlock (parent);
rwlock_unlock (parent->lock);
if (st != 0)
/* Something went wrong. Maybe there is no member left. */
return NULL;
}
/* We can be sure the parent is an archive. */
assert (parent->kind == ELF_K_AR);
return &parent->state.ar.elf_ar_hdr;
return &elf->elf_ar_hdr;
}

View File

@ -43,7 +43,7 @@ elf_getaroff (Elf *elf)
{
/* Be gratious, the specs demand it. */
if (elf == NULL || elf->parent == NULL)
return ELF_C_NULL;
return -1;
/* We can be sure the parent is an archive. */
Elf *parent = elf->parent;

View File

@ -582,4 +582,18 @@ elf_getdata (Elf_Scn *scn, Elf_Data *data)
return result;
}
Elf_Data *
internal_function
__elf_getdata_wrlock (Elf_Scn *scn, Elf_Data *data)
{
Elf_Data *result;
if (scn == NULL)
return NULL;
result = __elf_getdata_rdlock (scn, data);
return result;
}
INTDEF(elf_getdata)

View File

@ -1,6 +1,6 @@
/* Return converted data from raw chunk of ELF file.
Copyright (C) 2007, 2014, 2015 Red Hat, Inc.
Copyright (C) 2022 Mark J. Wielaard <mark@klomp.org>
Copyright (C) 2022, 2023 Mark J. Wielaard <mark@klomp.org>
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@ -33,11 +33,26 @@
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "libelfP.h"
#include "common.h"
#include "eu-search.h"
static int
chunk_compare (const void *a, const void *b)
{
Elf_Data_Chunk *da = (Elf_Data_Chunk *)a;
Elf_Data_Chunk *db = (Elf_Data_Chunk *)b;
if (da->offset != db->offset)
return da->offset - db->offset;
if (da->data.d.d_size != db->data.d.d_size)
return da->data.d.d_size - db->data.d.d_size;
return da->data.d.d_type - db->data.d.d_type;
}
Elf_Data *
elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type)
@ -72,22 +87,31 @@ elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type)
int flags = 0;
Elf_Data *result = NULL;
rwlock_rdlock (elf->lock);
rwlock_wrlock (elf->lock);
/* Maybe we already got this chunk? */
Elf_Data_Chunk *rawchunks = elf->state.elf.rawchunks;
while (rawchunks != NULL)
Elf_Data_Chunk key;
key.offset = offset;
key.data.d.d_size = size;
key.data.d.d_type = type;
Elf_Data_Chunk **found
= eu_tsearch_nolock (&key, &elf->state.elf.rawchunk_tree, &chunk_compare);
if (found == NULL)
goto nomem;
/* Existing entry. */
if (*found != &key && *found != NULL)
{
if ((rawchunks->offset == offset || size == 0)
&& rawchunks->data.d.d_size == size
&& rawchunks->data.d.d_type == type)
{
result = &rawchunks->data.d;
goto out;
}
rawchunks = rawchunks->next;
result = &(*found)->data.d;
goto out;
}
/* New entry. Note that *found will point to the newly inserted
(dummy) key. We'll replace it with a real rawchunk when that is
setup. Make sure to tdelete the dummy key if anything goes
wrong. */
size_t align = __libelf_type_align (elf->class, type);
if (elf->map_address != NULL)
{
@ -112,6 +136,8 @@ elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type)
if (rawchunk == NULL)
{
nomem:
eu_tdelete_nolock (&key, &elf->state.elf.rawchunk_tree,
&chunk_compare);
__libelf_seterrno (ELF_E_NOMEM);
goto out;
}
@ -122,6 +148,8 @@ elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type)
!= size))
{
/* Something went wrong. */
eu_tdelete_nolock (&key, &elf->state.elf.rawchunk_tree,
&chunk_compare);
free (rawchunk);
__libelf_seterrno (ELF_E_READ_ERROR);
goto out;
@ -149,6 +177,8 @@ elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type)
/* The copy will be appropriately aligned for direct access. */
memcpy (buffer, rawchunk, size);
free (rawchunk);
}
}
else
@ -165,6 +195,9 @@ elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type)
/* Call the conversion function. */
(*__elf_xfctstom[elf->class - 1][type])(buffer, rawchunk, size, 0);
if (!flags)
free (rawchunk);
}
/* Allocate the dummy container to point at this buffer. */
@ -186,11 +219,7 @@ elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type)
chunk->data.d.d_version = EV_CURRENT;
chunk->offset = offset;
rwlock_unlock (elf->lock);
rwlock_wrlock (elf->lock);
chunk->next = elf->state.elf.rawchunks;
elf->state.elf.rawchunks = chunk;
*found = chunk;
result = &chunk->data.d;
out:

View File

@ -46,5 +46,6 @@ elf_memory (char *image, size_t size)
return NULL;
}
return __libelf_read_mmaped_file (-1, image, 0, size, ELF_C_READ, NULL);
return __libelf_read_mmaped_file (-1, image, 0, size,
ELF_C_READ_MMAP_PRIVATE, NULL);
}

View File

@ -94,9 +94,9 @@ elf_newscn (Elf *elf)
1
#endif
)
newp = calloc (sizeof (Elf_ScnList)
+ ((elf->state.elf.scnincr *= 2)
* sizeof (Elf_Scn)), 1);
newp = calloc (1, sizeof (Elf_ScnList)
+ ((elf->state.elf.scnincr *= 2)
* sizeof (Elf_Scn)));
if (newp == NULL)
{
__libelf_seterrno (ELF_E_NOMEM);

View File

@ -56,7 +56,7 @@ elf_next (Elf *elf)
/* Now advance the offset. */
parent->state.ar.offset += (sizeof (struct ar_hdr)
+ ((parent->state.ar.elf_ar_hdr.ar_size + 1)
+ ((parent->state.ar.cur_ar_hdr.ar_size + 1)
& ~1l));
/* Get the next archive header. */
@ -64,7 +64,7 @@ elf_next (Elf *elf)
/* If necessary, mark the archive header as unusable. */
if (ret == ELF_C_NULL)
parent->state.ar.elf_ar_hdr.ar_name = NULL;
parent->state.ar.cur_ar_hdr.ar_name = NULL;
rwlock_unlock (parent->lock);

View File

@ -53,7 +53,7 @@ elf_rand (Elf *elf, size_t offset)
if (__libelf_next_arhdr_wrlock (elf) != 0)
{
/* Mark the archive header as unusable. */
elf->state.ar.elf_ar_hdr.ar_name = NULL;
elf->elf_ar_hdr.ar_name = NULL;
return 0;
}

View File

@ -84,7 +84,7 @@ __libelf_readall (Elf *elf)
/* If this is an archive and we have derived descriptors get the
locks for all of them. */
libelf_acquire_all (elf);
libelf_acquire_all_children (elf);
if (elf->maximum_size == ~((size_t) 0))
{
@ -141,7 +141,7 @@ __libelf_readall (Elf *elf)
__libelf_seterrno (ELF_E_NOMEM);
/* Free the locks on the children. */
libelf_release_all (elf);
libelf_release_all_children (elf);
}
rwlock_unlock (elf->lock);

View File

@ -1,5 +1,6 @@
/* Get the section index of the extended section index table.
Copyright (C) 2007 Red Hat, Inc.
Copyright (C) 2025 Mark J. Wielaard <mark@klomp.org>
This file is part of elfutils.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2007.
@ -37,14 +38,53 @@
int
elf_scnshndx (Elf_Scn *scn)
{
if (unlikely (scn->shndx_index == 0))
size_t scnndx;
GElf_Shdr shdr_mem;
GElf_Shdr *shdr;
Elf *elf;
Elf_Scn *nscn;
if (scn == NULL)
return -1;
scnndx = scn->index;
elf = scn->elf;
shdr = gelf_getshdr (scn, &shdr_mem);
if (shdr == NULL)
return -1;
/* Only SYMTAB sections can have a SHNDX section. */
if (shdr->sh_type != SHT_SYMTAB)
return 0;
/* By convention the SHT_SYMTAB_SHNDX section is right after the the
SHT_SYMTAB section, so start there. */
nscn = scn;
while ((nscn = elf_nextscn (elf, nscn)) != NULL)
{
/* We do not have the value yet. We get it as a side effect of
getting a section header. */
GElf_Shdr shdr_mem;
(void) INTUSE(gelf_getshdr) (scn, &shdr_mem);
shdr = gelf_getshdr (nscn, &shdr_mem);
if (shdr == NULL)
return -1;
if (shdr->sh_type == SHT_SYMTAB_SHNDX && shdr->sh_link == scnndx)
return nscn->index;
}
return scn->shndx_index;
/* OK, not found, start from the top. */
nscn = NULL;
while ((nscn = elf_nextscn (elf, nscn)) != NULL
&& nscn->index != scnndx)
{
shdr = gelf_getshdr (nscn, &shdr_mem);
if (shdr == NULL)
return -1;
if (shdr->sh_type == SHT_SYMTAB_SHNDX && shdr->sh_link == scnndx)
return nscn->index;
}
/* No shndx found, but no errors. */
return 0;
}
INTDEF(elf_scnshndx)

View File

@ -1,5 +1,6 @@
/* Return string pointer from string section.
Copyright (C) 1998-2002, 2004, 2008, 2009, 2015 Red Hat, Inc.
Copyright (C) 2025 Mark J. Wielaard <mark@klomp.org>
This file is part of elfutils.
Contributed by Ulrich Drepper <drepper@redhat.com>, 1998.
@ -53,24 +54,6 @@ get_zdata (Elf_Scn *strscn)
return zdata;
}
static bool validate_str (const char *str, size_t from, size_t to)
{
#if HAVE_DECL_MEMRCHR
// Check end first, which is likely a zero terminator, to prevent function call
return ((to > 0 && str[to - 1] == '\0')
|| (to - from > 0 && memrchr (&str[from], '\0', to - from - 1) != NULL));
#else
do {
if (to <= from)
return false;
to--;
} while (str[to]);
return true;
#endif
}
char *
elf_strptr (Elf *elf, size_t idx, size_t offset)
{
@ -201,9 +184,12 @@ elf_strptr (Elf *elf, size_t idx, size_t offset)
// initialized yet (when data_read is zero). So we cannot just
// look at the rawdata.d.d_size.
/* Make sure the string is NUL terminated. Start from the end,
which very likely is a NUL char. */
if (likely (validate_str (strscn->rawdata_base, offset, sh_size)))
/* First check there actually is any data. This could be a new
section which hasn't had any data set yet. Then make sure
the string is at a valid offset and NUL terminated. */
if (unlikely (strscn->rawdata_base == NULL))
__libelf_seterrno (ELF_E_INVALID_SECTION);
else if (likely (validate_str (strscn->rawdata_base, offset, sh_size)))
result = &strscn->rawdata_base[offset];
else
__libelf_seterrno (ELF_E_INVALID_INDEX);

View File

@ -32,12 +32,21 @@
#endif
#include <libelfP.h>
#include <pthread.h>
/* Multiple threads may initialize __libelf_version.
pthread_once() ensures that __libelf_version is initialized only once. */
once_define(static, version_once);
/* Currently selected version. Should be EV_CURRENT.
Will be EV_NONE if elf_version () has not been called yet. */
unsigned int __libelf_version = EV_NONE;
static void initialize_version(void)
{
__libelf_version = EV_CURRENT;
}
unsigned int
elf_version (unsigned int version)
{
@ -49,7 +58,7 @@ elf_version (unsigned int version)
/* Phew, we know this version. */
/* Signal that the version is now initialized. */
__libelf_version = EV_CURRENT;
once(version_once, initialize_version);
/* And return the last (or initial) version. */
return EV_CURRENT;

View File

@ -29,28 +29,7 @@
#ifndef EU_CONFIG_H
#define EU_CONFIG_H 1
#ifdef USE_LOCKS
# include <pthread.h>
# include <assert.h>
# define rwlock_define(class,name) class pthread_rwlock_t name
# define RWLOCK_CALL(call) \
({ int _err = pthread_rwlock_ ## call; assert_perror (_err); })
# define rwlock_init(lock) RWLOCK_CALL (init (&lock, NULL))
# define rwlock_fini(lock) RWLOCK_CALL (destroy (&lock))
# define rwlock_rdlock(lock) RWLOCK_CALL (rdlock (&lock))
# define rwlock_wrlock(lock) RWLOCK_CALL (wrlock (&lock))
# define rwlock_unlock(lock) RWLOCK_CALL (unlock (&lock))
#else
/* Eventually we will allow multi-threaded applications to use the
libraries. Therefore we will add the necessary locking although
the macros used expand to nothing for now. */
# define rwlock_define(class,name) class int name
# define rwlock_init(lock) ((void) (lock))
# define rwlock_fini(lock) ((void) (lock))
# define rwlock_rdlock(lock) ((void) (lock))
# define rwlock_wrlock(lock) ((void) (lock))
# define rwlock_unlock(lock) ((void) (lock))
#endif /* USE_LOCKS */
#include "locks.h"
#include <libintl.h>
/* gettext helper macros. */

85
src/eu-search.c Normal file
View File

@ -0,0 +1,85 @@
/* Definitions for thread-safe tsearch/tfind
Copyright (C) 2023 Rice University
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/>. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "eu-search.h"
void *eu_tsearch (const void *key, search_tree *tree,
int (*compare)(const void *, const void *))
{
rwlock_wrlock (tree->lock);
void *ret = tsearch (key, &tree->root, compare);
rwlock_unlock (tree->lock);
return ret;
}
void *eu_tfind (const void *key, search_tree *tree,
int (*compare)(const void *, const void *))
{
rwlock_rdlock (tree->lock);
void *ret = tfind (key, &tree->root, compare);
rwlock_unlock (tree->lock);
return ret;
}
void *eu_tdelete (const void *key, search_tree *tree,
int (*compare)(const void *, const void *))
{
rwlock_wrlock (tree->lock);
void *ret = tdelete (key, &tree->root, compare);
rwlock_unlock (tree->lock);
return ret;
}
void eu_tdestroy (search_tree *tree, void (*free_node)(void *))
{
rwlock_wrlock (tree->lock);
tdestroy (tree->root, free_node);
tree->root = NULL;
rwlock_unlock (tree->lock);
}
void eu_search_tree_init (search_tree *tree)
{
tree->root = NULL;
rwlock_init (tree->lock);
}
void eu_search_tree_fini (search_tree *tree, void (*free_node)(void *))
{
eu_tdestroy (tree, free_node);
rwlock_fini (tree->lock);
}

88
src/eu-search.h Normal file
View File

@ -0,0 +1,88 @@
/* Calls for thread-safe tsearch/tfind
Copyright (C) 2023 Rice University
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 EU_SEARCH_H
#define EU_SEARCH_H 1
#include <stdlib.h>
#include <search.h>
#include <locks.h>
typedef struct
{
void *root;
rwlock_define (, lock);
} search_tree;
/* Search TREE for KEY and add KEY if not found. Synchronized using
TREE's lock. */
extern void *eu_tsearch (const void *key, search_tree *tree,
int (*compare)(const void *, const void *));
/* Search TREE for KEY. Synchronized with TREE's lock. */
extern void *eu_tfind (const void *key, search_tree *tree,
int (*compare)(const void *, const void *));
/* Delete key from TREE. Synchronized with TREE's lock. */
extern void *eu_tdelete (const void *key, search_tree *tree,
int (*compare)(const void *, const void *));
/* Search TREE for KEY and add KEY if not found. No locking is performed. */
static inline void *
eu_tsearch_nolock (const void *key, search_tree *tree,
int (*compare)(const void *, const void *))
{
return tsearch (key, &tree->root, compare);
}
/* Search TREE for KEY. No locking is performed. */
static inline void *
eu_tfind_nolock (const void *key, search_tree *tree,
int (*compare)(const void *, const void *))
{
return tfind (key, &tree->root, compare);
}
/* Delete key from TREE. No locking is performed. */
static inline void *
eu_tdelete_nolock (const void *key, search_tree *tree,
int (*compare)(const void *, const void *))
{
return tdelete (key, &tree->root, compare);
}
/* Free all nodes from TREE. */
void eu_tdestroy (search_tree *tree, void (*free_node)(void *));
/* Initialize TREE's root and lock. */
void eu_search_tree_init (search_tree *tree);
/* Free all nodes from TREE as well as TREE's lock. */
void eu_search_tree_fini (search_tree *tree, void (*free_node)(void *));
#endif

View File

@ -69,7 +69,8 @@ const size_t __libelf_type_sizes[ELFCLASSNUM - 1][ELF_T_NUM] =
[ELF_T_LIB] = sizeof (ElfW2(LIBELFBITS, Ext_Lib)), \
[ELF_T_AUXV] = sizeof (ElfW2(LIBELFBITS, Ext_auxv_t)), \
[ELF_T_CHDR] = sizeof (ElfW2(LIBELFBITS, Ext_Chdr)), \
[ELF_T_GNUHASH] = ELFW2(LIBELFBITS, FSZ_WORD)
[ELF_T_GNUHASH] = ELFW2(LIBELFBITS, FSZ_WORD), \
[ELF_T_RELR] = ELFW2(LIBELFBITS, FSZ_RELR)
TYPE_SIZES (32)
},
[ELFCLASS64 - 1] = {

View File

@ -51,8 +51,8 @@ gelf_getnote (Elf_Data *data, size_t offset, GElf_Nhdr *result,
/* It's easy to handle this type. It has the same size for 32 and
64 bit objects. */
assert (sizeof (GElf_Nhdr) == sizeof (Elf32_Nhdr));
assert (sizeof (GElf_Nhdr) == sizeof (Elf64_Nhdr));
eu_static_assert (sizeof (GElf_Nhdr) == sizeof (Elf32_Nhdr));
eu_static_assert (sizeof (GElf_Nhdr) == sizeof (Elf64_Nhdr));
rwlock_rdlock (((Elf_Data_Scn *) data)->s->elf->lock);

View File

@ -204,7 +204,8 @@ const xfct_t __elf_xfctstom[ELFCLASSNUM - 1][ELF_T_NUM] =
[ELF_T_MOVE] = ElfW2(Bits, cvt_Move), \
[ELF_T_LIB] = ElfW2(Bits, cvt_Lib), \
[ELF_T_AUXV] = ElfW2(Bits, cvt_auxv_t), \
[ELF_T_CHDR] = ElfW2(Bits, cvt_chdr)
[ELF_T_CHDR] = ElfW2(Bits, cvt_chdr), \
[ELF_T_RELR] = ElfW2(Bits, cvt_Relr)
define_xfcts (32),
[ELF_T_GNUHASH] = Elf32_cvt_Word
},

View File

@ -36,6 +36,7 @@ FUNDAMENTAL (WORD, Word, LIBELFBITS);
FUNDAMENTAL (SWORD, Sword, LIBELFBITS);
FUNDAMENTAL (XWORD, Xword, LIBELFBITS);
FUNDAMENTAL (SXWORD, Sxword, LIBELFBITS);
FUNDAMENTAL (RELR, Relr, LIBELFBITS);
/* The structured types. */
TYPE (Ehdr, LIBELFBITS)

View File

@ -1,5 +1,6 @@
/* Conversion functions for versioning information.
Copyright (C) 2006, 2007 Red Hat, Inc.
Copyright (C) 2023, Mark J. Wielaard <mark@klomp.org>
This file is part of elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2006.
@ -36,6 +37,7 @@
static void
elf_cvt_gnuhash (void *dest, const void *src, size_t len, int encode)
{
size_t size = len;
/* The GNU hash table format on 64 bit machines mixes 32 bit and 64 bit
words. We must detangle them here. */
Elf32_Word *dest32 = dest;
@ -45,7 +47,7 @@ elf_cvt_gnuhash (void *dest, const void *src, size_t len, int encode)
for (unsigned int cnt = 0; cnt < 4; ++cnt)
{
if (len < 4)
return;
goto done;
dest32[cnt] = bswap_32 (src32[cnt]);
len -= 4;
}
@ -58,7 +60,7 @@ elf_cvt_gnuhash (void *dest, const void *src, size_t len, int encode)
for (unsigned int cnt = 0; cnt < bitmask_words; ++cnt)
{
if (len < 8)
return;
goto done;
dest64[cnt] = bswap_64 (src64[cnt]);
len -= 8;
}
@ -71,4 +73,10 @@ elf_cvt_gnuhash (void *dest, const void *src, size_t len, int encode)
*dest32++ = bswap_32 (*src32++);
len -= 4;
}
done:
/* If there are any bytes left, we weren't able to convert the
partial structures, just copy them over. */
if (len > 0)
memmove (dest + size - len, src + size - len, len);
}

View File

@ -1,5 +1,6 @@
/* Internal interfaces for libelf.
Copyright (C) 1998-2010, 2015, 2016 Red Hat, Inc.
Copyright (C) 2023 Mark J. Wielaard <mark@klomp.org>
This file is part of elfutils.
Contributed by Ulrich Drepper <drepper@redhat.com>, 1998.
@ -32,6 +33,7 @@
#include <ar.h>
#include <gelf.h>
#include "eu-search.h"
#include <errno.h>
#include <stdbool.h>
@ -62,6 +64,7 @@
#define ELF32_FSZ_SWORD 4
#define ELF32_FSZ_XWORD 8
#define ELF32_FSZ_SXWORD 8
#define ELF32_FSZ_RELR 4
/* Same for 64 bits objects. */
#define ELF64_FSZ_ADDR 8
@ -71,6 +74,7 @@
#define ELF64_FSZ_SWORD 4
#define ELF64_FSZ_XWORD 8
#define ELF64_FSZ_SXWORD 8
#define ELF64_FSZ_RELR 8
/* This is an extension of the ELF_F_* enumeration. The values here are
@ -214,9 +218,6 @@ struct Elf_Scn
int data_read; /* Nonzero if the section was created by the
user or if the data from the file/memory
is read. */
int shndx_index; /* Index of the extended section index
table for this symbol table (if this
section is a symbol table). */
size_t index; /* Index of this section. */
struct Elf *elf; /* The underlying ELF file. */
@ -262,11 +263,7 @@ typedef struct Elf_ScnList
typedef struct Elf_Data_Chunk
{
Elf_Data_Scn data;
union
{
Elf_Scn dummy_scn;
struct Elf_Data_Chunk *next;
};
Elf_Scn dummy_scn;
int64_t offset; /* The original raw offset in the Elf image. */
} Elf_Data_Chunk;
@ -309,6 +306,9 @@ struct Elf
/* Reference counting for the descriptor. */
int ref_count;
/* Structure returned by 'elf_getarhdr'. */
Elf_Arhdr elf_ar_hdr;
/* Lock to handle multithreaded programs. */
rwlock_define (,lock);
@ -324,7 +324,8 @@ struct Elf
Elf_ScnList *scns_last; /* Last element in the section list.
If NULL the data has not yet been
read from the file. */
Elf_Data_Chunk *rawchunks; /* List of elf_getdata_rawchunk results. */
search_tree rawchunk_tree; /* Tree and lock for elf_getdata_rawchunk
results. */
unsigned int scnincr; /* Number of sections allocate the last
time. */
int ehdr_flags; /* Flags (dirty) for ELF header. */
@ -343,7 +344,8 @@ struct Elf
Elf_ScnList *scns_last; /* Last element in the section list.
If NULL the data has not yet been
read from the file. */
Elf_Data_Chunk *rawchunks; /* List of elf_getdata_rawchunk results. */
search_tree rawchunk_tree; /* Tree and lock for
elf_getdata_rawchunk results. */
unsigned int scnincr; /* Number of sections allocate the last
time. */
int ehdr_flags; /* Flags (dirty) for ELF header. */
@ -368,7 +370,8 @@ struct Elf
Elf_ScnList *scns_last; /* Last element in the section list.
If NULL the data has not yet been
read from the file. */
Elf_Data_Chunk *rawchunks; /* List of elf_getdata_rawchunk results. */
search_tree rawchunk_tree; /* Tree and lock for
elf_getdata_rawchunk results. */
unsigned int scnincr; /* Number of sections allocate the last
time. */
int ehdr_flags; /* Flags (dirty) for ELF header. */
@ -394,7 +397,8 @@ struct Elf
int64_t offset; /* Offset in file we are currently at.
elf_next() advances this to the next
member of the archive. */
Elf_Arhdr elf_ar_hdr; /* Structure returned by 'elf_getarhdr'. */
Elf_Arhdr cur_ar_hdr; /* Copy of current archive member's structure
returned by 'elf_getarhdr'. */
struct ar_hdr ar_hdr; /* Header read from file. */
char ar_name[16]; /* NUL terminated ar_name of elf_ar_hdr. */
char raw_name[17]; /* This is a buffer for the NUL terminated
@ -515,15 +519,18 @@ extern Elf32_Shdr *__elf32_getshdr_rdlock (Elf_Scn *__scn) internal_function;
extern Elf64_Shdr *__elf64_getshdr_rdlock (Elf_Scn *__scn) internal_function;
extern Elf32_Shdr *__elf32_getshdr_wrlock (Elf_Scn *__scn) internal_function;
extern Elf64_Shdr *__elf64_getshdr_wrlock (Elf_Scn *__scn) internal_function;
extern Elf32_Chdr *__elf32_getchdr_wrlock (Elf_Scn *__scn) internal_function;
extern Elf64_Chdr *__elf64_getchdr_wrlock (Elf_Scn *__scn) internal_function;
extern Elf_Scn *__elf_getscn_internal (Elf *__elf, size_t __index)
attribute_hidden;
extern Elf_Scn *__elf_nextscn_internal (Elf *__elf, Elf_Scn *__scn)
attribute_hidden;
extern int __elf_scnshndx_internal (Elf_Scn *__scn) attribute_hidden;
extern Elf_Data *__elf_getdata_internal (Elf_Scn *__scn, Elf_Data *__data)
attribute_hidden;
extern Elf_Data *__elf_getdata_rdlock (Elf_Scn *__scn, Elf_Data *__data)
internal_function;
extern Elf_Data *__elf_getdata_wrlock (Elf_Scn *__scn, Elf_Data *__data)
internal_function;
extern Elf_Data *__elf_rawdata_internal (Elf_Scn *__scn, Elf_Data *__data)
attribute_hidden;
/* Should be called to setup first section data element if
@ -574,10 +581,10 @@ extern uint32_t __libelf_crc32 (uint32_t crc, unsigned char *buf, size_t len)
extern void * __libelf_compress (Elf_Scn *scn, size_t hsize, int ei_data,
size_t *orig_size, size_t *orig_addralign,
size_t *size, bool force)
size_t *size, bool force, bool use_zstd)
internal_function;
extern void * __libelf_decompress (void *buf_in, size_t size_in,
extern void * __libelf_decompress (int chtype, void *buf_in, size_t size_in,
size_t size_out) internal_function;
extern void * __libelf_decompress_elf (Elf_Scn *scn,
size_t *size_out, size_t *addralign)
@ -614,4 +621,7 @@ extern void __libelf_reset_rawdata (Elf_Scn *scn, void *buf, size_t size,
#define INVALID_NDX(ndx, type, data) \
unlikely ((data)->d_size / sizeof (type) <= (unsigned int) (ndx))
#define ELF64_MIPS_R_TYPE1(i) ((i) & 0xff)
#define ELF64_MIPS_R_TYPE2(i) (((i) >> 8) & 0xff)
#define ELF64_MIPS_R_TYPE3(i) (((i) >> 16) & 0xff)
#endif /* libelfP.h */

78
src/locks.h Normal file
View File

@ -0,0 +1,78 @@
/* Configuration definitions.
Copyright (C) 2024 Red Hat, Inc.
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 LOCKS_H
#define LOCKS_H 1
#ifdef USE_LOCKS
# include <pthread.h>
# include <assert.h>
# define rwlock_define(class,name) class pthread_rwlock_t name
# define once_define(class,name) class pthread_once_t name = PTHREAD_ONCE_INIT
# define RWLOCK_CALL(call) \
({ int _err = pthread_rwlock_ ## call; assert_perror (_err); })
# define ONCE_CALL(call) \
({ int _err = pthread_ ## call; assert_perror (_err); })
# define rwlock_init(lock) RWLOCK_CALL (init (&lock, NULL))
# define rwlock_fini(lock) RWLOCK_CALL (destroy (&lock))
# define rwlock_rdlock(lock) RWLOCK_CALL (rdlock (&lock))
# define rwlock_wrlock(lock) RWLOCK_CALL (wrlock (&lock))
# define rwlock_unlock(lock) RWLOCK_CALL (unlock (&lock))
# define mutex_define(class,name) class pthread_mutex_t name
# define MUTEX_CALL(call) \
({ int _err = pthread_mutex_ ## call; assert_perror (_err); })
# define mutex_init(lock) \
({ pthread_mutexattr_t _attr; \
pthread_mutexattr_init (&_attr); \
pthread_mutexattr_settype (&_attr, PTHREAD_MUTEX_RECURSIVE); \
MUTEX_CALL (init (&lock, &_attr)); })
# define mutex_lock(_lock) MUTEX_CALL (lock (&_lock))
# define mutex_unlock(lock) MUTEX_CALL (unlock (&lock))
# define mutex_fini(lock) MUTEX_CALL (destroy (&lock))
# define once(once_control, init_routine) \
ONCE_CALL (once (&once_control, init_routine))
#else
/* Eventually we will allow multi-threaded applications to use the
libraries. Therefore we will add the necessary locking although
the macros used expand to nothing for now. */
# define rwlock_define(class,name) class int name
# define rwlock_init(lock) ((void) (lock))
# define rwlock_fini(lock) ((void) (lock))
# define rwlock_rdlock(lock) ((void) (lock))
# define rwlock_wrlock(lock) ((void) (lock))
# define rwlock_unlock(lock) ((void) (lock))
# define mutex_define(class,name) class int name
# define mutex_init(lock) ((void) (lock))
# define mutex_lock(lock) ((void) (lock))
# define mutex_unlock(lock) ((void) (lock))
# define mutex_fini(lock) ((void) (lock))
# define once_define(class,name)
# define once(once_control, init_routine) init_routine()
#endif /* USE_LOCKS */
#endif /* locks.h */

View File

@ -27,6 +27,10 @@
the GNU Lesser General Public License along with this program. If
not, see <http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stddef.h>

View File

@ -1,6 +1,7 @@
/* Declarations for common convenience functions.
Copyright (C) 2006-2011 Red Hat, Inc.
Copyright (C) 2022 Mark J. Wielaard <mark@klomp.org>
Copyright (C) 2023 Khem Raj.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@ -30,9 +31,15 @@
#ifndef LIB_SYSTEM_H
#define LIB_SYSTEM_H 1
#include <config.h>
/* Prevent double inclusion of config.h, config.h includes eu-config.h. */
#ifdef HAVE_CONFIG_H
#ifndef EU_CONFIG_H
# include <config.h>
#endif
#endif
#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
@ -97,6 +104,32 @@ startswith (const char *str, const char *prefix)
return strncmp (str, prefix, strlen (prefix)) == 0;
}
/* Return TRUE if STR[FROM] is a valid string with a zero terminator
at or before STR[TO - 1]. Note FROM is an index into the STR
array, while TO is the maximum size of the STR array. This
function returns FALSE when TO is zero or FROM >= TO. */
static inline bool
validate_str (const char *str, size_t from, size_t to)
{
#if HAVE_DECL_MEMRCHR
// Check end first, which is likely a zero terminator,
// to prevent function call
return (to > 0
&& (str[to - 1] == '\0'
|| (to > from
&& memrchr (&str[from], '\0', to - from - 1) != NULL)));
#else
do {
if (to <= from)
return false;
to--;
} while (str[to]);
return true;
#endif
}
/* A special gettext function we use if the strings are too short. */
#define sgettext(Str) \
({ const char *__res = strrchr (_(Str), '|'); \
@ -192,4 +225,17 @@ extern char *__cxa_demangle (const char *mangled_name, char *output_buffer,
extern int never_defined_just_used_for_checking[(expr) ? 1 : -1] \
__attribute__ ((unused))
/* We really want a basename implementation that doesn't modify the
input argument. Normally you get that from string.h with _GNU_SOURCE
define. But some libc implementations don't define it and other
define it, but provide an implementation that still modifies the
argument. So define our own and poison a bare basename symbol. */
static inline const char *
xbasename(const char *s)
{
const char *p = strrchr(s, '/');
return p ? p+1 : s;
}
#pragma GCC poison basename
#endif /* system.h */

57
update Executable file
View File

@ -0,0 +1,57 @@
#!/bin/bash
set -e -o pipefail
shopt -s dotglob extglob nullglob
cd -- "$(git -C "${0%/*}" rev-parse --show-toplevel)"
if [[ $@ != +([0-9])*(.+([0-9])) ]]; then
echo "Usage: ${0##*/} UPSTREAM-VERSION"
echo "Update upstream branch then merge changes into master."
echo "This maintainer script does not attempt to be portable."
exit 64
elif ! git diff --exit-code --quiet; then
echo "Uncommitted changes in the working directory"
exit 1
elif ! git diff --cached --exit-code --quiet; then
echo "Uncommitted changes in the index"
exit 1
fi >&2
TMP=$(mktemp -d tmp-XXXXXX)
trap 'rm -r $TMP' EXIT
echo "Downloading upstream files for version $1:"
URL=https://sourceware.org/elfutils/ftp/$1/elfutils-$1.tar.bz2
COLUMNS=64 curl -L -# "$URL" | tar -x -f - -C $TMP --strip-components=1
git checkout upstream
git rm -q -r include src
mkdir -p include src
for FILE in $TMP/libelf/*.[ch] $TMP/lib/{crc32,eu-search,next_prime}.c \
$TMP/lib/{eu-config,eu-search,fixedsizehash,locks,system}.h; do
sed ':a;s/[ \t]*$//;/^\n*$/{$d;N;ba}' "$FILE" >"src/${FILE##*/}"
git add "src/${FILE##*/}"
done
git mv src/gelf.h src/libelf.h src/nlist.h include
cp $TMP/COPYING-GPLV2 $TMP/COPYING-LGPLV3 .
git add COPYING-GPLV2 COPYING-LGPLV3
if git diff --cached --exit-code --quiet; then
echo "No upstream changes to merge"
git checkout master
else
git commit -m "Update upstream files from elfutils $1"
git checkout master
git merge --no-commit upstream
sed -i "s/^MINOR *=.*/MINOR = $1/" Makefile
git add Makefile
git commit -m "Merge from upstream libelf $1"
echo "Merged libelf ready to review, build and test"
echo "Sign: git tag -m v$1 -s v$1"
echo "Push: git push --tags origin upstream master"
fi