This is the mail archive of the systemtap@sourceware.org mailing list for the systemtap project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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) */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]