| From: Paul Pluzhnikov <ppluzhnikov@google.com> |
| Subject: Add dlopen_with_offset to glibc. |
| |
| This patchset is used in Google internal and is needed for |
| Loonix, https://crbug.com/1015890. |
| |
| The patch is a squashed diff of following commits: |
| https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=0010a400dcb13304c9081b0f9ad156ce88178320 |
| https://sourceware.org/git/?p=glibc.git;a=commit;h=024f0eb409268e704a83cae2c1511d31167c6f49 |
| https://sourceware.org/git/?p=glibc.git;a=commit;h=295883290d7f26f483e574e80a851cea2d639d12 |
| https://sourceware.org/git/?p=glibc.git;a=commit;h=771d3bf7065f6c25219cf206816b695a628a4618 |
| https://sourceware.org/git/?p=glibc.git;a=commit;h=a6241b657547f0f708629bc254ebcaafb6f25074 |
| https://sourceware.org/git/?p=glibc.git;a=commit;h=c0342bb26e0251dc2d7ca00a884ea831705e32b4 |
| |
| diff -ruB a/dlfcn/dlfcn.h b/dlfcn/dlfcn.h |
| --- a/dlfcn/dlfcn.h 2020-01-31 18:58:26.005144594 -0800 |
| +++ b/dlfcn/dlfcn.h 2020-01-31 19:10:10.569416564 -0800 |
| @@ -22,6 +22,7 @@ |
| #include <features.h> |
| #define __need_size_t |
| #include <stddef.h> |
| +#include <sys/types.h> |
| |
| /* Collect various system dependent definitions and declarations. */ |
| #include <bits/dlfcn.h> |
| @@ -55,6 +56,26 @@ |
| passed to `dlsym' to get symbol values from it. */ |
| extern void *dlopen (const char *__file, int __mode) __THROWNL; |
| |
| +/* Same as above, but ELF header is at OFF from the start of file. */ |
| +#ifndef __USE_FILE_OFFSET64 |
| +extern void *__google_dlopen_with_offset (__const char *__file, |
| + __off_t offset, |
| + int __mode) __THROW; |
| +#else |
| +# ifdef __REDIRECT_NTH |
| +extern void *__REDIRECT_NTH (__google_dlopen_with_offset, |
| + (__const char *__file, __off64_t offset, int __mode), |
| + __google_dlopen_with_offset64); |
| +# else |
| +#define __google_dlopen_with_offset __google_dlopen_with_offset64 |
| +# endif |
| +#endif /* not __USE_FILE_OFFSET64 */ |
| +#ifdef __USE_LARGEFILE64 |
| +extern void *__google_dlopen_with_offset64 (__const char *__file, |
| + __off64_t offset, |
| + int __mode) __THROW; |
| +#endif |
| + |
| /* Unmap and close a shared object opened by `dlopen'. |
| The handle cannot be used again after calling `dlclose'. */ |
| extern int dlclose (void *__handle) __THROWNL __nonnull ((1)); |
| @@ -68,6 +89,12 @@ |
| /* Like `dlopen', but request object to be allocated in a new namespace. */ |
| extern void *dlmopen (Lmid_t __nsid, const char *__file, int __mode) __THROWNL; |
| |
| +/* Same as above, but ELF header is at OFF from the start of file. */ |
| +extern void *__google_dlmopen_with_offset (Lmid_t __nsid, |
| + __const char *__file, |
| + off_t offset, |
| + int __mode) __THROW; |
| + |
| /* Find the run-time address in the shared object HANDLE refers to |
| of the symbol called NAME with VERSION. */ |
| extern void *dlvsym (void *__restrict __handle, |
| diff -ruB a/dlfcn/dlmopen.c b/dlfcn/dlmopen.c |
| --- a/dlfcn/dlmopen.c 2020-01-31 18:58:26.005144594 -0800 |
| +++ b/dlfcn/dlmopen.c 2020-01-31 18:58:37.493214204 -0800 |
| @@ -38,6 +38,8 @@ |
| { |
| /* Namespace ID. */ |
| Lmid_t nsid; |
| + /* ELF header at offset in file. */ |
| + off_t offset; |
| /* The arguments for dlopen_doit. */ |
| const char *file; |
| int mode; |
| @@ -68,13 +70,52 @@ |
| _dl_signal_error (EINVAL, NULL, NULL, N_("invalid mode")); |
| } |
| |
| - args->new = GLRO(dl_open) (args->file ?: "", args->mode | __RTLD_DLOPEN, |
| + args->new = GLRO(dl_open) (args->file ?: "", args->offset, args->mode | __RTLD_DLOPEN, |
| args->caller, |
| args->nsid, __dlfcn_argc, __dlfcn_argv, |
| __environ); |
| } |
| |
| |
| +static void * |
| +__dlmopen_common (struct dlmopen_args *args) |
| +{ |
| + |
| +# ifdef SHARED |
| + return _dlerror_run (dlmopen_doit, args) ? NULL : args->new; |
| +# else |
| + if (_dlerror_run (dlmopen_doit, args)) |
| + return NULL; |
| + |
| + __libc_register_dl_open_hook ((struct link_map *) args->new); |
| + __libc_register_dlfcn_hook ((struct link_map *) args->new); |
| + |
| + return args->new; |
| +# endif |
| +} |
| + |
| +void * |
| +__dlmopen_with_offset (Lmid_t nsid, const char *file, off_t offset, |
| + int mode DL_CALLER_DECL) |
| +{ |
| +# ifdef SHARED |
| + if (!rtld_active ()) |
| + return _dlfcn_hook->dlmopen_with_offset (nsid, file, offset, mode, RETURN_ADDRESS (0)); |
| +# endif |
| + |
| + struct dlmopen_args oargs; |
| + oargs.nsid = nsid; |
| + oargs.file = file; |
| + oargs.offset = offset; |
| + oargs.mode = mode; |
| + oargs.caller = DL_CALLER; |
| + |
| + return __dlmopen_common (&oargs); |
| +} |
| +# ifdef SHARED |
| +strong_alias (__dlmopen_with_offset, __google_dlmopen_with_offset) |
| +# endif |
| + |
| void * |
| __dlmopen (Lmid_t nsid, const char *file, int mode DL_CALLER_DECL) |
| { |
| @@ -86,20 +127,11 @@ |
| struct dlmopen_args args; |
| args.nsid = nsid; |
| args.file = file; |
| + args.offset = 0; |
| args.mode = mode; |
| args.caller = DL_CALLER; |
| |
| -# ifdef SHARED |
| - return _dlerror_run (dlmopen_doit, &args) ? NULL : args.new; |
| -# else |
| - if (_dlerror_run (dlmopen_doit, &args)) |
| - return NULL; |
| - |
| - __libc_register_dl_open_hook ((struct link_map *) args.new); |
| - __libc_register_dlfcn_hook ((struct link_map *) args.new); |
| - |
| - return args.new; |
| -# endif |
| + return __dlmopen_common (&args); |
| } |
| # ifdef SHARED |
| strong_alias (__dlmopen, dlmopen) |
| diff -ruB a/dlfcn/dlopen.c b/dlfcn/dlopen.c |
| --- a/dlfcn/dlopen.c 2020-01-31 18:58:26.005144594 -0800 |
| +++ b/dlfcn/dlopen.c 2020-02-03 10:27:39.539613901 -0800 |
| @@ -21,6 +21,7 @@ |
| #include <stddef.h> |
| #include <unistd.h> |
| #include <ldsodefs.h> |
| +#include <errno.h> |
| |
| #if !defined SHARED && IS_IN (libdl) |
| |
| @@ -37,6 +38,8 @@ |
| { |
| /* The arguments for dlopen_doit. */ |
| const char *file; |
| + /* ELF header at offset in file. */ |
| + off_t offset; |
| int mode; |
| /* The return value of dlopen_doit. */ |
| void *new; |
| @@ -63,13 +66,61 @@ |
| | __RTLD_SPROF)) |
| _dl_signal_error (0, NULL, NULL, _("invalid mode parameter")); |
| |
| - args->new = GLRO(dl_open) (args->file ?: "", args->mode | __RTLD_DLOPEN, |
| + args->new = GLRO(dl_open) (args->file ?: "", args->offset, args->mode | __RTLD_DLOPEN, |
| args->caller, |
| args->file == NULL ? LM_ID_BASE : NS, |
| __dlfcn_argc, __dlfcn_argv, __environ); |
| } |
| |
| |
| +static void * |
| +__dlopen_common (struct dlopen_args *args) |
| +{ |
| +# ifdef SHARED |
| + return _dlerror_run (dlopen_doit, args) ? NULL : args->new; |
| +# else |
| + if (_dlerror_run (dlopen_doit, args)) |
| + return NULL; |
| + |
| + __libc_register_dl_open_hook ((struct link_map *) args->new); |
| + __libc_register_dlfcn_hook ((struct link_map *) args->new); |
| + |
| + return args->new; |
| +# endif |
| +} |
| + |
| +# ifdef SHARED |
| +void * |
| +__dlopen_with_offset (const char *file, off_t offset, int mode DL_CALLER_DECL) |
| +{ |
| + if (!rtld_active ()) |
| + return _dlfcn_hook->dlopen_with_offset (file, offset, mode, DL_CALLER); |
| + |
| + struct dlopen_args oargs; |
| + oargs.file = file; |
| + oargs.offset = offset; |
| + oargs.mode = mode; |
| + oargs.caller = DL_CALLER; |
| + |
| + return __dlopen_common (&oargs); |
| +} |
| +strong_alias (__dlopen_with_offset, __google_dlopen_with_offset) |
| + |
| +void * |
| +__dlopen_with_offset64 (const char *file, off64_t offset, int mode DL_CALLER_DECL) |
| +{ |
| +#ifndef __OFF_T_MATCHES_OFF64_T |
| + if (offset > 0xFFFFFFFF) { |
| + _dl_signal_error(EFBIG, "__dlopen_with_offset64", NULL, |
| + N_("File offset too large. Only 32 bit ELF supported.")); |
| + return NULL; |
| + } |
| +#endif |
| + return __dlopen_with_offset(file, offset, mode); |
| +} |
| +strong_alias (__dlopen_with_offset64, __google_dlopen_with_offset64) |
| +# endif |
| + |
| void * |
| __dlopen (const char *file, int mode DL_CALLER_DECL) |
| { |
| @@ -80,20 +131,11 @@ |
| |
| struct dlopen_args args; |
| args.file = file; |
| + args.offset = 0; |
| args.mode = mode; |
| args.caller = DL_CALLER; |
| |
| -# ifdef SHARED |
| - return _dlerror_run (dlopen_doit, &args) ? NULL : args.new; |
| -# else |
| - if (_dlerror_run (dlopen_doit, &args)) |
| - return NULL; |
| - |
| - __libc_register_dl_open_hook ((struct link_map *) args.new); |
| - __libc_register_dlfcn_hook ((struct link_map *) args.new); |
| - |
| - return args.new; |
| -# endif |
| + return __dlopen_common (&args); |
| } |
| # ifdef SHARED |
| # include <shlib-compat.h> |
| diff -ruB a/dlfcn/dlopenold.c b/dlfcn/dlopenold.c |
| --- a/dlfcn/dlopenold.c 2020-01-31 18:58:26.005144594 -0800 |
| +++ b/dlfcn/dlopenold.c 2020-01-31 18:58:37.493214204 -0800 |
| @@ -51,7 +51,7 @@ |
| { |
| struct dlopen_args *args = (struct dlopen_args *) a; |
| |
| - args->new = GLRO(dl_open) (args->file ?: "", args->mode | __RTLD_DLOPEN, |
| + args->new = GLRO(dl_open) (args->file ?: "", 0, args->mode | __RTLD_DLOPEN, |
| args->caller, |
| args->file == NULL ? LM_ID_BASE : NS, |
| __dlfcn_argc, __dlfcn_argv, __environ); |
| diff -ruB a/dlfcn/Versions b/dlfcn/Versions |
| --- a/dlfcn/Versions 2020-01-31 18:58:26.005144594 -0800 |
| +++ b/dlfcn/Versions 2020-01-31 20:14:57.708927157 -0800 |
| @@ -11,6 +11,12 @@ |
| GLIBC_2.3.4 { |
| dlmopen; |
| } |
| + GLIBC_2.15 { |
| + __google_dlopen_with_offset; __google_dlmopen_with_offset; |
| + } |
| + GLIBC_2.27 { |
| + __google_dlopen_with_offset64; |
| + } |
| GLIBC_PRIVATE { |
| _dlfcn_hook; |
| } |
| diff -ruB a/elf/dl-deps.c b/elf/dl-deps.c |
| --- a/elf/dl-deps.c 2020-01-31 18:58:26.017144667 -0800 |
| +++ b/elf/dl-deps.c 2020-01-31 18:58:37.493214204 -0800 |
| @@ -60,7 +60,7 @@ |
| { |
| struct openaux_args *args = (struct openaux_args *) a; |
| |
| - args->aux = _dl_map_object (args->map, args->name, |
| + args->aux = _dl_map_object (args->map, args->name, 0, |
| (args->map->l_type == lt_executable |
| ? lt_library : args->map->l_type), |
| args->trace_mode, args->open_mode, |
| diff -ruB a/elf/dl-libc.c b/elf/dl-libc.c |
| --- a/elf/dl-libc.c 2020-01-31 18:58:26.005144594 -0800 |
| +++ b/elf/dl-libc.c 2020-01-31 18:58:37.493214204 -0800 |
| @@ -59,6 +59,7 @@ |
| { |
| /* Argument to do_dlopen. */ |
| const char *name; |
| + off_t offset; |
| /* Opening mode. */ |
| int mode; |
| /* This is the caller of the dlopen() function. */ |
| @@ -93,7 +94,7 @@ |
| { |
| struct do_dlopen_args *args = (struct do_dlopen_args *) ptr; |
| /* Open and relocate the shared object. */ |
| - args->map = GLRO(dl_open) (args->name, args->mode, args->caller_dlopen, |
| + args->map = GLRO(dl_open) (args->name, args->offset, args->mode, args->caller_dlopen, |
| __LM_ID_CALLER, __libc_argc, __libc_argv, |
| __environ); |
| } |
| @@ -186,6 +187,7 @@ |
| { |
| struct do_dlopen_args args; |
| args.name = name; |
| + args.offset = 0; |
| args.mode = mode; |
| args.caller_dlopen = RETURN_ADDRESS (0); |
| |
| diff -ruB a/elf/dl-load.c b/elf/dl-load.c |
| --- a/elf/dl-load.c 2020-01-31 18:58:26.017144667 -0800 |
| +++ b/elf/dl-load.c 2020-01-31 19:17:00.667895111 -0800 |
| @@ -35,6 +35,7 @@ |
| #include <stackinfo.h> |
| #include <caller.h> |
| #include <sysdep.h> |
| +#include <_itoa.h> |
| #include <stap-probe.h> |
| #include <libc-pointer-arith.h> |
| #include <array_length.h> |
| @@ -856,7 +857,7 @@ |
| static |
| #endif |
| struct link_map * |
| -_dl_map_object_from_fd (const char *name, const char *origname, int fd, |
| +_dl_map_object_from_fd (const char *name, const char *origname, int fd, off_t offset, |
| struct filebuf *fbp, char *realname, |
| struct link_map *loader, int l_type, int mode, |
| void **stack_endp, Lmid_t nsid) |
| @@ -887,7 +888,8 @@ |
| |
| /* Look again to see if the real name matched another already loaded. */ |
| for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next) |
| - if (!l->l_removed && _dl_file_id_match_p (&l->l_file_id, &id)) |
| + if (!l->l_removed && _dl_file_id_match_p (&l->l_file_id, &id) |
| + && l->l_off == offset) |
| { |
| /* The object is already loaded. |
| Just bump its reference count and return it. */ |
| @@ -896,7 +898,10 @@ |
| /* If the name is not in the list of names for this object add |
| it. */ |
| free (realname); |
| - add_name_to_object (l, name); |
| + if (offset == 0) |
| + /* If offset!=0, foo.so/@0x<offset> should be the *only* |
| + name for this object. b/20141439. */ |
| + add_name_to_object (l, name); |
| |
| return l; |
| } |
| @@ -994,8 +999,29 @@ |
| else |
| assert (r->r_state == RT_ADD); |
| |
| +#ifdef SHARED |
| + // This code could be linked into 'sln', which does not have _itoa. |
| + // We only care about this when this is linked into ld-linux. |
| + if (offset != 0) |
| + { |
| + /* Google-specific: to help GDB, and for b/18243822, turn realname |
| + into "realname/@0x<offset>" */ |
| + realname = realloc (realname, strlen(realname) + 16 + 4 /* "/@0x" */); |
| + if (realname == NULL) |
| + { |
| + errstring = N_("unable to realloc"); |
| + goto call_lose_errno; |
| + } |
| + strcat(realname, "/@0x"); |
| + |
| + char tmp[20]; |
| + tmp[19] = '\0'; |
| + strcat(realname, _itoa(offset, &tmp[19], 16, 0)); |
| + } |
| +#endif |
| + |
| /* Enter the new object in the list of loaded objects. */ |
| - l = _dl_new_object (realname, name, l_type, loader, mode, nsid); |
| + l = _dl_new_object (realname, (offset ? realname : name), l_type, loader, mode, nsid); |
| if (__glibc_unlikely (l == NULL)) |
| { |
| #ifdef SHARED |
| @@ -1082,7 +1108,12 @@ |
| c->mapend = ALIGN_UP (ph->p_vaddr + ph->p_filesz, GLRO(dl_pagesize)); |
| c->dataend = ph->p_vaddr + ph->p_filesz; |
| c->allocend = ph->p_vaddr + ph->p_memsz; |
| - c->mapoff = ALIGN_DOWN (ph->p_offset, GLRO(dl_pagesize)); |
| + if (offset & (GLRO(dl_pagesize) - 1)) |
| + { |
| + errstring = N_("invalid offset"); |
| + goto call_lose; |
| + } |
| + c->mapoff = ALIGN_DOWN(offset + ph->p_offset, GLRO(dl_pagesize)); |
| |
| /* Determine whether there is a gap between the last segment |
| and this one. */ |
| @@ -1362,6 +1393,8 @@ |
| assert (origname == NULL); |
| #endif |
| |
| + l->l_off = offset; |
| + |
| /* When we profile the SONAME might be needed for something else but |
| loading. Add it right away. */ |
| if (__glibc_unlikely (GLRO(dl_profile) != NULL) |
| @@ -1447,7 +1480,7 @@ |
| If FD is not -1, then the file is already open and FD refers to it. |
| In that case, FD is consumed for both successful and error returns. */ |
| static int |
| -open_verify (const char *name, int fd, |
| +open_verify (const char *name, int fd, off_t offset, |
| struct filebuf *fbp, struct link_map *loader, |
| int whatcode, int mode, bool *found_other_class, bool free_name) |
| { |
| @@ -1528,6 +1561,9 @@ |
| unsigned int osversion; |
| size_t maplength; |
| |
| + if (offset > 0 && __lseek (fd, offset, SEEK_SET) == -1) |
| + goto close_and_out; |
| + |
| /* We successfully opened the file. Now verify it is a file |
| we can use. */ |
| __set_errno (0); |
| @@ -1763,7 +1799,7 @@ |
| if MAY_FREE_DIRS is true. */ |
| |
| static int |
| -open_path (const char *name, size_t namelen, int mode, |
| +open_path (const char *name, size_t namelen, off_t offset, int mode, |
| struct r_search_path_struct *sps, char **realname, |
| struct filebuf *fbp, struct link_map *loader, int whatcode, |
| bool *found_other_class) |
| @@ -1815,7 +1851,7 @@ |
| if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS)) |
| _dl_debug_printf (" trying file=%s\n", buf); |
| |
| - fd = open_verify (buf, -1, fbp, loader, whatcode, mode, |
| + fd = open_verify (buf, -1, offset, fbp, loader, whatcode, mode, |
| found_other_class, false); |
| if (this_dir->status[cnt] == unknown) |
| { |
| @@ -1913,7 +1949,7 @@ |
| /* Map in the shared object file NAME. */ |
| |
| struct link_map * |
| -_dl_map_object (struct link_map *loader, const char *name, |
| +_dl_map_object (struct link_map *loader, const char *name, off_t offset, |
| int type, int trace_mode, int mode, Lmid_t nsid) |
| { |
| int fd; |
| @@ -2028,7 +2064,7 @@ |
| for (l = loader; l; l = l->l_loader) |
| if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH")) |
| { |
| - fd = open_path (name, namelen, mode, |
| + fd = open_path (name, namelen, offset, mode, |
| &l->l_rpath_dirs, |
| &realname, &fb, loader, LA_SER_RUNPATH, |
| &found_other_class); |
| @@ -2044,7 +2080,7 @@ |
| && main_map != NULL && main_map->l_type != lt_loaded |
| && cache_rpath (main_map, &main_map->l_rpath_dirs, DT_RPATH, |
| "RPATH")) |
| - fd = open_path (name, namelen, mode, |
| + fd = open_path (name, namelen, offset, mode, |
| &main_map->l_rpath_dirs, |
| &realname, &fb, loader ?: main_map, LA_SER_RUNPATH, |
| &found_other_class); |
| @@ -2052,7 +2088,7 @@ |
| |
| /* Try the LD_LIBRARY_PATH environment variable. */ |
| if (fd == -1 && env_path_list.dirs != (void *) -1) |
| - fd = open_path (name, namelen, mode, &env_path_list, |
| + fd = open_path (name, namelen, offset, mode, &env_path_list, |
| &realname, &fb, |
| loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded, |
| LA_SER_LIBPATH, &found_other_class); |
| @@ -2061,7 +2097,7 @@ |
| if (fd == -1 && loader != NULL |
| && cache_rpath (loader, &loader->l_runpath_dirs, |
| DT_RUNPATH, "RUNPATH")) |
| - fd = open_path (name, namelen, mode, |
| + fd = open_path (name, namelen, offset, mode, |
| &loader->l_runpath_dirs, &realname, &fb, loader, |
| LA_SER_RUNPATH, &found_other_class); |
| |
| @@ -2070,7 +2106,7 @@ |
| realname = _dl_sysdep_open_object (name, namelen, &fd); |
| if (realname != NULL) |
| { |
| - fd = open_verify (realname, fd, |
| + fd = open_verify (realname, fd, offset, |
| &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded, |
| LA_SER_CONFIG, mode, &found_other_class, |
| false); |
| @@ -2124,7 +2160,7 @@ |
| |
| if (cached != NULL) |
| { |
| - fd = open_verify (cached, -1, |
| + fd = open_verify (cached, -1, 0, |
| &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded, |
| LA_SER_CONFIG, mode, &found_other_class, |
| false); |
| @@ -2142,7 +2178,7 @@ |
| && ((l = loader ?: GL(dl_ns)[nsid]._ns_loaded) == NULL |
| || __glibc_likely (!(l->l_flags_1 & DF_1_NODEFLIB))) |
| && rtld_search_dirs.dirs != (void *) -1) |
| - fd = open_path (name, namelen, mode, &rtld_search_dirs, |
| + fd = open_path (name, namelen, offset, mode, &rtld_search_dirs, |
| &realname, &fb, l, LA_SER_DEFAULT, &found_other_class); |
| |
| /* Add another newline when we are tracing the library loading. */ |
| @@ -2159,7 +2195,7 @@ |
| fd = -1; |
| else |
| { |
| - fd = open_verify (realname, -1, &fb, |
| + fd = open_verify (realname, -1, offset, &fb, |
| loader ?: GL(dl_ns)[nsid]._ns_loaded, 0, mode, |
| &found_other_class, true); |
| if (__glibc_unlikely (fd == -1)) |
| @@ -2221,7 +2257,7 @@ |
| } |
| |
| void *stack_end = __libc_stack_end; |
| - return _dl_map_object_from_fd (name, origname, fd, &fb, realname, loader, |
| + return _dl_map_object_from_fd (name, origname, fd, offset, &fb, realname, loader, |
| type, mode, &stack_end, nsid); |
| } |
| |
| diff -ruB a/elf/dl-open.c b/elf/dl-open.c |
| --- a/elf/dl-open.c 2020-01-31 18:58:26.017144667 -0800 |
| +++ b/elf/dl-open.c 2020-01-31 18:58:37.493214204 -0800 |
| @@ -44,6 +44,8 @@ |
| struct dl_open_args |
| { |
| const char *file; |
| + /* ELF header at offset in file. */ |
| + off_t offset; |
| int mode; |
| /* This is the caller of the dlopen() function. */ |
| const void *caller_dlopen; |
| @@ -221,7 +223,7 @@ |
| |
| /* Load the named object. */ |
| struct link_map *new; |
| - args->map = new = _dl_map_object (call_map, file, lt_loaded, 0, |
| + args->map = new = _dl_map_object (call_map, file, args->offset, lt_loaded, 0, |
| mode | __RTLD_CALLMAP, args->nsid); |
| |
| /* If the pointer returned is NULL this means the RTLD_NOLOAD flag is |
| @@ -539,7 +541,7 @@ |
| |
| |
| void * |
| -_dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid, |
| +_dl_open (const char *file, off_t offset, int mode, const void *caller_dlopen, Lmid_t nsid, |
| int argc, char *argv[], char *env[]) |
| { |
| if ((mode & RTLD_BINDING_MASK) == 0) |
| @@ -589,6 +591,7 @@ |
| |
| struct dl_open_args args; |
| args.file = file; |
| + args.offset = offset; |
| args.mode = mode; |
| args.caller_dlopen = caller_dlopen; |
| args.caller_dl_open = RETURN_ADDRESS (0); |
| diff -ruB a/elf/rtld.c b/elf/rtld.c |
| --- a/elf/rtld.c 2020-01-31 18:58:26.009144618 -0800 |
| +++ b/elf/rtld.c 2020-01-31 18:58:37.493214204 -0800 |
| @@ -588,7 +588,7 @@ |
| { |
| struct map_args *args = (struct map_args *) a; |
| int type = (args->mode == __RTLD_OPENEXEC) ? lt_executable : lt_library; |
| - args->map = _dl_map_object (args->loader, args->str, type, 0, |
| + args->map = _dl_map_object (args->loader, args->str, 0, type, 0, |
| args->mode, LM_ID_BASE); |
| } |
| |
| @@ -596,7 +596,7 @@ |
| dlmopen_doit (void *a) |
| { |
| struct dlmopen_args *args = (struct dlmopen_args *) a; |
| - args->map = _dl_open (args->fname, |
| + args->map = _dl_open (args->fname, 0, |
| (RTLD_LAZY | __RTLD_DLOPEN | __RTLD_AUDIT |
| | __RTLD_SECURE), |
| dl_main, LM_ID_NEWLM, _dl_argc, _dl_argv, |
| @@ -1050,7 +1050,7 @@ |
| else |
| { |
| HP_TIMING_NOW (start); |
| - _dl_map_object (NULL, rtld_progname, lt_executable, 0, |
| + _dl_map_object (NULL, rtld_progname, 0, lt_executable, 0, |
| __RTLD_OPENEXEC, LM_ID_BASE); |
| HP_TIMING_NOW (stop); |
| |
| Only in a/: glibc-2-27-dlopen-with-offset.patch |
| diff -ruB a/include/dlfcn.h b/include/dlfcn.h |
| --- a/include/dlfcn.h 2020-01-31 18:58:26.057144909 -0800 |
| +++ b/include/dlfcn.h 2020-01-31 18:58:37.493214204 -0800 |
| @@ -1,5 +1,6 @@ |
| #ifndef _DLFCN_H |
| #include <dlfcn/dlfcn.h> |
| +#include <sys/types.h> |
| #ifndef _ISOMAC |
| #include <link.h> /* For ElfW. */ |
| #include <stdbool.h> |
| @@ -88,6 +89,8 @@ |
| struct dlfcn_hook |
| { |
| void *(*dlopen) (const char *file, int mode, void *dl_caller); |
| + void *(*dlopen_with_offset) (const char *file, off_t offset, |
| + int mode, void *dl_caller); |
| int (*dlclose) (void *handle); |
| void *(*dlsym) (void *handle, const char *name, void *dl_caller); |
| void *(*dlvsym) (void *handle, const char *name, const char *version, |
| @@ -98,6 +101,8 @@ |
| void **extra_info, int flags); |
| int (*dlinfo) (void *handle, int request, void *arg, void *dl_caller); |
| void *(*dlmopen) (Lmid_t nsid, const char *file, int mode, void *dl_caller); |
| + void *(*dlmopen_with_offset) (Lmid_t nsid, const char *file, off_t offset, |
| + int mode, void *dl_caller); |
| void *pad[4]; |
| }; |
| |
| @@ -106,8 +111,14 @@ |
| |
| extern void *__dlopen (const char *file, int mode DL_CALLER_DECL) |
| attribute_hidden; |
| +extern void *__dlopen_with_offset (const char *file, off_t offset, |
| + int mode DL_CALLER_DECL) |
| + attribute_hidden; |
| extern void *__dlmopen (Lmid_t nsid, const char *file, int mode DL_CALLER_DECL) |
| attribute_hidden; |
| +extern void *__dlmopen_with_offset (Lmid_t nsid, const char *file, off_t offset, |
| + int mode DL_CALLER_DECL) |
| + attribute_hidden; |
| extern int __dlclose (void *handle) |
| attribute_hidden; |
| extern void *__dlsym (void *handle, const char *name DL_CALLER_DECL) |
| diff -ruB a/include/link.h b/include/link.h |
| --- a/include/link.h 2020-01-31 18:58:26.057144909 -0800 |
| +++ b/include/link.h 2020-01-31 18:58:37.493214204 -0800 |
| @@ -246,6 +246,12 @@ |
| object is the same as one already loaded. */ |
| struct r_file_id l_file_id; |
| |
| + /* Google-specific extension, intended to be part of public interface |
| + to the debugger. As such, it belongs right after l_prev... except |
| + putting it there causes Google libunwind to crash due to its own |
| + peeking into glibc internals (see grte_v1_glibc_link_map). */ |
| + size_t l_off; /* File offset to Elf_Ehdr. */ |
| + |
| /* Collected information about own RUNPATH directories. */ |
| struct r_search_path_struct l_runpath_dirs; |
| |
| diff -ruB a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h |
| --- a/sysdeps/generic/ldsodefs.h 2020-01-31 18:58:26.261146146 -0800 |
| +++ b/sysdeps/generic/ldsodefs.h 2020-01-31 18:58:37.497214228 -0800 |
| @@ -597,8 +597,9 @@ |
| const struct r_found_version *, int, int, |
| struct link_map *); |
| int (*_dl_check_caller) (const void *, enum allowmask); |
| - void *(*_dl_open) (const char *file, int mode, const void *caller_dlopen, |
| - Lmid_t nsid, int argc, char *argv[], char *env[]); |
| + void *(*_dl_open) (const char *file, off_t offset, int mode, |
| + const void *caller_dlopen, Lmid_t nsid, |
| + int argc, char *argv[], char *env[]); |
| void (*_dl_close) (void *map); |
| void *(*_dl_tls_get_addr_soft) (struct link_map *); |
| #ifdef HAVE_DL_DISCOVER_OSVERSION |
| @@ -849,10 +850,12 @@ |
| libc_hidden_proto (_dl_catch_exception) |
| |
| /* Open the shared object NAME and map in its segments. |
| + ELF header is at OFFSET into the file. |
| LOADER's DT_RPATH is used in searching for NAME. |
| If the object is already opened, returns its existing map. */ |
| extern struct link_map *_dl_map_object (struct link_map *loader, |
| const char *name, |
| + off_t offset, |
| int type, int trace_mode, int mode, |
| Lmid_t nsid) attribute_hidden; |
| |
| @@ -1109,8 +1112,9 @@ |
| /* Open the shared object NAME, relocate it, and run its initializer if it |
| hasn't already been run. MODE is as for `dlopen' (see <dlfcn.h>). If |
| the object is already opened, returns its existing map. */ |
| -extern void *_dl_open (const char *name, int mode, const void *caller, |
| - Lmid_t nsid, int argc, char *argv[], char *env[]) |
| +extern void *_dl_open (const char *name, off_t offset, int mode, |
| + const void *caller, Lmid_t nsid, |
| + int argc, char *argv[], char *env[]) |
| attribute_hidden; |
| |
| /* Free or queue for freeing scope OLD. If other threads might be |