This is the mail archive of the
systemtap@sourceware.org
mailing list for the systemtap project.
Re: s390x help needed - kernel read faults
On Mon, 2011-11-07 at 18:17 +0100, Mark Wielaard wrote:
> On Mon, Nov 07, 2011 at 10:03:19AM -0600, David Smith wrote:
> > I'm not sure why we provided our own functions, that decision was made a
> > long time ago. If we can't look at the address and know whether it is a
> > user space or kernel space address, then I don't see much choice than to
> > break up our memory accesses and require the callers to know whether
> > they are accessing kernel space or user space.
>
> Yes, it seems not that hard to track fully, we mostly do know already.
So I split our deref and store_deref into uderef/kderef and
store_u/kderef that are now used when user or kernel addresses are
accessed. For most architectures these are equal. But for s390x I
replaced our custom accessor functions with with standard s390 kernel
__get_user() and __put_user() functions and then wrap those in get_fs()
set_fs() calls to switch between user/kernel space addresses. See below.
Tested against 2.6.18 (rhel5) and 2.6.32 (rhel6) kernels. It improves
the make installcheck results a lot.
There is still some work to do for the user space dwarf unwinder.
Cheers,
Mark
=== runtime/loc2c-runtime.h s390 deref functions ===
#elif defined (__s390__) || defined (__s390x__)
/* Use same __get_user() and __put_user() for both user and kernel
addresses, but make sure set_fs() is called appropriately first. */
#define uderef(size, addr) ({ \
u8 _b; u16 _w; u32 _l; u64 _q; \
uintptr_t _a = (uintptr_t) addr; \
intptr_t _v = 0; \
int _bad = 0; \
mm_segment_t _oldfs = get_fs(); \
set_fs (USER_DS); \
switch (size) { \
case 1: _bad = __get_user(_b, (u8 *)(_a)); _v = _b; break; \
case 2: _bad = __get_user(_w, (u16 *)(_a)); _v = _w; break; \
case 4: _bad = __get_user(_l, (u32 *)(_a)); _v = _l; break; \
case 8: _bad = __get_user(_q, (u64 *)(_a)); _v = _q; break; \
default: __get_user_bad(); \
} \
set_fs (_oldfs); \
if (_bad) \
DEREF_FAULT(addr); \
_v; \
})
#define store_uderef(size, addr, value) ({ \
int _bad = 0; \
mm_segment_t _oldfs = get_fs(); \
set_fs (USER_DS); \
switch (size) { \
case 1: _bad = __put_user(((u8)(value)), ((u8 *)(addr))); break; \
case 2: _bad = __put_user(((u16)(value)), ((u16 *)(addr))); break; \
case 4: _bad = __put_user(((u32)(value)), ((u32 *)(addr))); break; \
case 8: _bad = __put_user(((u64)(value)), ((u64 *)(addr))); break; \
default: __put_user_bad(); \
} \
set_fs (_oldfs); \
if (_bad) \
STORE_DEREF_FAULT(addr); \
})
#define kderef(size, addr) ({ \
u8 _b; u16 _w; u32 _l; u64 _q; \
uintptr_t _a = (uintptr_t) addr; \
intptr_t _v = 0; \
int _bad = 0; \
mm_segment_t _oldfs = get_fs(); \
set_fs (KERNEL_DS); \
switch (size) { \
case 1: _bad = __get_user(_b, (u8 *)(_a)); _v = _b; break; \
case 2: _bad = __get_user(_w, (u16 *)(_a)); _v = _w; break; \
case 4: _bad = __get_user(_l, (u32 *)(_a)); _v = _l; break; \
case 8: _bad = __get_user(_q, (u64 *)(_a)); _v = _q; break; \
default: __get_user_bad(); \
} \
set_fs (_oldfs); \
if (_bad) \
DEREF_FAULT(addr); \
_v; \
})
#define store_kderef(size, addr, value) ({ \
int _bad = 0; \
mm_segment_t _oldfs = get_fs(); \
set_fs (KERNEL_DS); \
switch (size) { \
case 1: _bad = __put_user(((u8)(value)), ((u8 *)(addr))); break; \
case 2: _bad = __put_user(((u16)(value)), ((u16 *)(addr))); break; \
case 4: _bad = __put_user(((u32)(value)), ((u32 *)(addr))); break; \
case 8: _bad = __put_user(((u64)(value)), ((u64 *)(addr))); break; \
default: __put_user_bad(); \
} \
set_fs (_oldfs); \
if (_bad) \
STORE_DEREF_FAULT(addr); \
})
#endif /* (s390) || (s390x) */