From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 30209 invoked by alias); 9 Aug 2011 09:07:11 -0000 Received: (qmail 30198 invoked by uid 22791); 9 Aug 2011 09:07:09 -0000 X-SWARE-Spam-Status: No, hits=-6.8 required=5.0 tests=AWL,BAYES_00,RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,SPF_HELO_PASS,TW_XS X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 09 Aug 2011 09:06:52 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p7996p63028546 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Tue, 9 Aug 2011 05:06:52 -0400 Received: from host1.jankratochvil.net (ovpn-116-17.ams2.redhat.com [10.36.116.17]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p7996nHS022043 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Tue, 9 Aug 2011 05:06:51 -0400 Received: from host1.jankratochvil.net (localhost [127.0.0.1]) by host1.jankratochvil.net (8.14.4/8.14.4) with ESMTP id p7996nBX029700; Tue, 9 Aug 2011 11:06:49 +0200 Received: (from jkratoch@localhost) by host1.jankratochvil.net (8.14.4/8.14.4/Submit) id p7996mh5029699; Tue, 9 Aug 2011 11:06:48 +0200 Date: Tue, 09 Aug 2011 09:07:00 -0000 From: Jan Kratochvil To: Paul Pluzhnikov Cc: gdb-patches@sourceware.org Subject: Re: [patch] Implement qXfer:libraries for Linux/gdbserver Message-ID: <20110809090647.GA21388@host1.jankratochvil.net> References: <20110808210938.GA19337@host1.jankratochvil.net> <20110808213800.GA21915@host1.jankratochvil.net> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.21 (2010-09-15) X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2011-08/txt/msg00172.txt.bz2 On Tue, 09 Aug 2011 01:49:49 +0200, Paul Pluzhnikov wrote: > --- gdbserver/linux-low.c 21 Jul 2011 23:46:12 -0000 1.173 > +++ gdbserver/linux-low.c 8 Aug 2011 23:34:10 -0000 > @@ -4755,6 +4755,289 @@ linux_emit_ops (void) [...] > +static CORE_ADDR > +get_dynamic (const int pid, const int is_elf64) > +{ > + CORE_ADDR phdr_memaddr; > + int num_phdr, i; > + unsigned char *phdr_buf; > + const int phdr_size = is_elf64 ? sizeof (Elf64_Phdr) : sizeof (Elf32_Phdr); > + > + Two empty lines, should be one. > + if (get_phdr_phnum_from_proc_auxv (pid, is_elf64, &phdr_memaddr, &num_phdr)) > + return 0; > + > + gdb_assert (num_phdr < 100); /* Basic sanity check. */ > + phdr_buf = alloca (num_phdr * phdr_size); > + > + if (linux_read_memory (phdr_memaddr, phdr_buf, num_phdr * phdr_size)) > + return 0; > + > + for (i = 0; i < num_phdr; i++) > + { > + if (is_elf64) > + { > + Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size); > + > + if (p->p_type == PT_DYNAMIC) > + return p->p_vaddr; This does not work for -fPIE -pie executables such as those on Chromebook. One needs to relocate A_VAL as it is the in-file (0-based) address while in-memory address is shifted by X. X is calculated by solib-svr4.c svr4_exec_displacement. One can find here X probably most easily by subtracting PT_PHDR->P_VADDR from PHDR_MEMADDR. There is also a bug in it in solib-svr4.c scan_dyntag_auxv [rfc] Use auxillary vector to retrieve .dynamic/.interp sections http://sourceware.org/ml/gdb-patches/2008-08/msg00360.html but one would need to patch the code around to get the fix applicable first. > + } > + else > + { > + Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size); > + > + if (p->p_type == PT_DYNAMIC) > + return p->p_vaddr; Here too. > + } > + } > + > + return 0; > +} > + > +/* Return &_r_debug in the inferior, or -1 if not present. Return value > + can be 0 if the inferior does not yet have the library list initialized. */ > + > +static CORE_ADDR > +get_r_debug (const int pid, const int is_elf64) > +{ > + CORE_ADDR dynamic_memaddr; > + const int dyn_size = is_elf64 ? sizeof (Elf64_Dyn) : sizeof (Elf32_Dyn); > + unsigned char buf[sizeof (Elf64_Dyn)]; /* The larger of the two. */ > + > + dynamic_memaddr = get_dynamic (pid, is_elf64); > + if (dynamic_memaddr == 0) > + return (CORE_ADDR) -1; > + > + while (linux_read_memory (dynamic_memaddr, buf, dyn_size) == 0) > + { > + if (is_elf64) > + { > + Elf64_Dyn *const dyn = (Elf64_Dyn *) buf; > + > + if (dyn->d_tag == DT_DEBUG) > + return dyn->d_un.d_val; > + > + if (dyn->d_tag == DT_NULL) > + break; > + } > + else > + { > + Elf32_Dyn *const dyn = (Elf32_Dyn *) buf; > + > + if (dyn->d_tag == DT_DEBUG) > + return dyn->d_un.d_val; > + > + if (dyn->d_tag == DT_NULL) > + break; > + } > + > + dynamic_memaddr += dyn_size; > + } > + > + return (CORE_ADDR) -1; > +} > + > +/* Read one pointer from MEMADDR in the inferior. */ > + > +static int > +read_one_ptr (CORE_ADDR memaddr, CORE_ADDR *ptr, int ptr_size) > +{ > + *ptr = 0; > + return linux_read_memory (memaddr, (unsigned char *) ptr, ptr_size); > +} > + > + Two empty lines, should be one. > +struct link_map_offsets > + { > + /* Offset and size of r_debug.r_version. */ > + int r_version_offset; > + > + /* Offset and size of r_debug.r_map. */ > + int r_map_offset; > + > + /* Offset to l_addr field in struct link_map. */ > + int l_addr_offset; > + > + /* Offset to l_name field in struct link_map. */ > + int l_name_offset; > + > + /* Offset to l_next field in struct link_map. */ > + int l_next_offset; > + > + /* Offset to l_prev field in struct link_map. */ > + int l_prev_offset; > + Excessive empty line. > + }; > + > +/* Clear and refresh ALL_DLLS list. */ > + > +static void > +linux_refresh_libraries (void) > +{ > + struct process_info_private *const priv = current_process ()->private; > + char filename[PATH_MAX]; > + int pid, is_elf64, ptr_size, r_version; > + CORE_ADDR lm_addr, lm_prev, l_name, l_addr, l_next, l_prev; > + > + static const struct link_map_offsets lmo_32bit_offsets = > + { > + 0, /* r_version offset. */ > + 4, /* r_debug.r_map offset. */ > + 0, /* l_addr offset in link_map. */ > + 4, /* l_name offset in link_map. */ > + 12, /* l_next offset in link_map. */ > + 16 /* l_prev offset in link_map. */ > + }; > + > + static const struct link_map_offsets lmo_64bit_offsets = > + { > + 0, /* r_version offset. */ > + 8, /* r_debug.r_map offset. */ > + 0, /* l_addr offset in link_map. */ > + 8, /* l_name offset in link_map. */ > + 24, /* l_next offset in link_map. */ > + 32 /* l_prev offset in link_map. */ > + }; > + const struct link_map_offsets *lmo; > + > + pid = lwpid_of (get_thread_lwp (current_inferior)); > + xsnprintf (filename, sizeof filename, "/proc/%d/exe", pid); > + is_elf64 = elf_64_file_p (filename); > + lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets; > + ptr_size = is_elf64 ? 8 : 4; > + > + if (priv->r_debug == 0) > + priv->r_debug = get_r_debug (pid, is_elf64); > + > + if (priv->r_debug == (CORE_ADDR) -1 || priv->r_debug == 0) > + return; > + > + r_version = 0; > + if (linux_read_memory (priv->r_debug + lmo->r_version_offset, > + (unsigned char *) &r_version, > + sizeof (r_version)) != 0 > + || r_version != 1) > + { > + warning ("unexpected r_debug version %d", r_version); > + return; > + } > + > + if (read_one_ptr (priv->r_debug + lmo->r_map_offset, > + &lm_addr, ptr_size) != 0) > + { > + warning ("unable to read r_map from 0x%lx", > + (long) priv->r_debug + lmo->r_map_offset); > + return; > + } > + > + clear_all_dlls (); > + > + lm_prev = 0; > + while (read_one_ptr (lm_addr + lmo->l_name_offset, > + &l_name, ptr_size) == 0 > + && read_one_ptr (lm_addr + lmo->l_addr_offset, > + &l_addr, ptr_size) == 0 > + && read_one_ptr (lm_addr + lmo->l_prev_offset, > + &l_prev, ptr_size) == 0 > + && read_one_ptr (lm_addr + lmo->l_next_offset, > + &l_next, ptr_size) == 0) > + { > + unsigned char libname[PATH_MAX]; > + > + if (lm_prev != l_prev) > + { > + warning ("corrupt solib chain: 0x%lx != 0x%lx", > + (long) lm_prev, (long) l_prev); > + break; > + } > + > + /* Not checking for error because reading may stop before > + we've got PATH_MAX worth of characters. */ > + libname[0] = '\0'; > + linux_read_memory (l_name, libname, sizeof (libname)); > + if (libname[0] != '\0') > + loaded_dll ((const char *) libname, l_addr); Unprotected against inferior string longer than PATH_MAX, this is a regression against solib-svr4.c. > + > + if (l_next == 0) > + break; > + > + lm_prev = lm_addr; > + lm_addr = l_next; > + } > + > + /* The library notification response is not expected for GNU/Linux. */ > + dlls_changed = 0; > +} > + > + > static struct target_ops linux_target_ops = { > linux_create_inferior, > linux_attach, > @@ -4813,7 +5096,8 @@ static struct target_ops linux_target_op > linux_cancel_breakpoints, > linux_stabilize_threads, > linux_install_fast_tracepoint_jump_pad, > - linux_emit_ops > + linux_emit_ops, > + linux_refresh_libraries > }; > > static void > Index: gdbserver/linux-low.h > =================================================================== > RCS file: /cvs/src/src/gdb/gdbserver/linux-low.h,v > retrieving revision 1.47 > diff -u -p -r1.47 linux-low.h > --- gdbserver/linux-low.h 1 Jan 2011 15:33:24 -0000 1.47 > +++ gdbserver/linux-low.h 8 Aug 2011 23:34:10 -0000 > @@ -56,6 +56,9 @@ struct process_info_private > /* libthread_db-specific additions. Not NULL if this process has loaded > thread_db, and it is active. */ > struct thread_db *thread_db; > + > + /* &_r_debug. -1 if not yet determined. 0 if no PT_DYNAMIC in Phdrs. */ + /* &_r_debug. 0 if not yet determined. -1 if no PT_DYNAMIC in Phdrs. */ My mistake. > + CORE_ADDR r_debug; > }; > > struct lwp_info; But I still believe the GDB part should be more unified, I will try it. Thanks, Jan