aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriraisr <iraisr@a5019735-40e9-0310-863c-91ae7b9d1cf9>2015-09-25 20:12:26 +0000
committeriraisr <iraisr@a5019735-40e9-0310-863c-91ae7b9d1cf9>2015-09-25 20:12:26 +0000
commite03654002556aa3ece73c344ec8c8cbe15754df1 (patch)
tree95a981493a58e7581b29ae57aa7d52cd2a5bf371
parentba0f0541efceb398184d137caa4da16d2d2a6c91 (diff)
downloadvalgrind-e03654002556aa3ece73c344ec8c8cbe15754df1.tar.gz
Support correctly AT_SUN_SYSSTAT_ADDR and AT_SUN_SYSSTAT_ZONE_ADDR
in the auxiliary vector. This is possible as Solaris 12 kernel now creates auxv even for statically linked binaries. n-i-bz git-svn-id: svn://svn.valgrind.org/valgrind/trunk@15682 a5019735-40e9-0310-863c-91ae7b9d1cf9
-rw-r--r--README.solaris10
-rw-r--r--coregrind/m_initimg/initimg-solaris.c94
-rw-r--r--coregrind/m_syswrap/syswrap-solaris.c104
-rw-r--r--coregrind/pub_core_syswrap.h1
-rw-r--r--include/vki/vki-solaris.h7
5 files changed, 146 insertions, 70 deletions
diff --git a/README.solaris b/README.solaris
index 6bc8eec4a..a4aaf6a22 100644
--- a/README.solaris
+++ b/README.solaris
@@ -79,15 +79,6 @@ Limitations
possible for Valgrind to arrange mapping of a kernel shared page at the
address specified in the mapfile for the guest application. There is currently
no such mechanism in Solaris. Hacky workarounds are possible, though.
-- Guest programs do not contain entries for AT_SUN_SYSSTAT_ADDR and
- AT_SUN_SYSSTAT_ZONE_ADDR in their auxilliary vectors. There is no direct way
- how to obtain addresses of these pages shared with the kernel as they are
- passed in auxv and kernel does not create auxv for statically linked binaries
- (such as Valgrind analysis tools).
- Indirect methods, such as scanning 1-page mappings found at Valgrind
- startup surrounded by reservations, could be possible. But it is hard to tell
- which page is which because their contents are filled only when a system
- cyclic is started. See get_hrusec() for reference.
- When a thread has no stack then all system calls will result in Valgrind
crash, even though such system calls use just parameters passed in registers.
This should happen only in pathological situations when a thread is created
@@ -139,6 +130,7 @@ TODO list
to see this in effect. Would require awareness of syscall parameter semantics.
- Correctly print arguments of DW_CFA_ORCL_arg_loc in show_CF_instruction() when
it is implemented in libdwarf.
+- Provide tests for AT_SUN_SYSSTAT_ADDR and AT_SUN_SYSSTAT_ZONE_ADDR.
Contacts
diff --git a/coregrind/m_initimg/initimg-solaris.c b/coregrind/m_initimg/initimg-solaris.c
index bdfb6c545..2c20e2176 100644
--- a/coregrind/m_initimg/initimg-solaris.c
+++ b/coregrind/m_initimg/initimg-solaris.c
@@ -29,6 +29,8 @@
The GNU General Public License is contained in the file COPYING.
*/
+/* Copyright 2013-2015, Ivo Raisr <ivosh@ivosh.net>. */
+
#if defined(VGO_solaris)
/* Note: This file is based on initimg-linux.c. */
@@ -273,6 +275,59 @@ static HChar *copy_str(HChar **tab, const HChar *str)
return orig;
}
+/* The auxiliary vector might not be present. So we cross-check pointers from
+ argv and envp pointing to the string table. */
+static vki_auxv_t *find_original_auxv(Addr init_sp)
+{
+ HChar **sp = (HChar **) init_sp;
+ HChar *lowest_str_ptr = (HChar *) UINTPTR_MAX; // lowest ptr to string table
+
+ sp++; // skip argc
+
+ while (*sp != NULL) { // skip argv
+ if (*sp < lowest_str_ptr)
+ lowest_str_ptr = *sp;
+ sp++;
+ }
+ sp++;
+
+ while (*sp != 0) { // skip env
+ if (*sp < lowest_str_ptr)
+ lowest_str_ptr = *sp;
+ sp++;
+ }
+ sp++;
+
+ if ((Addr) sp < (Addr) lowest_str_ptr) {
+ return (vki_auxv_t *) sp;
+ } else {
+ return NULL;
+ }
+}
+
+static void copy_auxv_entry(const vki_auxv_t *orig_auxv, Int type,
+ const HChar *type_name, vki_auxv_t *auxv)
+{
+ vg_assert(auxv != NULL);
+
+ if (orig_auxv == NULL) {
+ VG_(printf)("valgrind: Cannot locate auxiliary vector.\n");
+ VG_(printf)("valgrind: Cannot continue. Sorry.\n\n");
+ VG_(exit)(1);
+ }
+
+ for ( ; orig_auxv->a_type != VKI_AT_NULL; orig_auxv++) {
+ if (orig_auxv->a_type == type) {
+ auxv->a_type = type;
+ auxv->a_un.a_val = orig_auxv->a_un.a_val;
+ return;
+ }
+ }
+
+ VG_(printf)("valgrind: Cannot locate %s in the aux\n", type_name);
+ VG_(printf)("valgrind: vector. Cannot continue. Sorry.\n\n");
+ VG_(exit)(1);
+}
/* This sets up the client's initial stack, containing the args,
environment and aux vector.
@@ -305,11 +360,12 @@ static HChar *copy_str(HChar **tab, const HChar *str)
clstack_end, which was previously determined by the address space manager.
The returned value is the SP value for the client.
- Note that no aux vector is created by kernel on Solaris if the program is
- statically linked (which is our case). That means we have to build auxv
- from scratch. */
+ Note that auxiliary vector is *not* created by kernel on illumos and
+ Solaris 11 if the program is statically linked (which is our case).
+ Although we now taught Solaris 12 to create the auxiliary vector, we still
+ have to build auxv from scratch, to make the code consistent. */
-static Addr setup_client_stack(void *init_sp,
+static Addr setup_client_stack(Addr init_sp,
HChar **orig_envp,
const ExeInfo *info,
Addr clstack_end,
@@ -335,6 +391,9 @@ static Addr setup_client_stack(void *init_sp,
vg_assert(VG_(args_the_exename));
vg_assert(VG_(args_for_client));
+ /* Get the original auxv (if any). */
+ vki_auxv_t *orig_auxv = find_original_auxv(init_sp);
+
/* ==================== compute sizes ==================== */
/* First of all, work out how big the client stack will be. */
@@ -378,11 +437,20 @@ static Addr setup_client_stack(void *init_sp,
AT_PAGESZ
AT_SUN_AUXFLAFGS
AT_SUN_HWCAP
+ AT_SUN_SYSSTAT_ADDR (if supported)
+ AT_SUN_SYSSTAT_ZONE_ADDR (if supported)
AT_NULL
It would be possible to also add AT_PHENT, AT_PHNUM, AT_ENTRY,
AT_SUN_LDDATA, but they don't seem to be so important. */
auxsize = 9 * sizeof(*auxv);
+# if defined(SOLARIS_RESERVE_SYSSTAT_ADDR)
+ auxsize += sizeof(*auxv);
+# endif
+# if defined(SOLARIS_RESERVE_SYSSTAT_ZONE_ADDR)
+ auxsize += sizeof(*auxv);
+# endif
+
# if defined(VGA_x86) || defined(VGA_amd64)
/* AT_SUN_PLATFORM string. */
stringsize += VG_(strlen)("i86pc") + 1;
@@ -739,6 +807,22 @@ static Addr setup_client_stack(void *init_sp,
*/
}
+# if defined(SOLARIS_RESERVE_SYSSTAT_ADDR)
+ /* AT_SUN_SYSSTAT_ADDR */
+ copy_auxv_entry(orig_auxv, VKI_AT_SUN_SYSSTAT_ADDR,
+ "AT_SUN_SYSSTAT_ADDR", auxv);
+ VG_(change_mapping_ownership)(auxv->a_un.a_val, True);
+ auxv++;
+# endif
+
+# if defined(SOLARIS_RESERVE_SYSSTAT_ZONE_ADDR)
+ /* AT_SUN_SYSSTAT_ZONE_ADDR */
+ copy_auxv_entry(orig_auxv, VKI_AT_SUN_SYSSTAT_ZONE_ADDR,
+ "AT_SUN_SYSSTAT_ZONE_ADDR", auxv);
+ VG_(change_mapping_ownership)(auxv->a_un.a_val, True);
+ auxv++;
+# endif
+
/* AT_NULL */
auxv->a_type = VKI_AT_NULL;
auxv->a_un.a_val = 0;
@@ -811,7 +895,7 @@ IIFinaliseImageInfo VG_(ii_create_image)(IICreateImageInfo iicii,
- If a larger --main-stacksize value is specified, use that instead.
- In all situations, the minimum allowed stack size is 1M.
*/
- void *init_sp = iicii.argv - 1;
+ Addr init_sp = (Addr) (iicii.argv - 1);
SizeT m1 = 1024 * 1024;
SizeT m16 = 16 * m1;
SizeT szB = (SizeT)VG_(client_rlimit_stack).rlim_cur;
diff --git a/coregrind/m_syswrap/syswrap-solaris.c b/coregrind/m_syswrap/syswrap-solaris.c
index 25029d4d1..bd2f0044c 100644
--- a/coregrind/m_syswrap/syswrap-solaris.c
+++ b/coregrind/m_syswrap/syswrap-solaris.c
@@ -28,10 +28,10 @@
The GNU General Public License is contained in the file COPYING.
*/
-/* Copyright 2015-2015, Tomas Jedlicka <jedlickat@gmail.com>. */
-
/* Copyright 2013-2015, Ivo Raisr <ivosh@ivosh.net>. */
+/* Copyright 2015-2015, Tomas Jedlicka <jedlickat@gmail.com>. */
+
/* Copyright 2013, OmniTI Computer Consulting, Inc. All rights reserved. */
#if defined(VGO_solaris)
@@ -438,6 +438,50 @@ void VG_(syswrap_init)(void)
VG_(atfork)(NULL, NULL, clean_schedctl_data);
}
+/* Changes ownership of a memory mapping shared between kernel and the client
+ process. This mapping should have already been pre-arranged during process
+ address space initialization happening in kernel. Valgrind on startup created
+ a segment for this mapping categorized as Valgrind's owned anonymous.
+ Size of this mapping typically varies among Solaris versions but should be
+ page aligned.
+ If 'once_only' is 'True', it is expected this function is called once only
+ and the mapping ownership has not been changed, yet [useful during
+ initialization]. If 'False', this function can be called many times but does
+ change ownership only upon the first invocation [useful in syscall wrappers].
+ */
+void VG_(change_mapping_ownership)(Addr addr, Bool once_only)
+{
+ const NSegment *seg = VG_(am_find_anon_segment)(addr);
+ vg_assert(seg != NULL);
+ vg_assert(seg->start == addr);
+ vg_assert(VG_IS_PAGE_ALIGNED(seg->start));
+ vg_assert(VG_IS_PAGE_ALIGNED(seg->end + 1));
+ SizeT size = seg->end - seg->start + 1;
+ vg_assert(size > 0);
+
+ Bool do_change = False;
+ if (once_only) {
+ vg_assert(VG_(am_is_valid_for_valgrind)(addr, size, VKI_PROT_READ));
+ do_change = True;
+ } else {
+ if (!VG_(am_is_valid_for_client)(addr, size, VKI_PROT_READ))
+ do_change = True;
+ }
+
+ if (do_change) {
+ Bool change_ownership_OK = VG_(am_change_ownership_v_to_c)(addr, size);
+ vg_assert(change_ownership_OK);
+
+ /* Tell the tool about just discovered mapping. */
+ VG_TRACK(new_mem_startup,
+ addr, size,
+ True /* readable? */,
+ False /* writable? */,
+ False /* executable? */,
+ 0 /* di_handle */);
+ }
+}
+
/* Calculate the Fletcher-32 checksum of a given buffer. */
UInt ML_(fletcher32)(UShort *buf, SizeT blocks)
{
@@ -9755,33 +9799,7 @@ POST(fast_gethrt)
if (RES == 0)
return;
- /* Returned address points to a memory mapping shared between kernel
- and the process. This was already pre-arranged during process address
- space initialization happening in kernel. Valgrind on startup created
- a segment for this mapping categorized as Valgrind's owned anonymous.
- Size of this mapping varies among Solaris versions but should be
- page aligned. */
- const NSegment *seg = VG_(am_find_anon_segment)(RES);
- vg_assert(seg != NULL);
- vg_assert(seg->start == RES);
- vg_assert(VG_IS_PAGE_ALIGNED(seg->start));
- vg_assert(VG_IS_PAGE_ALIGNED(seg->end + 1));
- SizeT size = seg->end - seg->start + 1;
- vg_assert(size > 0);
-
- if (!VG_(am_is_valid_for_client)(RES, size, VKI_PROT_READ)) {
- Bool change_ownership_v_c_OK
- = VG_(am_change_ownership_v_to_c)(RES, size);
- vg_assert(change_ownership_v_c_OK);
-
- /* Tell the tool about just discovered mapping. */
- VG_TRACK(new_mem_startup,
- RES, size,
- True /* readable? */,
- False /* writable? */,
- False /* executable? */,
- 0 /* di_handle */);
- }
+ VG_(change_mapping_ownership)(RES, False);
}
#endif /* SOLARIS_GETHRT_FASTTRAP */
@@ -9798,33 +9816,7 @@ POST(fast_getzoneoffset)
if (RES == 0)
return;
- /* Returned address points to a memory mapping shared between kernel
- and the process. This was already pre-arranged during process address
- space initialization happening in kernel. Valgrind on startup created
- a segment for this mapping categorized as Valgrind's owned anonymous.
- Size of this mapping varies among Solaris versions but should be
- page aligned. */
- const NSegment *seg = VG_(am_find_anon_segment)(RES);
- vg_assert(seg != NULL);
- vg_assert(seg->start == RES);
- vg_assert(VG_IS_PAGE_ALIGNED(seg->start));
- vg_assert(VG_IS_PAGE_ALIGNED(seg->end + 1));
- SizeT size = seg->end - seg->start + 1;
- vg_assert(size > 0);
-
- if (!VG_(am_is_valid_for_client)(RES, size, VKI_PROT_READ)) {
- Bool change_ownership_v_c_OK
- = VG_(am_change_ownership_v_to_c)(RES, size);
- vg_assert(change_ownership_v_c_OK);
-
- /* Tell the tool about just discovered mapping. */
- VG_TRACK(new_mem_startup,
- RES, size,
- True /* readable? */,
- False /* writable? */,
- False /* executable? */,
- 0 /* di_handle */);
- }
+ VG_(change_mapping_ownership)(RES, False);
}
#endif /* SOLARIS_GETZONEOFFSET_FASTTRAP */
diff --git a/coregrind/pub_core_syswrap.h b/coregrind/pub_core_syswrap.h
index 35e8bc915..0b5b54bd6 100644
--- a/coregrind/pub_core_syswrap.h
+++ b/coregrind/pub_core_syswrap.h
@@ -93,6 +93,7 @@ extern void VG_(save_context)(ThreadId tid, vki_ucontext_t *uc,
extern void VG_(restore_context)(ThreadId tid, vki_ucontext_t *uc,
CorePart part, Bool esp_is_thrptr);
extern void VG_(syswrap_init)(void);
+extern void VG_(change_mapping_ownership)(Addr addr, Bool once_only);
extern Bool VG_(setup_client_dataseg)(void);
extern void VG_(track_client_dataseg)(ThreadId tid);
#endif
diff --git a/include/vki/vki-solaris.h b/include/vki/vki-solaris.h
index a5f7ece5b..7b5a6a05f 100644
--- a/include/vki/vki-solaris.h
+++ b/include/vki/vki-solaris.h
@@ -70,6 +70,7 @@
#include <sys/types.h>
#define VKI_UINT_MAX UINT_MAX
+#define VKI_UINTPTR_MAX UINTPTR_MAX
#define vki_boolean_t boolean_t
#define vki_datalink_id_t datalink_id_t
#define vki_uint_t uint_t
@@ -252,6 +253,12 @@ typedef struct {
#define VKI_AT_SUN_HWCAP AT_SUN_HWCAP
#define VKI_AT_SUN_EXECNAME AT_SUN_EXECNAME
#define VKI_AT_SUN_AUXFLAGS AT_SUN_AUXFLAGS
+#if defined(SOLARIS_RESERVE_SYSSTAT_ADDR)
+#define VKI_AT_SUN_SYSSTAT_ADDR AT_SUN_SYSSTAT_ADDR
+#endif
+#if defined(SOLARIS_RESERVE_SYSSTAT_ZONE_ADDR)
+#define VKI_AT_SUN_SYSSTAT_ZONE_ADDR AT_SUN_SYSSTAT_ZONE_ADDR
+#endif
#define VKI_AF_SUN_HWCAPVERIFY AF_SUN_HWCAPVERIFY