From owner-freebsd-sparc Fri Jan 3 7:10:11 2003 Delivered-To: freebsd-sparc@hub.freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 7A49C37B401 for ; Fri, 3 Jan 2003 07:10:02 -0800 (PST) Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id 6185143ED8 for ; Fri, 3 Jan 2003 07:10:01 -0800 (PST) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.12.6/8.12.6) with ESMTP id h03FA1NS020981 for ; Fri, 3 Jan 2003 07:10:01 -0800 (PST) (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.12.6/8.12.6/Submit) id h03FA1Rp020980; Fri, 3 Jan 2003 07:10:01 -0800 (PST) Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id EBB2337B401 for ; Fri, 3 Jan 2003 07:09:39 -0800 (PST) Received: from mailhub.fokus.gmd.de (mailhub.fokus.gmd.de [193.174.154.14]) by mx1.FreeBSD.org (Postfix) with ESMTP id CC2A643EC5 for ; Fri, 3 Jan 2003 07:09:38 -0800 (PST) (envelope-from hbb@catssrv.fokus.gmd.de) Received: from catssrv.fokus.gmd.de (catssrv [192.168.229.23]) by mailhub.fokus.gmd.de (8.11.6/8.11.6) with ESMTP id h03F9bJ13266 for ; Fri, 3 Jan 2003 16:09:37 +0100 (MET) Received: from catssrv.fokus.gmd.de (localhost [127.0.0.1]) by catssrv.fokus.gmd.de (8.12.6/8.12.6) with ESMTP id h03F9bx5003758 for ; Fri, 3 Jan 2003 16:09:37 +0100 (CET) (envelope-from hbb@catssrv.fokus.gmd.de) Received: (from hbb@localhost) by catssrv.fokus.gmd.de (8.12.6/8.12.6/Submit) id h03F9bmD003757; Fri, 3 Jan 2003 16:09:37 +0100 (CET) (envelope-from hbb) Message-Id: <200301031509.h03F9bmD003757@catssrv.fokus.gmd.de> Date: Fri, 3 Jan 2003 16:09:37 +0100 (CET) From: Hartmut Brandt Reply-To: Hartmut Brandt To: FreeBSD-gnats-submit@FreeBSD.org X-Send-Pr-Version: 3.113 Subject: sparc64/46730: kldxref does not work Sender: owner-freebsd-sparc@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.org >Number: 46730 >Category: sparc64 >Synopsis: kldxref does not work >Confidential: no >Severity: serious >Priority: high >Responsible: freebsd-sparc >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Fri Jan 03 07:10:00 PST 2003 >Closed-Date: >Last-Modified: >Originator: Hartmut Brandt >Release: FreeBSD 5.0-CURRENT sparc64 >Organization: FhI Fokus >Environment: System: FreeBSD catssrv.fokus.gmd.de 5.0-CURRENT FreeBSD 5.0-CURRENT #20: Fri Jan 3 14:08:11 CET 2003 hbb@catssrv.fokus.gmd.de:/opt/obj/usr/src/sys/CATSSRV sparc64 >Description: kldxref fails to correctly read most kld files. The reason for this is that kldxref assumes, that the ELF file containes only REL relocation records and that only RELATIVE relocations need to be performed to read the module meta data. If these two assumptions are true, effectively no relocation has to be performed, because the module's load address is 0 in kldxref's case. For sparc64 the first assumptions is certainly false, because sparc64 uses only RELA relocation records. Because of the missing relocation in this case, the code tries to access 0 offsets in the file. >How-To-Repeat: Execute kldxref /boot/kernel and watch the error messages. >Fix: The following patch fixes the problem in the following way: 1. It reads the REL and RELA relocation records. 2. At the places where pointers are accessed in the object file two additional routines are called that look whether relocation records exist for the object file part that is to be red. If there are it applies the relocations. The patch currently handles REL records of type R_I386_RELATIVE and RELA records of type R_SPARC_RELATIVE. Alle other combinations result in a warning message. This means that alpha and ia64 user will probably see warning messages. This can be overcome by either adding the corresponding alpha and ia64 relocation types (R_ALPHA_RELATIVE and R_IA64_REL64LSB (I suppose)) or removing the warning message itself. The entire handling of REL records could be removed, because it effectively is a NOP a.t.m. I suggest leaving it, because if in the future other relocation types refer to the file offsets in question, we will get a warning message. Index: ef.c =================================================================== RCS file: /usr/ncvs/src/usr.sbin/kldxref/ef.c,v retrieving revision 1.5 diff -c -r1.5 ef.c *** ef.c 17 Jul 2002 23:41:58 -0000 1.5 --- ef.c 3 Jan 2003 14:56:09 -0000 *************** *** 151,157 **** --- 151,166 ---- Elf_Hashelt hashhdr[2]; /* int plttype = DT_REL;*/ int error; + Elf_Off rel_off; + Elf_Off rela_off; + int rel_sz; + int rela_sz; + int rel_entry; + int rela_entry; + rel_off = rela_off = 0; + rel_sz = rela_sz = 0; + rel_entry = rela_entry = 0; for (dp = ef->ef_dyn; dp->d_tag != DT_NULL; dp++) { switch (dp->d_tag) { case DT_HASH: *************** *** 187,192 **** --- 196,231 ---- if (dp->d_un.d_val != sizeof(Elf_Sym)) return EFTYPE; break; + case DT_REL: + if (rel_off != 0) + warnx("second DT_REL entry ignored"); + rel_off = dp->d_un.d_ptr; + break; + case DT_RELSZ: + if (rel_sz != 0) + warnx("second DT_RELSZ entry ignored"); + rel_sz = dp->d_un.d_val; + break; + case DT_RELENT: + if (rel_entry != 0) + warnx("second DT_RELENT entry ignored"); + rel_entry = dp->d_un.d_val; + break; + case DT_RELA: + if (rela_off != 0) + warnx("second DT_RELA entry ignored"); + rela_off = dp->d_un.d_ptr; + break; + case DT_RELASZ: + if (rela_sz != 0) + warnx("second DT_RELASZ entry ignored"); + rela_sz = dp->d_un.d_val; + break; + case DT_RELAENT: + if (rela_entry != 0) + warnx("second DT_RELAENT entry ignored"); + rela_entry = dp->d_un.d_val; + break; } } if (ef->ef_symoff == 0) { *************** *** 210,218 **** --- 249,360 ---- warnx("can't load .dynstr section"); return EIO; } + if (rel_off != 0) { + if (rel_entry == 0) { + warnx("%s: no DT_RELENT for DT_REL", ef->ef_name); + return (EFTYPE); + } + if (rel_entry != sizeof(Elf_Rel)) { + warnx("%s: inconsistent DT_RELENT value", + ef->ef_name); + return (EFTYPE); + } + if (rel_sz % rel_entry != 0) { + warnx("%s: inconsistent values for DT_RELSZ and " + "DT_RELENT", ef->ef_name); + return (EFTYPE); + } + if (ef_read_entry(ef, ef_get_offset(ef, rel_off), rel_sz, + (void **)&ef->ef_rel) != 0) { + warnx("%s: cannot load DT_REL section", ef->ef_name); + return (EIO); + } + ef->ef_relsz = rel_sz / rel_entry; + if (ef->ef_verbose) + warnx("%s: %d REL entries", ef->ef_name, + ef->ef_relsz); + } + if (rela_off != 0) { + if (rela_entry == 0) { + warnx("%s: no DT_RELAENT for DT_RELA", ef->ef_name); + return (EFTYPE); + } + if (rela_entry != sizeof(Elf_Rela)) { + warnx("%s: inconsistent DT_RELAENT value", + ef->ef_name); + return (EFTYPE); + } + if (rela_sz % rela_entry != 0) { + warnx("%s: inconsistent values for DT_RELASZ and " + "DT_RELAENT", ef->ef_name); + return (EFTYPE); + } + if (ef_read_entry(ef, ef_get_offset(ef, rela_off), rela_sz, + (void **)&ef->ef_rela) != 0) { + warnx("%s: cannot load DT_RELA section", ef->ef_name); + return (EIO); + } + ef->ef_relasz = rela_sz / rela_entry; + if (ef->ef_verbose) + warnx("%s: %d RELA entries", ef->ef_name, + ef->ef_relasz); + } return 0; } + /* + * Apply relocations to the values we got from the file. + */ + static int + ef_reloc(elf_file_t ef, Elf_Off offset, size_t len, void *dest) + { + const Elf_Rel *r; + const Elf_Rela *a; + #ifdef R_SPARC_RELATIVE + Elf_Word w; + #endif + + for (r = ef->ef_rel; r < &ef->ef_rel[ef->ef_relsz]; r++) { + if (r->r_offset >= offset && r->r_offset < offset + len) { + switch (ELF_R_TYPE(r->r_info)) { + + #ifdef R_386_RELATIVE + case R_386_RELATIVE: + /* load address is 0 - nothing to do */ + break; + #endif + + default: + warnx("unhandled relocation type %u", + ELF_R_TYPE(r->r_info)); + break; + } + } + } + + for (a = ef->ef_rela; a < &ef->ef_rela[ef->ef_relasz]; a++) { + if (a->r_offset >= offset && a->r_offset < offset + len) { + switch (ELF_R_TYPE(a->r_info)) { + + #ifdef R_SPARC_RELATIVE + case R_SPARC_RELATIVE: + /* load address is 0 */ + w = a->r_addend; + memcpy((u_char *)dest + (a->r_offset - offset), + &w, sizeof(w)); + break; + #endif + + default: + warnx("unhandled relocation type %u", + ELF_R_TYPE(a->r_info)); + break; + } + } + } + return (0); + } + int ef_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest) { *************** *** 259,264 **** --- 401,423 ---- } int + ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void*dest) + { + u_long ofs = ef_get_offset(ef, offset); + int error; + + if (ofs == 0) { + if (ef->ef_verbose) + warnx("ef_seg_read(%s): zero offset (%lx:%ld)", + ef->ef_name, (long)offset, ofs); + return EFAULT; + } + if ((error = ef_read(ef, ofs, len, dest)) != 0) + return (error); + return (ef_reloc(ef, offset, len, dest)); + } + + int ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr) { int error; *************** *** 267,272 **** --- 426,445 ---- if (*ptr == NULL) return ENOMEM; error = ef_seg_read(ef, offset, len, *ptr); + if (error) + free(*ptr); + return error; + } + + int + ef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, void**ptr) + { + int error; + + *ptr = malloc(len); + if (*ptr == NULL) + return ENOMEM; + error = ef_seg_read_rel(ef, offset, len, *ptr); if (error) free(*ptr); return error; Index: ef.h =================================================================== RCS file: /usr/ncvs/src/usr.sbin/kldxref/ef.h,v retrieving revision 1.2 diff -c -r1.2 ef.h *** ef.h 11 Apr 2002 09:30:15 -0000 1.2 --- ef.h 3 Jan 2003 14:56:09 -0000 *************** *** 28,33 **** --- 28,37 ---- int ef_nsegs; Elf_Phdr * ef_segs[2]; int ef_verbose; + Elf_Rel * ef_rel; /* relocation table */ + int ef_relsz; /* number of entries */ + Elf_Rela * ef_rela; /* relocation table */ + int ef_relasz; /* number of entries */ } *elf_file_t; __BEGIN_DECLS *************** *** 36,42 **** --- 40,48 ---- int ef_read(elf_file_t ef, Elf_Off offset, size_t len, void* dest); int ef_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr); int ef_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest); + int ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void *dest); int ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr); + int ef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, void**ptr); int ef_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym); __END_DECLS Index: kldxref.c =================================================================== RCS file: /usr/ncvs/src/usr.sbin/kldxref/kldxref.c,v retrieving revision 1.4 diff -c -r1.4 kldxref.c *** kldxref.c 22 Apr 2002 13:44:44 -0000 1.4 --- kldxref.c 3 Jan 2003 14:56:09 -0000 *************** *** 229,238 **** check(ef_lookup_symbol(&ef, "__stop_set_" MDT_SETNAME, &sym)); finish = sym->st_value; entries = (finish - start) / sizeof(void *); ! check(ef_seg_read_entry(&ef, start, sizeof(*p) * entries, (void**)&p)); orgp = p; while(entries--) { ! check(ef_seg_read(&ef, (Elf_Off)*p, sizeof(md), &md)); p++; check(ef_seg_read(&ef, (Elf_Off)md.md_cval, sizeof(cval), cval)); cval[MAXMODNAME] = '\0'; --- 229,239 ---- check(ef_lookup_symbol(&ef, "__stop_set_" MDT_SETNAME, &sym)); finish = sym->st_value; entries = (finish - start) / sizeof(void *); ! check(ef_seg_read_entry_rel(&ef, start, sizeof(*p) * entries, ! (void**)&p)); orgp = p; while(entries--) { ! check(ef_seg_read_rel(&ef, (Elf_Off)*p, sizeof(md), &md)); p++; check(ef_seg_read(&ef, (Elf_Off)md.md_cval, sizeof(cval), cval)); cval[MAXMODNAME] = '\0'; >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-sparc" in the body of the message