diff options
author | edp <none@none> | 2008-06-09 16:39:11 -0700 |
---|---|---|
committer | edp <none@none> | 2008-06-09 16:39:11 -0700 |
commit | 22872efb9462b28180d11ea401344608e641a5aa (patch) | |
tree | 4e19a1682581bff49a299d190161c54de0a5accd | |
parent | 0e8b4070e8262256f51dbb1aae9d22fa2f1366fc (diff) | |
download | illumos-joyent-22872efb9462b28180d11ea401344608e641a5aa.tar.gz |
6599700 librtld_db needs better plugin support
23 files changed, 693 insertions, 302 deletions
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_gelf.c b/usr/src/cmd/mdb/common/mdb/mdb_gelf.c index ade3da21cf..4bf43aec25 100644 --- a/usr/src/cmd/mdb/common/mdb/mdb_gelf.c +++ b/usr/src/cmd/mdb/common/mdb/mdb_gelf.c @@ -468,6 +468,45 @@ gelf_dyn_lookup(mdb_gelf_file_t *gf, GElf_Xword tag) return ((GElf_Xword)-1L); } +void +mdb_gelf_dyns_set(mdb_gelf_file_t *gf, void *dyns, size_t dyns_sz) +{ + size_t ndyns, i, dyn_size; + caddr_t dp; + GElf_Dyn *gdp; + + if (gf->gf_dyns != NULL) { + /* Free the existing dyn entries */ + free(gf->gf_dyns); + gf->gf_dyns = NULL; + gf->gf_ndyns = 0; + } + + if (gf->gf_ehdr.e_ident[EI_CLASS] == ELFCLASS32) + dyn_size = sizeof (Elf32_Dyn); + else + dyn_size = sizeof (Elf64_Dyn); + + ndyns = dyns_sz / dyn_size; + gf->gf_dyns = mdb_zalloc(sizeof (GElf_Dyn) * ndyns, UM_SLEEP); + gf->gf_ndyns = ndyns; + + dp = dyns; + gdp = gf->gf_dyns; + + if (gf->gf_ehdr.e_ident[EI_CLASS] == ELFCLASS32) { + for (i = 0; i < ndyns; i++, dp += dyn_size, gdp++) { + /* LINTED - alignment */ + (void) gelf32_to_dyn((Elf32_Dyn *)dp, gdp); + } + } else { + for (i = 0; i < ndyns; i++, dp += dyn_size, gdp++) { + /* LINTED - alignment */ + (void) gelf64_to_dyn((Elf64_Dyn *)dp, gdp); + } + } +} + static GElf_Dyn * gelf_dyns_init(mdb_gelf_file_t *gf, size_t dyn_size, GElf_Dyn *(*elf2gelf)(const void *, GElf_Dyn *)) diff --git a/usr/src/cmd/mdb/common/mdb/mdb_gelf.h b/usr/src/cmd/mdb/common/mdb/mdb_gelf.h index 4f9d5a95d4..a2baa4cfff 100644 --- a/usr/src/cmd/mdb/common/mdb/mdb_gelf.h +++ b/usr/src/cmd/mdb/common/mdb/mdb_gelf.h @@ -94,6 +94,7 @@ typedef struct mdb_gelf_dsym { extern int mdb_gelf_check(mdb_io_t *, Elf32_Ehdr *, GElf_Half); extern mdb_gelf_file_t *mdb_gelf_create(mdb_io_t *, GElf_Half, int); extern void mdb_gelf_destroy(mdb_gelf_file_t *); +extern void mdb_gelf_dyns_set(mdb_gelf_file_t *, void *, size_t); extern void mdb_gelf_ehdr_to_gehdr(Ehdr *, GElf_Ehdr *); diff --git a/usr/src/cmd/mdb/common/mdb/mdb_kproc.c b/usr/src/cmd/mdb/common/mdb/mdb_kproc.c index 6adda9dbc6..41e57b60b5 100644 --- a/usr/src/cmd/mdb/common/mdb/mdb_kproc.c +++ b/usr/src/cmd/mdb/common/mdb/mdb_kproc.c @@ -182,6 +182,8 @@ kp_file_create(mdb_tgt_t *t, kp_map_t *kpm, GElf_Half etype) { kp_file_t *kpf = mdb_zalloc(sizeof (kp_file_t), UM_SLEEP); kp_data_t *kp = t->t_data; + size_t dyns_sz; + void *dyns; kpf->kpf_fio = kp_io_create(t, kpm); kpf->kpf_map = kpm; @@ -198,6 +200,10 @@ kp_file_create(mdb_tgt_t *t, kp_map_t *kpm, GElf_Half etype) mdb_dprintf(MDB_DBG_TGT, "loading symbols for %s\n", kpm->kpm_map.map_name); + if ((kp->kp_rap != NULL) && (rd_get_dyns(kp->kp_rap, + kpf->kpf_text_base, &dyns, &dyns_sz) == RD_OK)) + mdb_gelf_dyns_set(kpf->kpf_file, dyns, dyns_sz); + kpf->kpf_dynsym = mdb_gelf_symtab_create_dynamic(kpf->kpf_file, MDB_TGT_DYNSYM); diff --git a/usr/src/cmd/sgs/librtld_db/Makefile.com b/usr/src/cmd/sgs/librtld_db/Makefile.com index 5a87d8d2f9..318433264d 100644 --- a/usr/src/cmd/sgs/librtld_db/Makefile.com +++ b/usr/src/cmd/sgs/librtld_db/Makefile.com @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -74,5 +74,8 @@ ROOTFS_LINKS64= $(ROOTFS_LIBDIR64)/$(LIBLINKS) $(ROOTFS_DYNLIB) := FILEMODE= 755 $(ROOTFS_DYNLIB64) := FILEMODE= 755 +pics/rd_elf.o := CERRWARN += -erroff=E_END_OF_LOOP_CODE_NOT_REACHED +pics/rd_elf64.o := CERRWARN += -erroff=E_END_OF_LOOP_CODE_NOT_REACHED + $(VAR_POUND_1)$(ROOTFS_LIBDIR)/$(LINTLIBSRC): ../common/$(LINTLIBSRC) $(VAR_POUND_1)$(INS.file) ../common/$(LINTLIBSRC) diff --git a/usr/src/cmd/sgs/librtld_db/amd64/Makefile b/usr/src/cmd/sgs/librtld_db/amd64/Makefile index 598eee444b..90593524fd 100644 --- a/usr/src/cmd/sgs/librtld_db/amd64/Makefile +++ b/usr/src/cmd/sgs/librtld_db/amd64/Makefile @@ -20,7 +20,7 @@ # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -37,6 +37,7 @@ SGSMSGTARG += $(SGSMSGINTEL) LINTFLAGS64 += $(VAR_LINTFLAGS64) CPPFLAGS += -D_SYSCALL32 CONVLIBDIR = $(CONVLIBDIR64) +DYNFLAGS += -M../common/mapfile-vers.64 .KEEP_STATE: diff --git a/usr/src/cmd/sgs/librtld_db/common/_rtld_db.h b/usr/src/cmd/sgs/librtld_db/common/_rtld_db.h index 0f513c1d32..da4a058372 100644 --- a/usr/src/cmd/sgs/librtld_db/common/_rtld_db.h +++ b/usr/src/cmd/sgs/librtld_db/common/_rtld_db.h @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -39,6 +39,60 @@ extern "C" { #endif +/* + * Brand helper libraries must name their ops vector using this macro. + */ +#ifdef _LP64 +#ifdef _ELF64 +#define RTLD_DB_BRAND_OPS rtld_db_brand_ops64 +#else /* !_ELF64 */ +#define RTLD_DB_BRAND_OPS rtld_db_brand_ops32 +#endif /* !_ELF64 */ +#else /* !_LP64 */ +#define RTLD_DB_BRAND_OPS rtld_db_brand_ops32 +#endif /* !_LP64 */ + +/* + * State kept for brand helper libraries + * + * All librtld_db brand plugin libraries need to specify a Lmid_t value + * that controls how link map ids are assigned to native solaris objects + * (as pointed to by the processes aux vectors) which are enumerated by + * librtld_db. In most cases this value will either be LM_ID_NONE or + * LM_ID_BRAND. + * + * If LM_ID_NONE is specified in the structure below, then when native solaris + * objects are enumerated by librtld_db, their link map id values will match + * the link map ids assigned to those objects by the solaris linker within + * the target process. + * + * If LM_ID_BRAND is specified in the structure below, then when native solaris + * objects are enumerated by librtld_db, their link map id value will be + * explicity set to LM_ID_BRAND, regardless of the link map ids assigned to + * those objects by the solaris linker within the target process. + * + * In all cases the librtld_db brand plugin library can report any link + * map id value that it wants for objects that it enumerates via it's + * rho_loadobj_iter() entry point. + */ +typedef struct __rd_helper_data *rd_helper_data_t; +typedef struct rd_helper_ops { + Lmid_t rho_lmid; + rd_helper_data_t (*rho_init)(rd_agent_t *, + struct ps_prochandle *); + void (*rho_fini)(rd_helper_data_t); + int (*rho_loadobj_iter)(rd_helper_data_t, + rl_iter_f *, void *); + rd_err_e (*rho_get_dyns)(rd_helper_data_t, + psaddr_t, void **, size_t *); +} rd_helper_ops_t; + +typedef struct rd_helper { + void *rh_dlhandle; + rd_helper_ops_t *rh_ops; + rd_helper_data_t rh_data; +} rd_helper_t; + struct rd_agent { mutex_t rd_mutex; struct ps_prochandle *rd_psp; /* prochandle pointer */ @@ -76,26 +130,36 @@ extern int rtld_db_logging; extern rd_err_e rd_binder_exit_addr(struct rd_agent *, const char *, psaddr_t *); -extern rd_err_e _rd_reset32(struct rd_agent *); + extern rd_err_e _rd_event_enable32(rd_agent_t *, int); extern rd_err_e _rd_event_getmsg32(rd_agent_t *, rd_event_msg_t *); +extern rd_err_e _rd_get_dyns32(struct rd_agent *, + psaddr_t, Dyn **, size_t *); +extern rd_err_e _rd_get_ehdr32(struct rd_agent *, + psaddr_t, Ehdr *, uint_t *); extern rd_err_e _rd_objpad_enable32(struct rd_agent *, size_t); extern rd_err_e _rd_loadobj_iter32(rd_agent_t *, rl_iter_f *, void *); +extern rd_err_e _rd_reset32(struct rd_agent *); extern rd_err_e find_dynamic_ent32(struct rd_agent *, psaddr_t, Xword, Dyn *); - extern rd_err_e plt32_resolution(rd_agent_t *, psaddr_t, lwpid_t, psaddr_t, rd_plt_info_t *); +extern rd_err_e validate_rdebug32(struct rd_agent *rap); #ifdef _LP64 -extern rd_err_e _rd_reset64(struct rd_agent *); extern rd_err_e _rd_event_enable64(rd_agent_t *, int); extern rd_err_e _rd_event_getmsg64(rd_agent_t *, rd_event_msg_t *); +extern rd_err_e _rd_get_dyns64(struct rd_agent *, + psaddr_t, Elf64_Dyn **, size_t *); +extern rd_err_e _rd_get_ehdr64(struct rd_agent *, + psaddr_t, Elf64_Ehdr *, uint_t *); extern rd_err_e _rd_objpad_enable64(struct rd_agent *, size_t); extern rd_err_e _rd_loadobj_iter64(rd_agent_t *, rl_iter_f *, void *); +extern rd_err_e _rd_reset64(struct rd_agent *); extern rd_err_e find_dynamic_ent64(struct rd_agent *, psaddr_t, Xword, Elf64_Dyn *); extern rd_err_e plt64_resolution(rd_agent_t *, psaddr_t, lwpid_t, psaddr_t, rd_plt_info_t *); +extern rd_err_e validate_rdebug64(struct rd_agent *rap); #endif #ifdef __cplusplus diff --git a/usr/src/cmd/sgs/librtld_db/common/librtld_db.msg b/usr/src/cmd/sgs/librtld_db/common/librtld_db.msg index a68b417490..97f3e77dbf 100644 --- a/usr/src/cmd/sgs/librtld_db/common/librtld_db.msg +++ b/usr/src/cmd/sgs/librtld_db/common/librtld_db.msg @@ -20,10 +20,11 @@ # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" +# # Message file for cmd/sgs/librtld_db. @@ -75,13 +76,15 @@ @ MSG_DB_READFAIL_2 "rtld_db: rpr: read of 0x%llx failed" @ MSG_DB_READFAIL_3 "rtld_db: roe: read of 0x%llx failed" @ MSG_DB_READFAIL_4 "rtld_db: fde: read of 0x%llx failed" +@ MSG_DB_READFAIL_5 "rtld_db: ge: read of 0x%llx failed" +@ MSG_DB_READFAIL_6 "rtld_db: gd: read of 0x%llx failed" @ MSG_DB_WRITEFAIL_1 "rtld_db: ree: write of 0x%llx failed" @ MSG_DB_WRITEFAIL_2 "rtld_db: roe: write of 0x%llx failed" @ MSG_DB_UNFNDSYM "rtld_db: rbea: unable to find sym: %s" @ MSG_DB_NODYNDEBUG "rtld_db: fde: no %lld found in .dynamic" @ MSG_DB_FINDDYNAMIC "rtld_db: fde: DYNAMIC entry found tag: %d found. \ val: 0x%llx" -@ MSG_DB_HELPER_PREFIX "/usr/lib/brand/" +@ MSG_DB_HELPER_PREFIX "/usr/lib/brand" @@ -99,7 +102,7 @@ @ MSG_DB_RDEVENTGETMSG "rtld_db: rd_event_getmsg(dmodel=%d, type=%d, \ state=%d)" @ MSG_DB_RDOBJPADE "rtld_db: rd_objpad_enable(padsize=0x%llx)" -@ MSG_DB_64BIT_PREFIX "64/"; +@ MSG_DB_64BIT_PREFIX "64/" @ MSG_DB_BRAND_HELPERPATH_PREFIX "%s/%s/%s/%s%s_librtld_db.so.1" @ MSG_DB_BRAND_HELPERPATH "%s/%s/%s%s_librtld_db.so.1" @ MSG_DB_HELPERNOOPS "rtld_db: helper lib loaded but ops not preset" @@ -122,4 +125,5 @@ @ MSG_SYM_DLACT "rtld_db_dlactivity" @ MSG_SYM_RTBIND "elf_rtbndr" @ MSG_SYM_DYNAMIC "_DYNAMIC" -@ MSG_SYM_BRANDOPS "rtld_db_brand_ops" +@ MSG_SYM_BRANDOPS32 "rtld_db_brand_ops32" +@ MSG_SYM_BRANDOPS64 "rtld_db_brand_ops64" diff --git a/usr/src/cmd/sgs/librtld_db/common/llib-lrtld_db b/usr/src/cmd/sgs/librtld_db/common/llib-lrtld_db index f54aa47e17..15bf89cbec 100644 --- a/usr/src/cmd/sgs/librtld_db/common/llib-lrtld_db +++ b/usr/src/cmd/sgs/librtld_db/common/llib-lrtld_db @@ -22,9 +22,9 @@ /* PROTOLIB1 */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. - */ + */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -45,6 +45,5 @@ rd_agent_t * rd_new(struct ps_prochandle *); rd_err_e rd_objpad_enable(struct rd_agent *, size_t); rd_err_e rd_plt_resolution(rd_agent_t *, psaddr_t, lwpid_t, psaddr_t, rd_plt_info_t *); -void rd_fix_phdrs(struct rd_agent *, Elf32_Dyn *, size_t, - uintptr_t); +rd_err_e rd_get_dyns(rd_agent_t *, psaddr_t, void **, size_t *); rd_err_e rd_reset(struct rd_agent *); diff --git a/usr/src/cmd/sgs/librtld_db/common/mapfile-vers b/usr/src/cmd/sgs/librtld_db/common/mapfile-vers index 0739202216..9735d7e0df 100644 --- a/usr/src/cmd/sgs/librtld_db/common/mapfile-vers +++ b/usr/src/cmd/sgs/librtld_db/common/mapfile-vers @@ -1,7 +1,4 @@ # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# # CDDL HEADER START # # The contents of this file are subject to the terms of the @@ -21,7 +18,13 @@ # # CDDL HEADER END # + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# # ident "%Z%%M% %I% %E% SMI" +# SUNW_1.1 { global: @@ -37,12 +40,19 @@ SUNW_1.1 { rd_new; rd_objpad_enable; rd_plt_resolution; - rd_fix_phdrs; rd_reset; local: *; }; +SUNWprivate_1.1 { + global: + _rd_get_dyns32; + _rd_get_ehdr32; + _rd_loadobj_iter32; + rd_get_dyns; + validate_rdebug32; +}; #Externally defined symbols { diff --git a/usr/src/cmd/sgs/librtld_db/common/mapfile-vers.64 b/usr/src/cmd/sgs/librtld_db/common/mapfile-vers.64 new file mode 100644 index 0000000000..5432883c53 --- /dev/null +++ b/usr/src/cmd/sgs/librtld_db/common/mapfile-vers.64 @@ -0,0 +1,35 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +SUNWprivate_1.1 { + global: + _rd_get_dyns64; + _rd_get_ehdr64; + _rd_loadobj_iter64; + validate_rdebug64; +}; diff --git a/usr/src/cmd/sgs/librtld_db/common/rd_elf.c b/usr/src/cmd/sgs/librtld_db/common/rd_elf.c index e427f966e7..99ad5312e5 100644 --- a/usr/src/cmd/sgs/librtld_db/common/rd_elf.c +++ b/usr/src/cmd/sgs/librtld_db/common/rd_elf.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -44,24 +44,30 @@ */ #ifdef _LP64 #ifdef _ELF64 -#define _rd_reset32 _rd_reset64 #define _rd_event_enable32 _rd_event_enable64 #define _rd_event_getmsg32 _rd_event_getmsg64 +#define _rd_get_dyns32 _rd_get_dyns64 +#define _rd_get_ehdr32 _rd_get_ehdr64 #define _rd_objpad_enable32 _rd_objpad_enable64 #define _rd_loadobj_iter32 _rd_loadobj_iter64 +#define _rd_reset32 _rd_reset64 #define find_dynamic_ent32 find_dynamic_ent64 +#define validate_rdebug32 validate_rdebug64 #define TList List #define TListnode Listnode +#define MSG_SYM_BRANDOPS MSG_SYM_BRANDOPS64 #else /* ELF32 */ #define Rt_map Rt_map32 #define Rtld_db_priv Rtld_db_priv32 #define TList List32 #define TListnode Listnode32 #define Lm_list Lm_list32 +#define MSG_SYM_BRANDOPS MSG_SYM_BRANDOPS32 #endif /* _ELF64 */ #else /* _LP64 */ #define TList List #define TListnode Listnode +#define MSG_SYM_BRANDOPS MSG_SYM_BRANDOPS32 #endif /* _LP64 */ /* @@ -73,8 +79,8 @@ typedef ps_err_e (*ps_pbrandname_fp_t)(struct ps_prochandle *, char *, size_t); -static rd_err_e -validate_rdebug(struct rd_agent *rap) +rd_err_e +validate_rdebug32(struct rd_agent *rap) { struct ps_prochandle *php = rap->rd_psp; psaddr_t db_privp; @@ -168,15 +174,6 @@ find_dynamic_ent32(struct rd_agent *rap, psaddr_t dynaddr, extern char rtld_db_helper_path[MAXPATHLEN]; -#ifndef _ELF64 -void -rd_fix_phdrs(struct rd_agent *rap, Elf32_Dyn *dp, size_t sz, uintptr_t a) -{ - if (rap->rd_helper.rh_ops != NULL) - rap->rd_helper.rh_ops->rho_fix_phdrs(rap, dp, sz, a); -} -#endif - rd_err_e _rd_reset32(struct rd_agent *rap) { @@ -231,7 +228,7 @@ _rd_reset32(struct rd_agent *rap) rap->rd_rdebug = (uintptr_t)auxvp->a_un.a_ptr; LOG(ps_plog(MSG_ORIG(MSG_DB_FLDDATA), rap->rd_rdebug)); - rc = validate_rdebug(rap); + rc = validate_rdebug32(rap); break; } auxvp++; @@ -258,7 +255,7 @@ _rd_reset32(struct rd_agent *rap) rap->rd_rdebug = symaddr; LOG(ps_plog(MSG_ORIG(MSG_DB_SYMRDEBUG), EC_ADDR(symaddr))); - rc = validate_rdebug(rap); + rc = validate_rdebug32(rap); } } @@ -280,7 +277,7 @@ _rd_reset32(struct rd_agent *rap) return (rc); } rap->rd_rdebug = dyn.d_un.d_ptr; - rc = validate_rdebug(rap); + rc = validate_rdebug32(rap); if (rc != RD_OK) { LOG(ps_plog(MSG_ORIG(MSG_DB_INITFAILED))); return (rc); @@ -288,17 +285,19 @@ _rd_reset32(struct rd_agent *rap) } /* - * If we are debugging a branded executable, load the appropriate helper - * library, and call its initialization routine. + * If we are debugging a branded executable, load the appropriate + * helper library, and call its initialization routine. Being unable + * to load the helper library is not a critical error. (Hopefully + * we'll still be able to access some objects in the target.) */ ps_pbrandname = (ps_pbrandname_fp_t)dlsym(RTLD_PROBE, "ps_pbrandname"); - if ((ps_pbrandname != NULL) && + while ((ps_pbrandname != NULL) && (ps_pbrandname(php, brandname, MAXPATHLEN) == PS_OK)) { const char *isa = ""; -#ifdef __amd64 +#ifdef _LP64 isa = MSG_ORIG(MSG_DB_64BIT_PREFIX); -#endif /* __amd64 */ +#endif /* _LP64 */ if (rtld_db_helper_path[0] != '\0') (void) snprintf(brandlib, MAXPATHLEN, @@ -312,28 +311,36 @@ _rd_reset32(struct rd_agent *rap) MSG_ORIG(MSG_DB_HELPER_PREFIX), brandname, isa, brandname); - if ((rap->rd_helper.rh_dlhandle = dlopen(brandlib, - RTLD_LAZY | RTLD_LOCAL)) == NULL) { + rap->rd_helper.rh_dlhandle = dlopen(brandlib, + RTLD_LAZY | RTLD_LOCAL); + if (rap->rd_helper.rh_dlhandle == NULL) { LOG(ps_plog(MSG_ORIG(MSG_DB_HELPERLOADFAILED), brandlib)); - return (RD_ERR); + break; } - if ((rap->rd_helper.rh_ops = dlsym(rap->rd_helper.rh_dlhandle, - MSG_ORIG(MSG_SYM_BRANDOPS))) == NULL) { + rap->rd_helper.rh_ops = dlsym(rap->rd_helper.rh_dlhandle, + MSG_ORIG(MSG_SYM_BRANDOPS)); + if (rap->rd_helper.rh_ops == NULL) { LOG(ps_plog(MSG_ORIG(MSG_DB_HELPERNOOPS), brandlib)); - return (RD_ERR); + (void) dlclose(rap->rd_helper.rh_dlhandle); + rap->rd_helper.rh_dlhandle = NULL; + break; } - rap->rd_helper.rh_data = rap->rd_helper.rh_ops->rho_init(php); + rap->rd_helper.rh_data = rap->rd_helper.rh_ops->rho_init(rap, + php); if (rap->rd_helper.rh_data == NULL) { LOG(ps_plog(MSG_ORIG(MSG_DB_HELPERINITFAILED))); (void) dlclose(rap->rd_helper.rh_dlhandle); rap->rd_helper.rh_dlhandle = NULL; rap->rd_helper.rh_ops = NULL; - } else - LOG(ps_plog(MSG_ORIG(MSG_DB_HELPERLOADED), brandname)); + break; + } + + LOG(ps_plog(MSG_ORIG(MSG_DB_HELPERLOADED), brandname)); + break; } if ((rap->rd_flags & RDF_FL_COREFILE) == 0) { @@ -367,6 +374,85 @@ _rd_reset32(struct rd_agent *rap) } rd_err_e +_rd_get_ehdr32(struct rd_agent *rap, + psaddr_t addr, Ehdr *ehdr, uint_t *phnum) +{ + struct ps_prochandle *php = rap->rd_psp; + Shdr shdr; + + if (ps_pread(php, addr, ehdr, sizeof (*ehdr)) != PS_OK) { + LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_5), EC_ADDR(addr))); + return (RD_ERR); + } + if (phnum == NULL) + return (RD_OK); + + if (ehdr->e_phnum != PN_XNUM) { + *phnum = ehdr->e_phnum; + return (RD_OK); + } + + /* deal with elf extended program headers */ + if ((ehdr->e_shoff == 0) || (ehdr->e_shentsize < sizeof (shdr))) + return (RD_ERR); + + addr += ehdr->e_shoff; + if (ps_pread(php, addr, &shdr, sizeof (shdr)) != PS_OK) { + LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_5), EC_ADDR(addr))); + return (RD_ERR); + } + + if (shdr.sh_info == 0) + return (RD_ERR); + + *phnum = shdr.sh_info; + return (RD_OK); +} + +rd_err_e +_rd_get_dyns32(rd_agent_t *rap, psaddr_t addr, Dyn **dynpp, size_t *dynpp_sz) +{ + struct ps_prochandle *php = rap->rd_psp; + rd_err_e err; + uint_t phnum; + Ehdr ehdr; + Phdr phdr; + Dyn *dynp; + int i; + + /* We only need to muck with dyn elements for ET_DYN objects */ + if ((err = _rd_get_ehdr32(rap, addr, &ehdr, &phnum)) != RD_OK) + return (err); + + for (i = 0; i < phnum; i++) { + psaddr_t a = addr + ehdr.e_phoff + (i * ehdr.e_phentsize); + if (ps_pread(php, a, &phdr, sizeof (phdr)) != PS_OK) { + LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_6), EC_ADDR(a))); + return (RD_ERR); + } + if (phdr.p_type == PT_DYNAMIC) + break; + } + if (i == phnum) + return (RD_ERR); + + if ((dynp = malloc(phdr.p_filesz)) == NULL) + return (RD_ERR); + if (ehdr.e_type == ET_DYN) + phdr.p_vaddr += addr; + if (ps_pread(php, phdr.p_vaddr, dynp, phdr.p_filesz) != PS_OK) { + free(dynp); + LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_6), + EC_ADDR(phdr.p_vaddr))); + return (RD_ERR); + } + + *dynpp = dynp; + *dynpp_sz = phdr.p_filesz; + return (RD_OK); +} + +rd_err_e _rd_event_enable32(rd_agent_t *rap, int onoff) { struct ps_prochandle *php = rap->rd_psp; @@ -502,8 +588,10 @@ iter_map(rd_agent_t *rap, unsigned long ident, psaddr_t lmaddr, lobj.rl_base = (psaddr_t)ADDR(&rmap); lobj.rl_flags = 0; lobj.rl_refnameaddr = (psaddr_t)REFNAME(&rmap); - if (rap->rd_helper.rh_dlhandle != NULL) - lobj.rl_lmident = LM_ID_BRAND; + if ((rap->rd_helper.rh_ops != NULL) && + (rap->rd_helper.rh_ops->rho_lmid != LM_ID_NONE)) + lobj.rl_lmident = + rap->rd_helper.rh_ops->rho_lmid; else lobj.rl_lmident = ident; @@ -679,8 +767,8 @@ _rd_loadobj_iter32(rd_agent_t *rap, rl_iter_f *cb, void *client_data) return (rc); if (rap->rd_helper.rh_ops != NULL) - return (rap->rd_helper.rh_ops->rho_loadobj_iter(rap->rd_psp, cb, - client_data, rap->rd_helper.rh_data)); + return (rap->rd_helper.rh_ops->rho_loadobj_iter( + rap->rd_helper.rh_data, cb, client_data)); return (RD_OK); } diff --git a/usr/src/cmd/sgs/librtld_db/common/rtld_db.c b/usr/src/cmd/sgs/librtld_db/common/rtld_db.c index a0324c6107..53f90f9c60 100644 --- a/usr/src/cmd/sgs/librtld_db/common/rtld_db.c +++ b/usr/src/cmd/sgs/librtld_db/common/rtld_db.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -110,6 +110,23 @@ rd_ctl(int cmd, void *arg) } rd_err_e +rd_get_dyns(rd_agent_t *rap, psaddr_t addr, void **dynpp, size_t *dynpp_sz) +{ + if (rap->rd_helper.rh_ops != NULL) + return (rap->rd_helper.rh_ops->rho_get_dyns( + rap->rd_helper.rh_data, addr, dynpp, dynpp_sz)); + +#ifdef _LP64 + if (rap->rd_dmodel == PR_MODEL_LP64) + return (_rd_get_dyns64(rap, + addr, (Elf64_Dyn **)dynpp, dynpp_sz)); + else +#endif + return (_rd_get_dyns32(rap, + addr, (Dyn **)dynpp, dynpp_sz)); +} + +rd_err_e rd_reset(struct rd_agent *rap) { rd_err_e err; @@ -151,7 +168,10 @@ rd_new(struct ps_prochandle *php) rap->rd_psp = php; (void) mutex_init(&rap->rd_mutex, USYNC_THREAD, 0); if (rd_reset(rap) != RD_OK) { - (void) dlclose(rap->rd_helper.rh_dlhandle); + if (rap->rd_helper.rh_dlhandle != NULL) { + rap->rd_helper.rh_ops->rho_fini(rap->rd_helper.rh_data); + (void) dlclose(rap->rd_helper.rh_dlhandle); + } free(rap); LOG(ps_plog(MSG_ORIG(MSG_DB_RESETFAIL))); return ((rd_agent_t *)0); @@ -165,6 +185,10 @@ void rd_delete(rd_agent_t *rap) { LOG(ps_plog(MSG_ORIG(MSG_DB_RDDELETE), rap)); + if (rap->rd_helper.rh_dlhandle != NULL) { + rap->rd_helper.rh_ops->rho_fini(rap->rd_helper.rh_data); + (void) dlclose(rap->rd_helper.rh_dlhandle); + } free(rap); } diff --git a/usr/src/cmd/sgs/librtld_db/sparcv9/Makefile b/usr/src/cmd/sgs/librtld_db/sparcv9/Makefile index 001502facb..de9be4eee9 100644 --- a/usr/src/cmd/sgs/librtld_db/sparcv9/Makefile +++ b/usr/src/cmd/sgs/librtld_db/sparcv9/Makefile @@ -20,7 +20,7 @@ # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -37,6 +37,7 @@ SGSMSGTARG += $(SGSMSGSPARCV9) LINTFLAGS64 += $(VAR_LINTFLAGS64) CPPFLAGS += -D_SYSCALL32 CONVLIBDIR = $(CONVLIBDIR64) +DYNFLAGS += -M../common/mapfile-vers.64 .KEEP_STATE: diff --git a/usr/src/head/link.h b/usr/src/head/link.h index c4f2dd8e94..5948108b37 100644 --- a/usr/src/head/link.h +++ b/usr/src/head/link.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -114,11 +114,10 @@ extern void ld_section64(); */ #define LM_ID_BASE 0x00 #define LM_ID_LDSO 0x01 -#define LM_ID_BRAND 0x02 /* marks branded objs in rd_loadobj_t */ - -#define LM_ID_NUM 3 - +#define LM_ID_NUM 2 +#define LM_ID_BRAND 0xfd /* brand emulation linkmap objs */ +#define LM_ID_NONE 0xfe /* no link map specified */ #define LM_ID_NEWLM 0xff /* create a new link-map */ /* diff --git a/usr/src/head/rtld_db.h b/usr/src/head/rtld_db.h index 52575a3bd3..c442087237 100644 --- a/usr/src/head/rtld_db.h +++ b/usr/src/head/rtld_db.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -161,27 +161,6 @@ typedef struct rd_plt_info { unsigned int pi_flags; } rd_plt_info_t; -/* - * State kept for brand helper libraries - */ -typedef struct rd_helper_ops { - void *(*rho_init)(struct ps_prochandle *); - int (*rho_loadobj_iter)(struct ps_prochandle *, rl_iter_f *cb, - void *client_data, void *helper_data); - void (*rho_fix_phdrs)(struct rd_agent *, Elf32_Dyn *, size_t, - psaddr_t addr); -} rd_helper_ops_t; - -typedef struct rd_helper { - rd_helper_ops_t *rh_ops; - void *rh_data; - void *rh_dlhandle; -} rd_helper_t; - -/* - * Brand helper libraries must name their ops vector using this macro. - */ -#define RTLD_DB_BRAND_OPS rtld_db_brand_ops /* * Values for pi_flags @@ -211,10 +190,9 @@ extern rd_agent_t *rd_new(struct ps_prochandle *); extern rd_err_e rd_objpad_enable(struct rd_agent *, size_t); extern rd_err_e rd_plt_resolution(rd_agent_t *, psaddr_t, lwpid_t, psaddr_t, rd_plt_info_t *); -extern void rd_fix_phdrs(struct rd_agent *, Elf32_Dyn *, - size_t, uintptr_t); +extern rd_err_e rd_get_dyns(rd_agent_t *, psaddr_t, void **, size_t *); extern rd_err_e rd_reset(struct rd_agent *); -#else +#else /* !__STDC__ */ extern void rd_delete(); extern char *rd_errstr(); extern rd_err_e rd_event_addr(); @@ -227,9 +205,9 @@ extern void rd_log(); extern rd_agent_t *rd_new(); extern rd_err_e rd_objpad_enable(); extern rd_err_e rd_plt_resolution(); -extern void rd_fix_phdrs(); +extern rd_err_e rd_get_dyns(); extern rd_err_e rd_reset(); -#endif +#endif /* !__STDC__ */ #ifdef __cplusplus } diff --git a/usr/src/lib/brand/lx/librtld_db/Makefile b/usr/src/lib/brand/lx/librtld_db/Makefile index f1ac26d7d5..2fc0a818f6 100644 --- a/usr/src/lib/brand/lx/librtld_db/Makefile +++ b/usr/src/lib/brand/lx/librtld_db/Makefile @@ -18,8 +18,9 @@ # # CDDL HEADER END # + # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -27,7 +28,7 @@ default: all -include ../../../Makefile.lib +include $(SRC)/lib/Makefile.lib SUBDIRS = $(MACH) $(BUILD64)SUBDIRS += $(MACH64) diff --git a/usr/src/lib/brand/lx/librtld_db/Makefile.com b/usr/src/lib/brand/lx/librtld_db/Makefile.com index 8c723ad86b..202cc0fe7b 100644 --- a/usr/src/lib/brand/lx/librtld_db/Makefile.com +++ b/usr/src/lib/brand/lx/librtld_db/Makefile.com @@ -18,8 +18,9 @@ # # CDDL HEADER END # + # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -28,32 +29,55 @@ LIBRARY = lx_librtld_db.a VERS = .1 COBJS = lx_librtld_db.o -OBJECTS = $(COBJS) +OBJECTS = $(COBJS) $(COBJS64) -include ../../../../Makefile.lib +include $(SRC)/lib/Makefile.lib include ../../Makefile.lx CSRCS = $(COBJS:%o=../common/%c) SRCS = $(CSRCS) SRCDIR = ../common -UTSBASE = ../../../../../uts +UTSBASE = $(SRC)/uts +# +# ATTENTION: +# Librtl_db brand plugin libraries should NOT directly invoke any +# libproc.so interfaces or be linked against libproc. If a librtl_db +# brand plugin library uses libproc.so interfaces then it may break +# any other librtld_db consumers (like mdb) that tries to attach +# to a branded process. The only safe interfaces that the a librtld_db +# brand plugin library can use to access a target process are the +# proc_service(3PROC) apis. +# +DYNFLAGS += $(VERSREF) -M../common/mapfile-vers LIBS = $(DYNLIB) -LDLIBS += -lc -lproc +LDLIBS += -lc -lrtld_db CFLAGS += $(CCVERBOSE) CPPFLAGS += -D_REENTRANT -I../ -I$(UTSBASE)/common/brand/lx \ - -I../../../../../cmd/sgs/librtld_db/common \ - -I../../../../../cmd/sgs/include \ - -I../../../../../cmd/sgs/include/$(MACH) + -I$(SRC)/cmd/sgs/librtld_db/common \ + -I$(SRC)/cmd/sgs/include \ + -I$(SRC)/cmd/sgs/include/$(MACH) ROOTLIBDIR = $(ROOT)/usr/lib/brand/lx ROOTLIBDIR64 = $(ROOT)/usr/lib/brand/lx/$(MACH64) +# +# The top level Makefiles define define TEXT_DOMAIN. But librtld_db.so.1 +# isn't internationalized and this library won't be either. The only +# messages that this library can generate are messages used for debugging +# the operation of the library itself. +# +DTEXTDOM = + .KEEP_STATE: all: $(LIBS) lint: lintcheck -include ../../../../Makefile.targ +pics/%64.o: ../common/%.c + $(COMPILE.c) -D_ELF64 $(PICFLAGS) -o $@ $< + $(POST_PROCESS_O) + +include $(SRC)/lib/Makefile.targ diff --git a/usr/src/lib/brand/lx/librtld_db/amd64/Makefile b/usr/src/lib/brand/lx/librtld_db/amd64/Makefile index f2cbdd0616..4e32e6e622 100644 --- a/usr/src/lib/brand/lx/librtld_db/amd64/Makefile +++ b/usr/src/lib/brand/lx/librtld_db/amd64/Makefile @@ -18,17 +18,16 @@ # # CDDL HEADER END # + # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # -# lib/brand/lx/librtld_db/amd64/Makefile - -ISASRCDIR=. -ASFLAGS += -P -D_ASM +# This is a 64-bit build, and as such needs 64-bit ELF support +COBJS64 = lx_librtld_db64.o include ../Makefile.com include $(SRC)/lib/Makefile.lib.64 diff --git a/usr/src/lib/brand/lx/librtld_db/amd64/mapfile-vers b/usr/src/lib/brand/lx/librtld_db/amd64/mapfile-vers new file mode 100644 index 0000000000..76415578d6 --- /dev/null +++ b/usr/src/lib/brand/lx/librtld_db/amd64/mapfile-vers @@ -0,0 +1,32 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# + +SUNWprivate_1.1 { + global: + rtld_db_brand_ops64; +}; diff --git a/usr/src/lib/brand/lx/librtld_db/common/lx_librtld_db.c b/usr/src/lib/brand/lx/librtld_db/common/lx_librtld_db.c index 4be5ee9a84..7d17789755 100644 --- a/usr/src/lib/brand/lx/librtld_db/common/lx_librtld_db.c +++ b/usr/src/lib/brand/lx/librtld_db/common/lx_librtld_db.c @@ -35,51 +35,92 @@ #include <proc_service.h> #include <rtld_db.h> #include <synch.h> + #include <sys/lx_brand.h> -static void *lx_ldb_client_init(struct ps_prochandle *); -static int lx_ldb_iter(struct ps_prochandle *, rl_iter_f *, void *, void *); -static void lx_ldb_fix_phdr(struct rd_agent *, Elf32_Dyn *, size_t, - psaddr_t); - -struct rd_agent { - mutex_t rd_mutex; - struct ps_prochandle *rd_psp; /* prochandle pointer */ - psaddr_t rd_rdebug; /* rtld r_debug */ - psaddr_t rd_preinit; /* rtld_db_preinit */ - psaddr_t rd_postinit; /* rtld_db_postinit */ - psaddr_t rd_dlact; /* rtld_db_dlact */ - psaddr_t rd_tbinder; /* tail of binder */ - psaddr_t rd_rtlddbpriv; /* rtld rtld_db_priv */ - ulong_t rd_flags; /* flags */ - ulong_t rd_rdebugvers; /* rtld_db_priv.vers */ - int rd_dmodel; /* data model */ - rd_helper_t rd_helper; /* private to helper */ -}; +/* + * ATTENTION: + * Librtl_db brand plugin libraries should NOT directly invoke any + * libproc.so interfaces or be linked against libproc. If a librtl_db + * brand plugin library uses libproc.so interfaces then it may break + * any other librtld_db consumers (like mdb) that tries to attach + * to a branded process. The only safe interfaces that the a librtld_db + * brand plugin library can use to access a target process are the + * proc_service(3PROC) apis. + */ + +/* + * M_DATA comes from some streams header file but is also redifined in + * _rtld_db.h, so nuke the old streams definition here. + */ +#ifdef M_DATA +#undef M_DATA +#endif /* M_DATA */ + +/* + * For 32-bit versions of this library, this file get's compiled once. + * For 64-bit versions of this library, this file get's compiled twice, + * once with _ELF64 defined and once without. The expectation is that + * the 64-bit version of the library can properly deal with both 32-bit + * and 64-bit elf files, hence in the 64-bit library there are two copies + * of all the interfaces in this file, one set named *32 and one named *64. + * + * This also means that we need to be careful when declaring local pointers + * that point to objects in another processes address space, since these + * pointers may not match the current processes pointer width. Basically, + * we should avoid using data types that change size between 32 and 64 bit + * modes like: long, void *, uintprt_t, caddr_t, psaddr_t, size_t, etc. + * Instead we should declare all pointers as uint32_t. Then when we + * are compiled to deal with 64-bit targets we'll re-define uint32_t + * to be a uint64_t. + * + * Finally, one last importante note. All the 64-bit elf file code + * is never used and can't be tested. This is because we don't actually + * support 64-bit Linux processes yet. The reason that we have it here + * is because we want to support debugging 32-bit elf targets with the + * 64-bit version of this library, so we need to have a 64-bit version + * of this library. But a 64-bit version of this library is expected + * to provide debugging interfaces for both 32 and 64-bit elf targets. + * So we provide the 64-bit elf target interfaces, but they will never + * be invoked and are untested. If we ever add support for 64-bit elf + * Linux processes, we'll need to verify that this code works correctly + * for those targets. + */ +#ifdef _LP64 +#ifdef _ELF64 +#define lx_ldb_get_dyns32 lx_ldb_get_dyns64 +#define lx_ldb_init32 lx_ldb_init64 +#define lx_ldb_fini32 lx_ldb_fini64 +#define lx_ldb_loadobj_iter32 lx_ldb_loadobj_iter64 +#define lx_ldb_getauxval32 lx_ldb_getauxval64 +#define lx_elf_props32 lx_elf_props64 +#define _rd_get_dyns32 _rd_get_dyns64 +#define _rd_get_ehdr32 _rd_get_ehdr64 +#define uint32_t uint64_t +#define Elf32_Dyn Elf64_Dyn +#define Elf32_Ehdr Elf64_Ehdr +#define Elf32_Phdr Elf64_Phdr +#endif /* _ELF64 */ +#endif /* _LP64 */ + +/* Included from usr/src/cmd/sgs/librtld_db/common */ +#include <_rtld_db.h> typedef struct lx_rd { - struct ps_prochandle *lr_php; /* prochandle of target */ - uint32_t lr_rdebug; /* address of lx r_debug */ - uint32_t lr_exec; /* base address of main executable */ + rd_agent_t *lr_rap; + struct ps_prochandle *lr_php; /* proc handle pointer */ + uint32_t lr_rdebug; /* address of lx r_debug */ + uint32_t lr_exec; /* base address of executable */ } lx_rd_t; -rd_helper_ops_t RTLD_DB_BRAND_OPS = { - lx_ldb_client_init, - lx_ldb_iter, - lx_ldb_fix_phdr -}; - -struct lx_link_map -{ +typedef struct lx_link_map { uint32_t lxm_addr; /* Base address shared object is loaded at. */ uint32_t lxm_name; /* Absolute file name object was found in. */ uint32_t lxm_ld; /* Dynamic section of the shared object. */ - uint32_t lxm_next; /* Chain of loaded objects. */ - uint32_t lxm_prev; -}; + uint32_t lxm_next; /* Chain of loaded objects. */ +} lx_link_map_t; -struct lx_r_debug -{ +typedef struct lx_r_debug { int r_version; /* Version number for this protocol. */ uint32_t r_map; /* Head of the chain of loaded objects. */ @@ -93,7 +134,23 @@ struct lx_r_debug uint32_t r_brk; r_state_e r_state; /* defined the same way between lx/solaris */ uint32_t r_ldbase; /* Base address the linker is loaded at. */ -}; +} lx_r_debug_t; + +static uint32_t +lx_ldb_getauxval32(struct ps_prochandle *php, int type) +{ + const auxv_t *auxvp = NULL; + + if (ps_pauxv(php, &auxvp) != PS_OK) + return ((uint32_t)-1); + + while (auxvp->a_type != AT_NULL) { + if (auxvp->a_type == type) + return ((uint32_t)(uintptr_t)auxvp->a_un.a_ptr); + auxvp++; + } + return ((uint32_t)-1); +} /* * A key difference between the linux linker and ours' is that the linux @@ -115,103 +172,111 @@ struct lx_r_debug * DT_NEEDED section. For all matching sections, we subtract the segment * base address to get back to relative addresses. */ -static void -lx_ldb_fix_phdr(struct rd_agent *rap, Elf32_Dyn *dp, size_t size, - psaddr_t addr) +static rd_err_e +lx_ldb_get_dyns32(rd_helper_data_t rhd, + psaddr_t addr, void **dynpp, size_t *dynpp_sz) { - struct ps_prochandle *php = rap->rd_psp; + lx_rd_t *lx_rd = (lx_rd_t *)rhd; + rd_agent_t *rap = lx_rd->lr_rap; + Elf32_Ehdr ehdr; + Elf32_Dyn *dynp = NULL; + size_t dynp_sz; + uint_t ndyns; int i; - int strsz = 0; - uint32_t strtab_p = NULL; - char *strtab; - /* Make sure addr matches the current byte size */ - addr = (uint32_t)addr; + ps_plog("lx_ldb_get_dyns: invoked for object at 0x%p", addr); - /* - * First we need to find the address of the string table. - */ - for (i = 0; i < size / sizeof (Elf32_Dyn); i++) { - if (dp[i].d_tag == DT_STRTAB) - strtab_p = dp[i].d_un.d_ptr; - if (dp[i].d_tag == DT_STRSZ) - strsz = dp[i].d_un.d_val; - } - if (strtab_p == NULL) { - ps_plog("lx_librtld_db: couldn't find strtab"); - return; - } - if (strsz == 0) { - ps_plog("lx_librtld_db: couldn't find strsz"); - return; + /* Read in a copy of the ehdr */ + if (_rd_get_ehdr32(rap, addr, &ehdr, NULL) != RD_OK) { + ps_plog("lx_ldb_get_dyns: _rd_get_ehdr() failed"); + return (RD_ERR); } - if ((strtab = malloc(strsz)) == NULL) - return; - if (Pread(php, strtab, strsz, strtab_p) != strsz) { - ps_plog("lx_librtld_db: couldn't read strtab at 0x%p", - strtab_p); - free(strtab); - return; + /* read out the PT_DYNAMIC elements for this object */ + if (_rd_get_dyns32(rap, addr, &dynp, &dynp_sz) != RD_OK) { + ps_plog("lx_ldb_get_dyns: _rd_get_dyns() failed"); + return (RD_ERR); } /* - * ELF binaries may have more than one DT_NEEDED entry - we must - * check them all. The linux linker segment also needs to be fixed, - * but it doesn't have a DT_NEEDED entry. Instead, look for a - * matching DT_SONAME. + * From here on out if we encounter an error we'll just return + * success and pass back the unmolested dynamic elements that + * we've already obtained. */ - for (i = 0; i < size / sizeof (Elf32_Dyn); i++) { - if (dp[i].d_tag == DT_SONAME && - strncmp(strtab + dp[i].d_un.d_ptr, LX_LINKER_NAME, - sizeof (LX_LINKER_NAME)) == 0) - break; - - if (dp[i].d_tag != DT_NEEDED) - continue; + *dynpp = dynp; + *dynpp_sz = dynp_sz; + ndyns = dynp_sz / sizeof (Elf32_Dyn); + + /* If this isn't a dynamic object, there's nothing left todo */ + if (ehdr.e_type != ET_DYN) { + ps_plog("lx_ldb_get_dyns: done: not a shared object"); + return (RD_OK); + } - if (strncmp(strtab + dp[i].d_un.d_ptr, - LX_LINKER_NAME, sizeof (LX_LINKER_NAME)) == 0 || - strncmp(strtab + dp[i].d_un.d_ptr, LX_LIBC_NAME, - sizeof (LX_LIBC_NAME)) == 0) + /* + * Before we blindly start changing dynamic section addresses + * we need to figure out if the current object that we're looking + * at is a linux object or a solaris object. To do this first + * we need to find the string tab dynamic section element. + */ + for (i = 0; i < ndyns; i++) { + if (dynp[i].d_tag == DT_STRTAB) break; } - free(strtab); - if (i == size / sizeof (Elf32_Dyn)) { - /* - * This is not a linux mapping, so we have nothing left to do. - */ - ps_plog("lx_librtld_db: " - "0x%p doesn't appear to be an lx object", addr); - return; + if (i == ndyns) { + ps_plog("lx_ldb_get_dyns: " + "failed to find string tab in the dynamic section"); + return (RD_OK); } /* - * The linux linker added the segment's base address to a bunch of the - * dynamic section addresses. Fix them back to their original, on-disk - * format so Solaris understands them. + * Check if the strtab value looks like an offset or an address. + * It's an offset if the value is less then the base address that + * the object is loaded at, or if the value is less than the offset + * of the section headers in the same elf object. This check isn't + * perfect, but in practice it's good enough. */ - for (i = 0; i < size / sizeof (Elf32_Dyn); i++) { - switch (dp[i].d_tag) { - case DT_INIT: - case DT_FINI: + if ((dynp[i].d_un.d_ptr < addr) || + (dynp[i].d_un.d_ptr < ehdr.e_shoff)) { + ps_plog("lx_ldb_get_dyns: " + "doesn't appear to be an lx object"); + return (RD_OK); + } + + /* + * This seems to be a a linux object, so we'll patch up the dynamic + * section addresses + */ + ps_plog("lx_ldb_get_dyns: " + "patching up lx object dynamic section addresses"); + for (i = 0; i < ndyns; i++) { + switch (dynp[i].d_tag) { + case DT_PLTGOT: case DT_HASH: case DT_STRTAB: case DT_SYMTAB: + case DT_RELA: + case DT_REL: case DT_DEBUG: - case DT_PLTGOT: case DT_JMPREL: - case DT_REL: - case DT_VERNEED: case DT_VERSYM: - if (dp[i].d_un.d_val > addr) { - dp[i].d_un.d_ptr -= addr; + if (dynp[i].d_un.d_val > addr) { + dynp[i].d_un.d_ptr -= addr; } break; default: break; } } + return (RD_OK); +} + +static void +lx_ldb_fini32(rd_helper_data_t rhd) +{ + lx_rd_t *lx_rd = (lx_rd_t *)rhd; + ps_plog("lx_ldb_fini: cleaning up lx helper"); + free(lx_rd); } /* @@ -224,64 +289,64 @@ lx_ldb_fix_phdr(struct rd_agent *rap, Elf32_Dyn *dp, size_t size, * address of the Elf header, and from there we can easily get to the DT_DEBUG * entry. */ -static void * -lx_ldb_client_init(struct ps_prochandle *php) +static rd_helper_data_t +lx_ldb_init32(rd_agent_t *rap, struct ps_prochandle *php) { - lx_rd_t *rd = calloc(sizeof (lx_rd_t), 1); - uint32_t phdr_addr, ehdr_addr, dp_addr; - Elf32_Dyn *dp; + lx_rd_t *lx_rd; + uint32_t addr, phdr_addr, dyn_addr; + Elf32_Dyn *dyn; Elf32_Phdr phdr, *ph, *phdrs; Elf32_Ehdr ehdr; - int i, dp_count; + int i, dyn_count; - rd->lr_rdebug = 0; - - if (rd == NULL) { - ps_plog("lx_ldb_client_init: cannot allocate memory"); + lx_rd = calloc(sizeof (lx_rd_t), 1); + if (lx_rd == NULL) { + ps_plog("lx_ldb_init: cannot allocate memory"); return (NULL); } + lx_rd->lr_rap = rap; + lx_rd->lr_php = php; - phdr_addr = Pgetauxval(php, AT_SUN_BRAND_LX_PHDR); + phdr_addr = lx_ldb_getauxval32(php, AT_SUN_BRAND_LX_PHDR); if (phdr_addr == (uint32_t)-1) { - ps_plog("lx_ldb_client_init: no LX_PHDR found in aux vector"); + ps_plog("lx_ldb_init: no LX_PHDR found in aux vector"); return (NULL); } - ps_plog("lx_ldb_client_init: found LX_PHDR auxv phdr at: 0x%p", + ps_plog("lx_ldb_init: found LX_PHDR auxv phdr at: 0x%p", phdr_addr); if (ps_pread(php, phdr_addr, &phdr, sizeof (phdr)) != PS_OK) { - ps_plog("lx_ldb_client_init: couldn't read phdr at 0x%p", + ps_plog("lx_ldb_init: couldn't read phdr at 0x%p", phdr_addr); - free(rd); + free(lx_rd); return (NULL); } /* The ELF headher should be before the program header in memory */ - rd->lr_exec = ehdr_addr = phdr_addr - phdr.p_offset; - if (ps_pread(php, ehdr_addr, &ehdr, sizeof (ehdr)) != - PS_OK) { - ps_plog("lx_ldb_client_init: couldn't read ehdr at 0x%p", - rd->lr_exec); - free(rd); + lx_rd->lr_exec = addr = phdr_addr - phdr.p_offset; + if (ps_pread(php, addr, &ehdr, sizeof (ehdr)) != PS_OK) { + ps_plog("lx_ldb_init: couldn't read ehdr at 0x%p", + lx_rd->lr_exec); + free(lx_rd); return (NULL); } - ps_plog("lx_ldb_client_init: read ehdr at: 0x%p", ehdr_addr); + ps_plog("lx_ldb_init: read ehdr at: 0x%p", addr); if ((phdrs = malloc(ehdr.e_phnum * ehdr.e_phentsize)) == NULL) { - ps_plog("lx_ldb_client_init: couldn't alloc phdrs memory"); - free(rd); + ps_plog("lx_ldb_init: couldn't alloc phdrs memory"); + free(lx_rd); return (NULL); } if (ps_pread(php, phdr_addr, phdrs, ehdr.e_phnum * ehdr.e_phentsize) != PS_OK) { - ps_plog("lx_ldb_client_init: couldn't read phdrs at 0x%p", + ps_plog("lx_ldb_init: couldn't read phdrs at 0x%p", phdr_addr); - free(rd); + free(lx_rd); free(phdrs); return (NULL); } - ps_plog("lx_ldb_client_init: read %d phdrs at: 0x%p", + ps_plog("lx_ldb_init: read %d phdrs at: 0x%p", ehdr.e_phnum, phdr_addr); for (i = 0, ph = phdrs; i < ehdr.e_phnum; i++, @@ -291,51 +356,51 @@ lx_ldb_client_init(struct ps_prochandle *php) break; } if (i == ehdr.e_phnum) { - ps_plog("lx_ldb_client_init: no PT_DYNAMIC in executable"); - free(rd); + ps_plog("lx_ldb_init: no PT_DYNAMIC in executable"); + free(lx_rd); free(phdrs); return (NULL); } - ps_plog("lx_ldb_client_init: found PT_DYNAMIC phdr[%d] at: 0x%p", + ps_plog("lx_ldb_init: found PT_DYNAMIC phdr[%d] at: 0x%p", i, (phdr_addr + ((char *)ph - (char *)phdrs))); - if ((dp = malloc(ph->p_filesz)) == NULL) { - ps_plog("lx_ldb_client_init: couldn't alloc for PT_DYNAMIC"); - free(rd); + if ((dyn = malloc(ph->p_filesz)) == NULL) { + ps_plog("lx_ldb_init: couldn't alloc for PT_DYNAMIC"); + free(lx_rd); free(phdrs); return (NULL); } - dp_addr = ehdr_addr + ph->p_offset; - dp_count = ph->p_filesz / sizeof (Elf32_Dyn); - if (ps_pread(php, dp_addr, dp, ph->p_filesz) != PS_OK) { - ps_plog("lx_ldb_client_init: couldn't read dynamic at 0x%p", - dp_addr); - free(rd); + dyn_addr = addr + ph->p_offset; + dyn_count = ph->p_filesz / sizeof (Elf32_Dyn); + if (ps_pread(php, dyn_addr, dyn, ph->p_filesz) != PS_OK) { + ps_plog("lx_ldb_init: couldn't read dynamic at 0x%p", + dyn_addr); + free(lx_rd); free(phdrs); - free(dp); + free(dyn); return (NULL); } - ps_plog("lx_ldb_client_init: read %d dynamic headers at: 0x%p", - dp_count, dp_addr); + ps_plog("lx_ldb_init: read %d dynamic headers at: 0x%p", + dyn_count, dyn_addr); - for (i = 0; i < dp_count; i++) { - if (dp[i].d_tag == DT_DEBUG) { - rd->lr_rdebug = dp[i].d_un.d_ptr; + for (i = 0; i < dyn_count; i++) { + if (dyn[i].d_tag == DT_DEBUG) { + lx_rd->lr_rdebug = dyn[i].d_un.d_ptr; break; } } free(phdrs); - free(dp); + free(dyn); - if (rd->lr_rdebug == 0) { - ps_plog("lx_ldb_client_init: no DT_DEBUG found in exe"); - free(rd); + if (lx_rd->lr_rdebug == 0) { + ps_plog("lx_ldb_init: no DT_DEBUG found in exe"); + free(lx_rd); return (NULL); } - ps_plog("lx_ldb_client_init: found DT_DEBUG: 0x%p", rd->lr_rdebug); + ps_plog("lx_ldb_init: found DT_DEBUG: 0x%p", lx_rd->lr_rdebug); - return (rd); + return ((rd_helper_data_t)lx_rd); } /* @@ -343,7 +408,7 @@ lx_ldb_client_init(struct ps_prochandle *php) * the proper link map ID. */ static size_t -lx_elf_props(struct ps_prochandle *php, uint32_t addr, psaddr_t *data_addr) +lx_elf_props32(struct ps_prochandle *php, uint32_t addr, psaddr_t *data_addr) { Elf32_Ehdr ehdr; Elf32_Phdr *phdrs, *ph; @@ -399,20 +464,20 @@ lx_elf_props(struct ps_prochandle *php, uint32_t addr, psaddr_t *data_addr) } static int -lx_ldb_iter(struct ps_prochandle *php, rl_iter_f *cb, void *client_data, - void *rd_addr) +lx_ldb_loadobj_iter32(rd_helper_data_t rhd, rl_iter_f *cb, void *client_data) { - lx_rd_t *lx_rd = (lx_rd_t *)rd_addr; - struct lx_r_debug r_debug; - struct lx_link_map map; + lx_rd_t *lx_rd = (lx_rd_t *)rhd; + struct ps_prochandle *php = lx_rd->lr_php; + lx_r_debug_t r_debug; + lx_link_map_t map; uint32_t p = NULL; int rc; rd_loadobj_t exec; if ((rc = ps_pread(php, (psaddr_t)lx_rd->lr_rdebug, &r_debug, sizeof (r_debug))) != PS_OK) { - ps_plog("lx_ldb_iter: Couldn't read linux r_debug at 0x%p", - rd_addr); + ps_plog("lx_ldb_loadobj_iter: " + "Couldn't read linux r_debug at 0x%p", lx_rd->lr_rdebug); return (rc); } @@ -427,22 +492,23 @@ lx_ldb_iter(struct ps_prochandle *php, rl_iter_f *cb, void *client_data, * the AT_EXECNAME entry instead. */ if ((rc = ps_pread(php, (psaddr_t)p, &map, sizeof (map))) != PS_OK) { - ps_plog("lx_ldb_iter: Couldn't read linux link map at 0x%p", - p); + ps_plog("lx_ldb_loadobj_iter: " + "Couldn't read linux link map at 0x%p", p); return (rc); } bzero(&exec, sizeof (exec)); exec.rl_base = lx_rd->lr_exec; exec.rl_dynamic = map.lxm_ld; - exec.rl_nameaddr = Pgetauxval(php, AT_SUN_EXECNAME); + exec.rl_nameaddr = lx_ldb_getauxval32(php, AT_SUN_EXECNAME); exec.rl_lmident = LM_ID_BASE; exec.rl_bend = exec.rl_base + - lx_elf_props(php, lx_rd->lr_exec, &exec.rl_data_base); + lx_elf_props32(php, lx_rd->lr_exec, &exec.rl_data_base); if ((*cb)(&exec, client_data) == 0) { - ps_plog("lx_ldb_iter: client callb failed for executable"); + ps_plog("lx_ldb_loadobj_iter: " + "client callb failed for executable"); return (PS_ERR); } @@ -451,8 +517,8 @@ lx_ldb_iter(struct ps_prochandle *php, rl_iter_f *cb, void *client_data, if ((rc = ps_pread(php, (psaddr_t)p, &map, sizeof (map))) != PS_OK) { - ps_plog("lx_ldb_iter: Couldn't read lk map at %p", - p); + ps_plog("lx_ldb_loadobj_iter: " + "Couldn't read lk map at %p", p); return (rc); } @@ -476,20 +542,34 @@ lx_ldb_iter(struct ps_prochandle *php, rl_iter_f *cb, void *client_data, */ obj.rl_bend = map.lxm_addr + - lx_elf_props(php, map.lxm_addr, &obj.rl_data_base); + lx_elf_props32(php, map.lxm_addr, &obj.rl_data_base); obj.rl_padstart = obj.rl_base; obj.rl_padend = obj.rl_bend; obj.rl_dynamic = map.lxm_ld; obj.rl_tlsmodid = 0; - ps_plog("lx_ldb_iter: 0x%p to 0x%p", + ps_plog("lx_ldb_loadobj_iter: 0x%p to 0x%p", obj.rl_base, obj.rl_bend); if ((*cb)(&obj, client_data) == 0) { - ps_plog("lx_ldb_iter: Client callback failed on %s", - map.lxm_name); + ps_plog("lx_ldb_loadobj_iter: " + "Client callback failed on %s", map.lxm_name); return (rc); } } return (RD_OK); } + +/* + * Librtld_db plugin linkage struct. + * + * When we get loaded by librtld_db, it will look for the symbol below + * to find our plugin entry points. + */ +rd_helper_ops_t RTLD_DB_BRAND_OPS = { + LM_ID_BRAND, + lx_ldb_init32, + lx_ldb_fini32, + lx_ldb_loadobj_iter32, + lx_ldb_get_dyns32 +}; diff --git a/usr/src/lib/brand/lx/librtld_db/common/mapfile-vers b/usr/src/lib/brand/lx/librtld_db/common/mapfile-vers index e3c40016b3..e460725681 100644 --- a/usr/src/lib/brand/lx/librtld_db/common/mapfile-vers +++ b/usr/src/lib/brand/lx/librtld_db/common/mapfile-vers @@ -20,14 +20,27 @@ # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" +# { global: - rtld_db_brand_ops; + rtld_db_brand_ops32; local: *; }; + +#Externally defined symbols +{ + global: + ps_pauxv = NODIRECT PARENT; + ps_pdmodel = NODIRECT PARENT; + ps_pglobal_lookup = NODIRECT PARENT; + ps_pglobal_sym = NODIRECT PARENT; + ps_plog = NODIRECT PARENT; + ps_pread = NODIRECT PARENT; + ps_pwrite = NODIRECT PARENT; +}; diff --git a/usr/src/lib/brand/lx/librtld_db/i386/Makefile b/usr/src/lib/brand/lx/librtld_db/i386/Makefile index e85d3fc08a..b5f780c072 100644 --- a/usr/src/lib/brand/lx/librtld_db/i386/Makefile +++ b/usr/src/lib/brand/lx/librtld_db/i386/Makefile @@ -18,17 +18,13 @@ # # CDDL HEADER END # + # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" +#ident "%Z%%M% %I% %E% SMI" # -# lib/brand/lx/librtld_db/i386/Makefile - -ISASRCDIR=. - -ASFLAGS += -P -D_ASM include ../Makefile.com diff --git a/usr/src/lib/libproc/common/Psymtab_machelf32.c b/usr/src/lib/libproc/common/Psymtab_machelf32.c index dc6ba18a59..704e41547c 100644 --- a/usr/src/lib/libproc/common/Psymtab_machelf32.c +++ b/usr/src/lib/libproc/common/Psymtab_machelf32.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -255,25 +255,19 @@ fake_elf32(struct ps_prochandle *P, file_info_t *fptr, uintptr_t addr, Off off; size_t pltsz = 0, pltentsz; - if (ehdr->e_type == ET_DYN) phdr->p_vaddr += addr; - if ((dp = malloc(phdr->p_filesz)) == NULL) - goto bad; - - if (Pread(P, dp, phdr->p_filesz, phdr->p_vaddr) != phdr->p_filesz) - goto bad; - -#ifndef _ELF64 - /* - * Allow librtld_db the opportunity to "fix" the program - * headers, if it needs to, before we process them. - */ - if (P->rap != NULL && ehdr->e_type == ET_DYN) { - rd_fix_phdrs(P->rap, dp, phdr->p_filesz, addr); + if (P->rap != NULL) { + if (rd_get_dyns(P->rap, addr, (void **)&dp, NULL) != RD_OK) + goto bad; + } else { + if ((dp = malloc(phdr->p_filesz)) == NULL) + goto bad; + if (Pread(P, dp, phdr->p_filesz, phdr->p_vaddr) != + phdr->p_filesz) + goto bad; } -#endif /* * Iterate over the items in the dynamic section, grabbing |