termux-packages/packages/libelf/0003-For-clang-use-Blocks-i...

485 lines
17 KiB
Diff

From e0785056a91f893ef4235aefb2a26bed3b17537f Mon Sep 17 00:00:00 2001
From: Chih-Hung Hsieh <chh@google.com>
Date: Sun, 31 May 2020 14:06:12 +0100
Subject: [PATCH 3/3] For clang use Blocks instead of nested functions.
* Clang has Blocks like closures that can serve similar
purpose as the nested functions in gnu99.
Syntax of Blocks is similar to nested functions that
*NESTED_FUNC macro can be used for the function/block
declarations.
See spec in http://clang.llvm.org/docs/BlockLanguageSpec.html
* Local variables used in a closure should have __BLOCK
attribute unless they are constants.
* Formal parameters used in a closure should be copied
to local variable and declared as __BLOCK.
* Cannot goto and jump over __BLOCK variables, so these
variables have been moved to be declared before goto.
* Clang Blocks cannot copy an array to a closure,
and gcc complains about unbounded stack usage from alloca.
---
lib/nested_func.h | 85 +++++++++++++++++++
libdwfl/dwfl_segment_report_module.c | 117 ++++++++++++++++-----------
libdwfl/link_map.c | 31 ++++---
3 files changed, 174 insertions(+), 59 deletions(-)
create mode 100644 lib/nested_func.h
diff --git a/lib/nested_func.h b/lib/nested_func.h
new file mode 100644
index 0000000..be44a31
--- /dev/null
+++ b/lib/nested_func.h
@@ -0,0 +1,85 @@
+/* Copyright (C) 2015 Red Hat, Inc.
+ This file is part of elfutils.
+ Written by Chih-Hung Hsieh <chh@google.com>, 2015.
+
+ 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 _NESTED_FUNC_H
+#define _NESTED_FUNC_H 1
+
+#if __clang__
+
+ #define __BLOCK __block
+
+ #define NESTED_FUNC(return_type, function_name, \
+ arg_types, arg_types_and_names) \
+ return_type (^function_name) arg_types = \
+ ^ return_type arg_types_and_names
+
+ /* Clang does not like inline keyword before a block variable. */
+ #define INLINE_NESTED_FUNC(r, f, t, a) \
+ NESTED_FUNC (r, f, t, a)
+
+ #define INLINE_INTUSE_NESTED_FUNC(r, f, t, a) \
+ NESTED_FUNC (r, INTUSE(f), t, a)
+
+ /* Recrusive blocks need to be declared before used. */
+ #define RECURSIVE_NESTED_FUNC(return_type, function_name, \
+ arg_types, arg_types_and_names) \
+ __BLOCK return_type (^function_name) arg_types; \
+ function_name = ^ return_type arg_types_and_names
+
+ #define INLINE_RECURSIVE_NESTED_FUNC(r, f, t, a) \
+ RECURSIVE_NESTED_FUNC (r, f, t, a)
+
+ #define INLINE_INTUSE_RECURSIVE_NESTED_FUNC(r, f, t, a) \
+ RECURSIVE_NESTED_FUNC (r, INTUSE(f), t, a)
+
+#else /* gcc nested function */
+
+ #define __BLOCK
+
+ #define NESTED_FUNC(return_type, function_name, \
+ arg_types, arg_types_and_names) \
+ return_type function_name arg_types_and_names
+
+ #define INLINE_NESTED_FUNC(r, f, t, a) \
+ inline NESTED_FUNC (r, f, t, a)
+
+ #define INLINE_INTUSE_NESTED_FUNC(r, f, t, a) \
+ inline NESTED_FUNC (r, INTUSE(f), t, a)
+
+ #define RECURSIVE_NESTED_FUNC(r, f, t, a) \
+ NESTED_FUNC (r, f, t, a)
+
+ #define INLINE_RECURSIVE_NESTED_FUNC(r, f, t, a) \
+ inline RECURSIVE_NESTED_FUNC (r, f, t, a)
+
+ #define INLINE_INTUSE_RECURSIVE_NESTED_FUNC(r, f, t, a) \
+ INLINE_RECURSIVE_NESTED_FUNC (r, INTUSE(f), t, a)
+
+#endif
+
+#endif /* _NESTED_FUNC_H */
diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c
index 430e13d..b7c6733 100644
--- a/libdwfl/dwfl_segment_report_module.c
+++ b/libdwfl/dwfl_segment_report_module.c
@@ -31,6 +31,7 @@
#undef _
#include "libdwflP.h"
#include "common.h"
+#include "nested_func.h"
#include <elf.h>
#include <gelf.h>
@@ -257,19 +258,23 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
GElf_Addr start = dwfl->lookup_addr[segment];
- inline bool segment_read (int segndx,
- void **buffer, size_t *buffer_available,
- GElf_Addr addr, size_t minread)
+ INLINE_NESTED_FUNC (bool, segment_read,
+ (int , void **, size_t *, GElf_Addr, size_t),
+ (int segndx,
+ void **buffer, size_t *buffer_available,
+ GElf_Addr addr, size_t minread))
{
return ! (*memory_callback) (dwfl, segndx, buffer, buffer_available,
addr, minread, memory_callback_arg);
- }
+ };
- inline void release_buffer (void **buffer, size_t *buffer_available)
+ INLINE_NESTED_FUNC (void, release_buffer,
+ (void **, size_t *),
+ (void **buffer, size_t *buffer_available))
{
if (*buffer != NULL)
(void) segment_read (-1, buffer, buffer_available, 0, 0);
- }
+ };
/* First read in the file header and check its sanity. */
@@ -282,7 +287,7 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
here so we can always safely free it. */
void *phdrsp = NULL;
- inline int finish (void)
+ INLINE_NESTED_FUNC (int, finish, (void), (void))
{
free (phdrsp);
release_buffer (&buffer, &buffer_available);
@@ -291,15 +296,17 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
if (fd != -1)
close (fd);
return ndx;
- }
+ };
if (segment_read (ndx, &buffer, &buffer_available,
start, sizeof (Elf64_Ehdr))
|| memcmp (buffer, ELFMAG, SELFMAG) != 0)
return finish ();
- inline bool read_portion (void **data, size_t *data_size,
- GElf_Addr vaddr, size_t filesz)
+ INLINE_NESTED_FUNC (bool, read_portion,
+ (void **, size_t *, GElf_Addr, size_t),
+ (void **data, size_t *data_size,
+ GElf_Addr vaddr, size_t filesz))
{
/* Check whether we will have to read the segment data, or if it
can be returned from the existing buffer. */
@@ -320,13 +327,15 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
*data = vaddr - start + buffer;
*data_size = 0;
return false;
- }
+ };
- inline void finish_portion (void **data, size_t *data_size)
+ INLINE_NESTED_FUNC (void, finish_portion,
+ (void **, size_t *),
+ (void **data, size_t *data_size))
{
if (*data_size != 0)
release_buffer (data, data_size);
- }
+ };
/* Extract the information we need from the file header. */
const unsigned char *e_ident;
@@ -342,13 +351,13 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
uint_fast16_t phnum;
uint_fast16_t phentsize;
GElf_Off shdrs_end;
- Elf_Data xlatefrom =
+ __BLOCK Elf_Data xlatefrom =
{
.d_type = ELF_T_EHDR,
.d_buf = (void *) buffer,
.d_version = EV_CURRENT,
};
- Elf_Data xlateto =
+ __BLOCK Elf_Data xlateto =
{
.d_type = ELF_T_EHDR,
.d_buf = &ehdr,
@@ -433,32 +442,33 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
xlateto.d_size = phdrsp_bytes;
/* Track the bounds of the file visible in memory. */
- GElf_Off file_trimmed_end = 0; /* Proper p_vaddr + p_filesz end. */
- GElf_Off file_end = 0; /* Rounded up to effective page size. */
- GElf_Off contiguous = 0; /* Visible as contiguous file from START. */
- GElf_Off total_filesz = 0; /* Total size of data to read. */
+ __BLOCK GElf_Off file_trimmed_end = 0; /* Proper p_vaddr + p_filesz end. */
+ __BLOCK GElf_Off file_end = 0; /* Rounded up to effective page size. */
+ __BLOCK GElf_Off contiguous = 0; /* Visible as contiguous file from START. */
+ __BLOCK GElf_Off total_filesz = 0; /* Total size of data to read. */
/* Collect the bias between START and the containing PT_LOAD's p_vaddr. */
- GElf_Addr bias = 0;
- bool found_bias = false;
+ __BLOCK GElf_Addr bias = 0;
+ __BLOCK bool found_bias = false;
/* Collect the unbiased bounds of the module here. */
- GElf_Addr module_start = -1l;
- GElf_Addr module_end = 0;
- GElf_Addr module_address_sync = 0;
+ __BLOCK GElf_Addr module_start = -1l;
+ __BLOCK GElf_Addr module_end = 0;
+ __BLOCK GElf_Addr module_address_sync = 0;
/* If we see PT_DYNAMIC, record it here. */
- GElf_Addr dyn_vaddr = 0;
- GElf_Xword dyn_filesz = 0;
+ __BLOCK GElf_Addr dyn_vaddr = 0;
+ __BLOCK GElf_Xword dyn_filesz = 0;
/* Collect the build ID bits here. */
- void *build_id = NULL;
- size_t build_id_len = 0;
- GElf_Addr build_id_vaddr = 0;
+ __BLOCK void *build_id = NULL;
+ __BLOCK size_t build_id_len = 0;
+ __BLOCK GElf_Addr build_id_vaddr = 0;
/* Consider a PT_NOTE we've found in the image. */
- inline void consider_notes (GElf_Addr vaddr, GElf_Xword filesz,
- GElf_Xword align)
+ INLINE_NESTED_FUNC (void, consider_notes,
+ (GElf_Addr, GElf_Xword, GElf_Xword),
+ (GElf_Addr vaddr, GElf_Xword filesz, GElf_Xword align))
{
/* If we have already seen a build ID, we don't care any more. */
if (build_id != NULL || filesz == 0)
@@ -535,13 +545,18 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
if (notes != data)
free (notes);
finish_portion (&data, &data_size);
- }
+ };
/* Consider each of the program headers we've read from the image. */
- inline void consider_phdr (GElf_Word type,
- GElf_Addr vaddr, GElf_Xword memsz,
- GElf_Off offset, GElf_Xword filesz,
- GElf_Xword align)
+ INLINE_NESTED_FUNC (void, consider_phdr,
+ (GElf_Word,
+ GElf_Addr, GElf_Xword,
+ GElf_Off, GElf_Xword,
+ GElf_Xword),
+ (GElf_Word type,
+ GElf_Addr vaddr, GElf_Xword memsz,
+ GElf_Off offset, GElf_Xword filesz,
+ GElf_Xword align))
{
switch (type)
{
@@ -604,7 +619,7 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
module_end = vaddr_end;
break;
}
- }
+ };
Elf32_Phdr (*p32)[phnum] = phdrsp;
Elf64_Phdr (*p64)[phnum] = phdrsp;
@@ -751,11 +766,12 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
We need its DT_STRTAB and DT_STRSZ to decipher DT_SONAME,
and they also tell us the essential portion of the file
for fetching symbols. */
- GElf_Addr soname_stroff = 0;
- GElf_Addr dynstr_vaddr = 0;
- GElf_Xword dynstrsz = 0;
- bool execlike = false;
- inline bool consider_dyn (GElf_Sxword tag, GElf_Xword val)
+ __BLOCK GElf_Addr soname_stroff = 0;
+ __BLOCK GElf_Addr dynstr_vaddr = 0;
+ __BLOCK GElf_Xword dynstrsz = 0;
+ __BLOCK bool execlike = false;
+ INLINE_NESTED_FUNC (bool, consider_dyn, (GElf_Sxword, GElf_Xword),
+ (GElf_Sxword tag, GElf_Xword val))
{
switch (tag)
{
@@ -780,7 +796,7 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
}
return soname_stroff != 0 && dynstr_vaddr != 0 && dynstrsz != 0;
- }
+ };
const size_t dyn_entsize = (ei_class == ELFCLASS32
? sizeof (Elf32_Dyn) : sizeof (Elf64_Dyn));
@@ -915,25 +931,30 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
if (unlikely (contents == NULL))
return finish ();
- inline void final_read (size_t offset, GElf_Addr vaddr, size_t size)
+ INLINE_NESTED_FUNC (void, final_read,
+ (size_t, GElf_Addr, size_t),
+ (size_t offset, GElf_Addr vaddr, size_t size))
{
void *into = contents + offset;
size_t read_size = size;
(void) segment_read (addr_segndx (dwfl, segment, vaddr, false),
&into, &read_size, vaddr, size);
- }
+ };
if (contiguous < file_trimmed_end)
{
/* We can't use the memory image verbatim as the file image.
So we'll be reading into a local image of the virtual file. */
- inline void read_phdr (GElf_Word type, GElf_Addr vaddr,
- GElf_Off offset, GElf_Xword filesz)
+ INLINE_NESTED_FUNC (void, read_phdr,
+ (GElf_Word, GElf_Addr,
+ GElf_Off, GElf_Xword),
+ (GElf_Word type, GElf_Addr vaddr,
+ GElf_Off offset, GElf_Xword filesz))
{
if (type == PT_LOAD)
final_read (offset, vaddr + bias, filesz);
- }
+ };
if (ei_class == ELFCLASS32)
for (uint_fast16_t i = 0; i < phnum; ++i)
diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c
index 29307c7..05f4da2 100644
--- a/libdwfl/link_map.c
+++ b/libdwfl/link_map.c
@@ -30,6 +30,7 @@
#include "libdwflP.h"
#include "../libdw/memory-access.h"
#include "system.h"
+#include "nested_func.h"
#include <byteswap.h>
#include <endian.h>
@@ -245,20 +246,27 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
struct r_debug_info *r_debug_info)
{
/* Skip r_version, to aligned r_map field. */
- GElf_Addr read_vaddr = r_debug_vaddr + addrsize (elfclass);
+ __BLOCK GElf_Addr read_vaddr = r_debug_vaddr + addrsize (elfclass);
void *buffer = NULL;
size_t buffer_available = 0;
- inline int release_buffer (int result)
+ INLINE_NESTED_FUNC (int, release_buffer, (int), (int result))
{
if (buffer != NULL)
(void) (*memory_callback) (dwfl, -1, &buffer, &buffer_available, 0, 0,
memory_callback_arg);
return result;
- }
+ };
+#if __clang__
+ /* Clang Blocks cannot copy an array to a closure. */
+ __BLOCK GElf_Addr *addrs = alloca(4 * sizeof (GElf_Addr));
+#else
+ /* gcc complains about unbounded stack usage from alloca. */
GElf_Addr addrs[4];
- inline bool read_addrs (GElf_Addr vaddr, size_t n)
+#endif
+ INLINE_NESTED_FUNC (bool, read_addrs,
+ (GElf_Addr, size_t), (GElf_Addr vaddr, size_t n))
{
size_t nb = n * addrsize (elfclass); /* Address words -> bytes to read. */
@@ -301,7 +309,7 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
}
return false;
- }
+ };
if (unlikely (read_addrs (read_vaddr, 1)))
return release_buffer (-1);
@@ -754,12 +762,13 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
}
/* If we found the phdr dimensions, search phdrs for PT_DYNAMIC. */
- GElf_Addr dyn_vaddr = 0;
- GElf_Xword dyn_filesz = 0;
- GElf_Addr dyn_bias = (GElf_Addr) -1;
+ __BLOCK GElf_Addr dyn_vaddr = 0;
+ __BLOCK GElf_Xword dyn_filesz = 0;
+ __BLOCK GElf_Addr dyn_bias = (GElf_Addr) -1;
- inline bool consider_phdr (GElf_Word type,
- GElf_Addr vaddr, GElf_Xword filesz)
+ INLINE_NESTED_FUNC (bool, consider_phdr,
+ (GElf_Word, GElf_Addr, GElf_Xword),
+ (GElf_Word type, GElf_Addr vaddr, GElf_Xword filesz))
{
switch (type)
{
@@ -781,7 +790,7 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
}
return false;
- }
+ };
if (phdr != 0 && phnum != 0)
{
--- a/libdw/Makefile.am 2020-05-31 15:31:02.096994754 +0100
+++ b/libdw/Makefile.am 2020-05-31 15:31:38.456994741 +0100
@@ -109,7 +109,7 @@
../libcpu/libcpu_pic.a libdw_pic.a ../libdwelf/libdwelf_pic.a \
../libdwfl/libdwfl_pic.a
libdw_so_DEPS = ../lib/libeu.a ../libelf/libelf.so
-libdw_so_LDLIBS = $(libdw_so_DEPS) -ldl -lz $(argp_LDADD) $(zip_LIBS) -pthread
+libdw_so_LDLIBS = $(libdw_so_DEPS) -ldl -lz $(argp_LDADD) $(zip_LIBS) -pthread -lBlocksRuntime
libdw_so_SOURCES =
libdw.so$(EXEEXT): $(srcdir)/libdw.map $(libdw_so_LIBS) $(libdw_so_DEPS)
$(AM_V_CCLD)$(LINK) $(dso_LDFLAGS) -o $@ \
diff --git a/libdwfl/Makefile.am b/libdwfl/Makefile.am
index 47bd62a..cba562f 100644
--- a/libdwfl/Makefile.am
+++ b/libdwfl/Makefile.am
@@ -40,6 +40,7 @@ noinst_LIBRARIES += libdwfl_pic.a
pkginclude_HEADERS = libdwfl.h
+AM_CFLAGS += -fblocks
libdwfl_a_SOURCES = dwfl_begin.c dwfl_end.c dwfl_error.c dwfl_version.c \
dwfl_module.c dwfl_report_elf.c relocate.c \
dwfl_module_build_id.c dwfl_module_report_build_id.c \
--- a/config/libdw.pc.in 2020-05-31 15:57:15.036994154 +0100
+++ b/config/libdw.pc.in 2020-05-31 15:57:46.646994142 +0100
@@ -19,4 +19,4 @@
# data structures or functions. zlib (gz) is always required, bzip2 (bz2)
# lzma (xz) and zstd () are optional. But bzip2 doesn't have a pkg-config file.
Requires.private: zlib @LIBLZMA@ @LIBZSTD@
-Libs.private: @BZ2_LIB@
+Libs.private: @BZ2_LIB@ BlocksRuntime
--
2.26.2