From patchwork Wed Mar 19 22:31:07 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kratochvil X-Patchwork-Id: 177 Return-Path: X-Original-To: siddhesh@wilcox.dreamhost.com Delivered-To: siddhesh@wilcox.dreamhost.com Received: from homiemail-mx20.g.dreamhost.com (caibbdcaaahc.dreamhost.com [208.113.200.72]) by wilcox.dreamhost.com (Postfix) with ESMTP id AFBAA36010F for ; Wed, 19 Mar 2014 15:31:32 -0700 (PDT) Received: by homiemail-mx20.g.dreamhost.com (Postfix, from userid 14314964) id 63ACD40E2F910; Wed, 19 Mar 2014 15:31:32 -0700 (PDT) X-Original-To: gdb@patchwork.siddhesh.in Delivered-To: x14314964@homiemail-mx20.g.dreamhost.com Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by homiemail-mx20.g.dreamhost.com (Postfix) with ESMTPS id 3F451408B4202 for ; Wed, 19 Mar 2014 15:31:32 -0700 (PDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:subject:from:to:cc:date:message-id:in-reply-to :references:mime-version:content-type:content-transfer-encoding; q=dns; s=default; b=JXseNbLBpznEi05yH3NEQAVS/6DMADzwZdO+ef+NIwR 0Swp2wLYzbklGablJP7w8kY9rfvkBdrzzY6nl7A2oUdagIAyJRVDsiwuJPLO8rcv DLwzr7V8FNxPP0VyjT2y4eDDVY2ooMuTRql58MGM+zR8Eer7cEy6bC1867MmP6bA = DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:subject:from:to:cc:date:message-id:in-reply-to :references:mime-version:content-type:content-transfer-encoding; s=default; bh=tOn9Obcq4bPR3X5qFlcMqKuUghY=; b=OZLAzMhksYNVQeKzn S1aSBiDt72iq4aNw+qX7TKl7ZKTyqTJR1yq3clhC9madheMW3JetbZjYr94mmf3l v/Ryuffl8M6KDjC49lJhBXeDGW9GIlVpWQpTl7NlyFoGqG20WRYrPxltv0TicAk9 yJuxEjQIsBxlly+gKMMly8aHaU= Received: (qmail 19388 invoked by alias); 19 Mar 2014 22:31:19 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 19253 invoked by uid 89); 19 Mar 2014 22:31:18 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-4.1 required=5.0 tests=AWL, BAYES_00, SPF_HELO_PASS, SPF_PASS, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 19 Mar 2014 22:31:14 +0000 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s2JMVA6l016508 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 19 Mar 2014 18:31:10 -0400 Received: from host1.jankratochvil.net (ovpn-116-22.ams2.redhat.com [10.36.116.22]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id s2JMV7Fx019985; Wed, 19 Mar 2014 18:31:08 -0400 Subject: [PATCH v5 5/8] Move linux_find_memory_regions_full & co. From: Jan Kratochvil To: gdb-patches@sourceware.org Cc: Aleksandar Ristovski Date: Wed, 19 Mar 2014 23:31:07 +0100 Message-ID: <20140319223107.14668.6979.stgit@host1.jankratochvil.net> In-Reply-To: <20140319223004.14668.20989.stgit@host1.jankratochvil.net> References: <20140319223004.14668.20989.stgit@host1.jankratochvil.net> User-Agent: StGit/0.17-dirty MIME-Version: 1.0 X-IsSubscribed: yes X-DH-Original-To: gdb@patchwork.siddhesh.in Hi, this should be just a move with no changes. Jan gdb/ 2014-02-26 Aleksandar Ristovski +#include #else #include "defs.h" +#include "target.h" #endif #include "linux-maps.h" +#include "gdb_assert.h" +#include +#include +#include "target-utils.h" + +/* Service function for corefiles and info proc. */ + +void +read_mapping (const char *line, + ULONGEST *addr, ULONGEST *endaddr, + const char **permissions, size_t *permissions_len, + ULONGEST *offset, + const char **device, size_t *device_len, + ULONGEST *inode, + const char **filename) +{ + const char *p = line; + + *addr = strtoulst (p, &p, 16); + if (*p == '-') + p++; + *endaddr = strtoulst (p, &p, 16); + + p = skip_spaces_const (p); + *permissions = p; + while (*p && !isspace (*p)) + p++; + *permissions_len = p - *permissions; + + *offset = strtoulst (p, &p, 16); + + p = skip_spaces_const (p); + *device = p; + while (*p && !isspace (*p)) + p++; + *device_len = p - *device; + + *inode = strtoulst (p, &p, 10); + + p = skip_spaces_const (p); + *filename = p; +} + +#ifdef GDBSERVER + +static int +linux_find_memory_read_stralloc_1_pread (int handle, gdb_byte *read_buf, + int len, ULONGEST offset, + int *target_errno) +{ + int retval = pread (handle, read_buf, len, offset); + + *target_errno = errno; + return retval; +} + +static LONGEST +linux_find_memory_read_stralloc_1 (const char *filename, gdb_byte **buf_p, + int padding) +{ + int fd; + LONGEST retval; + + fd = open (filename, O_RDONLY); + if (fd == -1) + return -1; + + retval = read_alloc (buf_p, fd, linux_find_memory_read_stralloc_1_pread, + padding, NULL); + + close (fd); + + return retval; +} + +#endif /* GDBSERVER */ + +static char * +linux_find_memory_read_stralloc (const char *filename) +{ +#ifndef GDBSERVER + return target_fileio_read_stralloc (filename); +#else /* GDBSERVER */ + return read_stralloc (filename, linux_find_memory_read_stralloc_1); +#endif /* GDBSERVER */ +} + +/* List memory regions in the inferior PID for a corefile. Call FUNC + with FUNC_DATA for each such region. Return immediately with the + value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should + be registered to be freed automatically if called FUNC throws an + exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is + not used. Return -1 if error occurs, 0 if all memory regions have + been processed or return the value from FUNC if FUNC returns + non-zero. */ + +int +linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func, + void *func_data, void **memory_to_free_ptr) +{ + char mapsfilename[100]; + char *data; + + xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", (int) pid); + data = linux_find_memory_read_stralloc (mapsfilename); + if (data == NULL) + { + /* Older Linux kernels did not support /proc/PID/smaps. */ + xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/maps", (int) pid); + data = linux_find_memory_read_stralloc (mapsfilename); + } + if (data) + { + char *line; + int retval = 0; + + if (memory_to_free_ptr != NULL) + { + gdb_assert (*memory_to_free_ptr == NULL); + *memory_to_free_ptr = data; + } + + line = strtok (data, "\n"); + while (line) + { + ULONGEST addr, endaddr, offset, inode; + const char *permissions, *device, *filename; + size_t permissions_len, device_len; + int read, write, exec; + int modified = 0, has_anonymous = 0; + + read_mapping (line, &addr, &endaddr, &permissions, &permissions_len, + &offset, &device, &device_len, &inode, &filename); + + /* Decode permissions. */ + read = (memchr (permissions, 'r', permissions_len) != 0); + write = (memchr (permissions, 'w', permissions_len) != 0); + exec = (memchr (permissions, 'x', permissions_len) != 0); + + /* Try to detect if region was modified by parsing smaps counters. */ + for (line = strtok (NULL, "\n"); + line && line[0] >= 'A' && line[0] <= 'Z'; + line = strtok (NULL, "\n")) + { + char keyword[64 + 1]; + + if (sscanf (line, "%64s", keyword) != 1) + { + warning (_("Error parsing {s,}maps file '%s'"), mapsfilename); + break; + } + if (strcmp (keyword, "Anonymous:") == 0) + has_anonymous = 1; + if (strcmp (keyword, "Shared_Dirty:") == 0 + || strcmp (keyword, "Private_Dirty:") == 0 + || strcmp (keyword, "Swap:") == 0 + || strcmp (keyword, "Anonymous:") == 0) + { + unsigned long number; + + if (sscanf (line, "%*s%lu", &number) != 1) + { + warning (_("Error parsing {s,}maps file '%s' number"), + mapsfilename); + break; + } + if (number != 0) + modified = 1; + } + } + + /* Older Linux kernels did not support the "Anonymous:" counter. + If it is missing, we can't be sure - dump all the pages. */ + if (!has_anonymous) + modified = 1; + + /* Invoke the callback function to create the corefile segment. */ + retval = func (addr, endaddr - addr, offset, inode, + read, write, exec, modified, filename, func_data); + if (retval != 0) + break; + } + + if (memory_to_free_ptr != NULL) + { + gdb_assert (data == *memory_to_free_ptr); + *memory_to_free_ptr = NULL; + } + xfree (data); + return retval; + } + + return -1; +} diff --git a/gdb/common/linux-maps.h b/gdb/common/linux-maps.h index ebf6f37..03b14d3 100644 --- a/gdb/common/linux-maps.h +++ b/gdb/common/linux-maps.h @@ -19,4 +19,29 @@ #ifndef COMMON_LINUX_MAPS_H #define COMMON_LINUX_MAPS_H +extern void + read_mapping (const char *line, + ULONGEST *addr, ULONGEST *endaddr, + const char **permissions, size_t *permissions_len, + ULONGEST *offset, + const char **device, size_t *device_len, + ULONGEST *inode, + const char **filename); + +/* Callback function for linux_find_memory_regions_full. If it returns + non-zero linux_find_memory_regions_full returns immediately with that + value. */ + +typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size, + ULONGEST offset, ULONGEST inode, + int read, int write, + int exec, int modified, + const char *filename, + void *data); + +extern int + linux_find_memory_regions_full (pid_t pid, + linux_find_memory_region_ftype *func, + void *func_data, void **memory_to_free_ptr); + #endif /* COMMON_LINUX_MAPS_H */ diff --git a/gdb/common/target-utils.c b/gdb/common/target-utils.c index 308996d..84d1bca 100644 --- a/gdb/common/target-utils.c +++ b/gdb/common/target-utils.c @@ -23,4 +23,93 @@ #include "defs.h" #endif +#include #include "target-utils.h" +#include "gdb_assert.h" + +LONGEST +read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func, + int padding, void **memory_to_free_ptr) +{ + size_t buf_alloc, buf_pos; + gdb_byte *buf; + LONGEST n; + int target_errno; + + /* Start by reading up to 4K at a time. The target will throttle + this number down if necessary. */ + buf_alloc = 4096; + buf = xmalloc (buf_alloc); + if (memory_to_free_ptr != NULL) + { + gdb_assert (*memory_to_free_ptr == NULL); + *memory_to_free_ptr = buf; + } + buf_pos = 0; + while (1) + { + n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding, + buf_pos, &target_errno); + if (n <= 0) + { + if (n < 0 || (n == 0 && buf_pos == 0)) + xfree (buf); + else + *buf_p = buf; + if (memory_to_free_ptr != NULL) + *memory_to_free_ptr = NULL; + if (n < 0) + { + /* An error occurred. */ + return -1; + } + else + { + /* Read all there was. */ + return buf_pos; + } + } + + buf_pos += n; + + /* If the buffer is filling up, expand it. */ + if (buf_alloc < buf_pos * 2) + { + buf_alloc *= 2; + buf = xrealloc (buf, buf_alloc); + if (memory_to_free_ptr != NULL) + *memory_to_free_ptr = buf; + } + } +} + +char * +read_stralloc (const char *filename, read_stralloc_func_ftype *func) +{ + gdb_byte *buffer; + char *bufstr; + LONGEST i, transferred; + + transferred = func (filename, &buffer, 1); + bufstr = (char *) buffer; + + if (transferred < 0) + return NULL; + + if (transferred == 0) + return xstrdup (""); + + bufstr[transferred] = 0; + + /* Check for embedded NUL bytes; but allow trailing NULs. */ + for (i = strlen (bufstr); i < transferred; i++) + if (bufstr[i] != 0) + { + warning (_("target file %s " + "contained unexpected null characters"), + filename); + break; + } + + return bufstr; +} diff --git a/gdb/common/target-utils.h b/gdb/common/target-utils.h index db33ec8..f8ca972 100644 --- a/gdb/common/target-utils.h +++ b/gdb/common/target-utils.h @@ -20,4 +20,15 @@ #ifndef COMMON_TARGET_UTILS_H #define COMMON_TARGET_UTILS_H +typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len, + ULONGEST offset, int *target_errno); +extern LONGEST read_alloc (gdb_byte **buf_p, int handle, + read_alloc_pread_ftype *pread_func, int padding, + void **memory_to_free_ptr); + +typedef LONGEST (read_stralloc_func_ftype) (const char *filename, + gdb_byte **buf_p, int padding); +extern char *read_stralloc (const char *filename, + read_stralloc_func_ftype *func); + #endif /* COMMON_TARGET_UTILS_H */ diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c index b9aba2d..d0c8761 100644 --- a/gdb/linux-tdep.c +++ b/gdb/linux-tdep.c @@ -32,6 +32,7 @@ #include "cli/cli-utils.h" #include "arch-utils.h" #include "gdb_obstack.h" +#include "linux-maps.h" #include @@ -274,44 +275,6 @@ linux_core_pid_to_str (struct gdbarch *gdbarch, ptid_t ptid) return normal_pid_to_str (ptid); } -/* Service function for corefiles and info proc. */ - -static void -read_mapping (const char *line, - ULONGEST *addr, ULONGEST *endaddr, - const char **permissions, size_t *permissions_len, - ULONGEST *offset, - const char **device, size_t *device_len, - ULONGEST *inode, - const char **filename) -{ - const char *p = line; - - *addr = strtoulst (p, &p, 16); - if (*p == '-') - p++; - *endaddr = strtoulst (p, &p, 16); - - p = skip_spaces_const (p); - *permissions = p; - while (*p && !isspace (*p)) - p++; - *permissions_len = p - *permissions; - - *offset = strtoulst (p, &p, 16); - - p = skip_spaces_const (p); - *device = p; - while (*p && !isspace (*p)) - p++; - *device_len = p - *device; - - *inode = strtoulst (p, &p, 10); - - p = skip_spaces_const (p); - *filename = p; -} - /* Implement the "info proc" command. */ static void @@ -730,126 +693,6 @@ linux_core_info_proc (struct gdbarch *gdbarch, char *args, error (_("unable to handle request")); } -/* Callback function for linux_find_memory_regions_full. If it returns - non-zero linux_find_memory_regions_full returns immediately with that - value. */ - -typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size, - ULONGEST offset, ULONGEST inode, - int read, int write, - int exec, int modified, - const char *filename, - void *data); - -/* List memory regions in the inferior PID for a corefile. Call FUNC - with FUNC_DATA for each such region. Return immediately with the - value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should - be registered to be freed automatically if called FUNC throws an - exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is - not used. Return -1 if error occurs, 0 if all memory regions have - been processed or return the value from FUNC if FUNC returns - non-zero. */ - -static int -linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func, - void *func_data, void **memory_to_free_ptr) -{ - char mapsfilename[100]; - char *data; - - xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", (int) pid); - data = target_fileio_read_stralloc (mapsfilename); - if (data == NULL) - { - /* Older Linux kernels did not support /proc/PID/smaps. */ - xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/maps", - (int) pid); - data = target_fileio_read_stralloc (mapsfilename); - } - if (data) - { - char *line; - int retval = 0; - - if (memory_to_free_ptr != NULL) - { - gdb_assert (*memory_to_free_ptr == NULL); - *memory_to_free_ptr = data; - } - - line = strtok (data, "\n"); - while (line) - { - ULONGEST addr, endaddr, offset, inode; - const char *permissions, *device, *filename; - size_t permissions_len, device_len; - int read, write, exec; - int modified = 0, has_anonymous = 0; - - read_mapping (line, &addr, &endaddr, &permissions, &permissions_len, - &offset, &device, &device_len, &inode, &filename); - - /* Decode permissions. */ - read = (memchr (permissions, 'r', permissions_len) != 0); - write = (memchr (permissions, 'w', permissions_len) != 0); - exec = (memchr (permissions, 'x', permissions_len) != 0); - - /* Try to detect if region was modified by parsing smaps counters. */ - for (line = strtok (NULL, "\n"); - line && line[0] >= 'A' && line[0] <= 'Z'; - line = strtok (NULL, "\n")) - { - char keyword[64 + 1]; - - if (sscanf (line, "%64s", keyword) != 1) - { - warning (_("Error parsing {s,}maps file '%s'"), mapsfilename); - break; - } - if (strcmp (keyword, "Anonymous:") == 0) - has_anonymous = 1; - if (strcmp (keyword, "Shared_Dirty:") == 0 - || strcmp (keyword, "Private_Dirty:") == 0 - || strcmp (keyword, "Swap:") == 0 - || strcmp (keyword, "Anonymous:") == 0) - { - unsigned long number; - - if (sscanf (line, "%*s%lu", &number) != 1) - { - warning (_("Error parsing {s,}maps file '%s' number"), - mapsfilename); - break; - } - if (number != 0) - modified = 1; - } - } - - /* Older Linux kernels did not support the "Anonymous:" counter. - If it is missing, we can't be sure - dump all the pages. */ - if (!has_anonymous) - modified = 1; - - /* Invoke the callback function to create the corefile segment. */ - retval = func (addr, endaddr - addr, offset, inode, - read, write, exec, modified, filename, func_data); - if (retval != 0) - break; - } - - if (memory_to_free_ptr != NULL) - { - gdb_assert (data == *memory_to_free_ptr); - *memory_to_free_ptr = NULL; - } - xfree (data); - return retval; - } - - return -1; -} - /* A structure for passing information through linux_find_memory_regions_full. */ diff --git a/gdb/target.c b/gdb/target.c index 06b6331..0e5ea33 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -45,6 +45,7 @@ #include "gdb/fileio.h" #include "agent.h" #include "auxv.h" +#include "target-utils.h" static void target_info (char *, int); @@ -2952,9 +2953,6 @@ target_fileio_close_cleanup (void *opaque) target_fileio_close (fd, &target_errno); } -typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len, - ULONGEST offset, int *target_errno); - static read_alloc_pread_ftype target_fileio_read_alloc_1_pread; /* Helper for target_fileio_read_alloc_1 to make it interruptible. */ @@ -2968,6 +2966,8 @@ target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len, return target_fileio_pread (handle, read_buf, len, offset, target_errno); } +static read_stralloc_func_ftype target_fileio_read_alloc_1; + /* Read target file FILENAME. Store the result in *BUF_P and return the size of the transferred data. PADDING additional bytes are available in *BUF_P. This is a helper function for @@ -2975,67 +2975,6 @@ target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len, information. */ static LONGEST -read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func, - int padding, void **memory_to_free_ptr) -{ - size_t buf_alloc, buf_pos; - gdb_byte *buf; - LONGEST n; - int target_errno; - - /* Start by reading up to 4K at a time. The target will throttle - this number down if necessary. */ - buf_alloc = 4096; - buf = xmalloc (buf_alloc); - if (memory_to_free_ptr != NULL) - { - gdb_assert (*memory_to_free_ptr == NULL); - *memory_to_free_ptr = buf; - } - buf_pos = 0; - while (1) - { - n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding, - buf_pos, &target_errno); - if (n <= 0) - { - if (n < 0 || (n == 0 && buf_pos == 0)) - xfree (buf); - else - *buf_p = buf; - if (memory_to_free_ptr != NULL) - *memory_to_free_ptr = NULL; - if (n < 0) - { - /* An error occurred. */ - return -1; - } - else - { - /* Read all there was. */ - return buf_pos; - } - } - - buf_pos += n; - - /* If the buffer is filling up, expand it. */ - if (buf_alloc < buf_pos * 2) - { - buf_alloc *= 2; - buf = xrealloc (buf, buf_alloc); - if (memory_to_free_ptr != NULL) - *memory_to_free_ptr = buf; - } - } -} - -typedef LONGEST (read_stralloc_func_ftype) (const char *filename, - gdb_byte **buf_p, int padding); - -static read_stralloc_func_ftype target_fileio_read_alloc_1; - -static LONGEST target_fileio_read_alloc_1 (const char *filename, gdb_byte **buf_p, int padding) { @@ -3073,37 +3012,6 @@ target_fileio_read_alloc (const char *filename, gdb_byte **buf_p) are returned as allocated but empty strings. A warning is issued if the result contains any embedded NUL bytes. */ -static char * -read_stralloc (const char *filename, read_stralloc_func_ftype *func) -{ - gdb_byte *buffer; - char *bufstr; - LONGEST i, transferred; - - transferred = func (filename, &buffer, 1); - bufstr = (char *) buffer; - - if (transferred < 0) - return NULL; - - if (transferred == 0) - return xstrdup (""); - - bufstr[transferred] = 0; - - /* Check for embedded NUL bytes; but allow trailing NULs. */ - for (i = strlen (bufstr); i < transferred; i++) - if (bufstr[i] != 0) - { - warning (_("target file %s " - "contained unexpected null characters"), - filename); - break; - } - - return bufstr; -} - char * target_fileio_read_stralloc (const char *filename) {