This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc 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: [RFC][PATCH 22/22] Add Infinity notes implementing td_ta_map_lwp2thr


I like the idea of improving debugging capabilities with something new
than libpthread_db, however I do not see the best approach of using
the i8 files directly in GLIBC. If I understood correctly from the
link you posted with this documentation, it is still a very WIP project
with rough places and the language/compiler is still being constantly
updated.

Also I do not like to add another tool dependency for complete GLIBC
build and one in such state (GLIBC do use python for benchmark but
it is not really required for build afaik). So which is the issue
of shipping the ELF notes in assembly format instead?

On 20-10-2015 12:56, Gary Benson wrote:
> This commit adds the source code for the two Infinity notes that
> implement libthread_db's td_ta_map_lwp2thr function.  It also adds
> an I8X testcase for it, and hooks it into "make check".
> 
> The build rules are conditional in that if I8C is not installed then
> no notes will be built; the resulting libpthread.so will be as before.
> If I8C is installed but I8X is not then the notes will be built but
> untested.  This combination is unlikely in practise as I8C and I8X are
> part of the same package.
> 
> The source code is split into five files:
> 
>   infinity-nptl.i8 contains some common definitions and will
>     be included by all other infinity-*.i8 files under nptl.
> 
>   infinity-map_lwp2thr.i8 contains "libpthread::map_lwp2thr",
>     the note function that debuggers etc will call.
> 
>     Libraries that contain Infinity notes should provide
>     documentation on the API of those notes.  For this note
>     this is basically that it takes one argument, an integer
>     specifying the LWPID of interest, and returns two results,
>     an integer status code (one of libthread_db's: TD_OK, TD_ERR,
>     etc) and a pointer which is the result of the call iff the
>     returned status was TD_OK.  The returned pointer is undefined
>     if the returned status was not TD_OK.
> 
>     A further part of libpthread::map_lwp2thr's API is that it
>     requires two external functions: procservice::get_register
>     and procservice::get_thread_area.
> 
>     (External functions must be defined *somehow* before this note may
>     be executed, in much the same way that programs wishing to use
>     libthread_db's td_ta_map_lwp2thr function must implement the
>     proc_service functions it uses.  They could be Infinity notes
>     from some other library, but in this case it's more likely that
>     the program executing the note would provide them directly.)
> 
>   infinity-lookup_th_unique_{cta,reg,rta}.i8 contain
>     "libpthread::__lookup_th_unique" for constant thread area,
>     register, and register thread area platforms respectively.  This
>     function is used by map_lwp2thr.  Which file is built depends on
>     macros defined in the platform's tls.h.  The double-underscore
>     preceeding its name indicates to note consumers that this function
>     is not part of libpthread's exported Infinity API.  It will be
>     part of the spec that consumers (i.e. programs that execute notes)
>     must not call double-underscore functions directly.
> ---
>  nptl/Makefile                         |   26 ++++++
>  nptl/infinity-lookup_th_unique_cta.i8 |   61 +++++++++++++
>  nptl/infinity-lookup_th_unique_reg.i8 |   76 ++++++++++++++++
>  nptl/infinity-lookup_th_unique_rta.i8 |  140 +++++++++++++++++++++++++++++
>  nptl/infinity-map_lwp2thr.i8          |  121 +++++++++++++++++++++++++
>  nptl/infinity-nptl.i8                 |   36 ++++++++
>  nptl/tst-infinity-map_lwp2thr.py      |  155 +++++++++++++++++++++++++++++++++
>  7 files changed, 615 insertions(+), 0 deletions(-)
>  create mode 100644 nptl/infinity-lookup_th_unique_cta.i8
>  create mode 100644 nptl/infinity-lookup_th_unique_reg.i8
>  create mode 100644 nptl/infinity-lookup_th_unique_rta.i8
>  create mode 100644 nptl/infinity-map_lwp2thr.i8
>  create mode 100644 nptl/infinity-nptl.i8
>  create mode 100644 nptl/tst-infinity-map_lwp2thr.py
> 
> diff --git a/nptl/Makefile b/nptl/Makefile
> index 0272813..eb90e66 100644
> --- a/nptl/Makefile
> +++ b/nptl/Makefile
> @@ -138,6 +138,12 @@ libpthread-routines = nptl-init vars events version pt-interp \
>  #		      pthread_setgid pthread_setegid pthread_setregid \
>  #		      pthread_setresgid
>  
> +ifneq ($(I8C),no)
> +infinity-routines = infinity-map_lwp2thr
> +
> +libpthread-routines += $(infinity-routines)
> +endif
> +
>  libpthread-shared-only-routines = version pt-interp pt-allocrtsig \
>  				  unwind-forcedunwind
>  libpthread-static-only-routines = pthread_atfork
> @@ -414,6 +420,26 @@ ifneq ($(have-cxx-thread_local),yes)
>  tests-unsupported += tst-thread_local1
>  endif
>  
> +tests += tst-infinity
> +ifneq ($(I8C),no)
> +ifneq ($(I8X),no)
> +infinity-tests = $(addprefix tst-,$(addsuffix .py,$(infinity-routines)))
> +
> +$(objpfx)tst-infinity.out: $(objpfx)libpthread.so$(libpthread.so-version) \
> +			   $(infinity-tests)
> +	$(I8X) -i $< -I$(common-objpfx) $(infinity-tests) > $@; \
> +	$(evaluate-test)
> +
> +tests-special += $(objpfx)tst-infinity.out
> +else
> +# I8X is not installed; the tests cannot be run.
> +tests-unsupported += tst-infinity
> +endif
> +else
> +# I8C is not installed; libpthread.so will not contain notes.
> +tests-unsupported += tst-infinity
> +endif
> +
>  include ../Rules
>  
>  ifeq (yes,$(build-shared))
> diff --git a/nptl/infinity-lookup_th_unique_cta.i8 b/nptl/infinity-lookup_th_unique_cta.i8
> new file mode 100644
> index 0000000..0af457e
> --- /dev/null
> +++ b/nptl/infinity-lookup_th_unique_cta.i8
> @@ -0,0 +1,61 @@
> +/* Which thread is running on an LWP?
> +   Copyright (C) 2003-2015 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +
> +/* Given an lwpid_t identifying an LWP, return TD_OK and the
> +   descriptor of the thread running on it, or a non-TD_OK
> +   td_err_e code indicating the reason for failure and an
> +   undefined value that must be ignored.  The caller must
> +   ensure that __pthread_initialize_minimal has gotten far
> +   enough; see the comments in infinity_map_lwp2thr.i8 for
> +   specifics.  */
> +
> +define libpthread::__lookup_th_unique returns td_err_e, ptr
> +	argument lwpid_t lwpid
> +	extern ps_get_ta_f procservice::get_thread_area
> +
> +		// stack 0: procservice::get_thread_area
> +		// stack 1: lwpid
> +	load I8_TS_CTA_VALUE
> +		// stack 0: I8_TS_CTA_VALUE
> +		// stack 1: procservice::get_thread_area
> +		// stack 2: lwpid
> +	swap
> +		// stack 0: procservice::get_thread_area
> +		// stack 1: I8_TS_CTA_VALUE
> +		// stack 2: lwpid
> +	call
> +		// stack 0: PS_OK (hopefully) or something else
> +		// stack 1: the thing we want (hopefully) or junk
> +	load PS_OK
> +		// stack 0: PS_OK
> +		// stack 1: PS_OK (hopefully) or something else
> +		// stack 2: the thing we want (hopefully) or junk
> +	bne get_thread_area_failed
> +		// stack 0: the thing we want
> +	load TD_OK
> +		// stack 0: TD_OK
> +		// stack 1: the thing we want
> +	return
> +
> +get_thread_area_failed:
> +		// stack 0: junk
> +	load TD_ERR
> +		// stack 0: TD_OK
> +		// stack 1: junk
> +	return
> diff --git a/nptl/infinity-lookup_th_unique_reg.i8 b/nptl/infinity-lookup_th_unique_reg.i8
> new file mode 100644
> index 0000000..07aa3a0
> --- /dev/null
> +++ b/nptl/infinity-lookup_th_unique_reg.i8
> @@ -0,0 +1,76 @@
> +/* Which thread is running on an LWP?
> +   Copyright (C) 2003-2015 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +
> +/* Given an lwpid_t identifying an LWP, return TD_OK and the
> +   descriptor of the thread running on it, or a non-TD_OK
> +   td_err_e code indicating the reason for failure and an
> +   undefined value that must be ignored.  The caller must
> +   ensure that __pthread_initialize_minimal has gotten far
> +   enough; see the comments in infinity_map_lwp2thr.i8 for
> +   specifics.  */
> +
> +define libpthread::__lookup_th_unique returns td_err_e, ptr
> +	argument lwpid_t lwpid
> +	extern ps_getreg_f procservice::get_register
> +
> +		// stack 0: procservice::get_register
> +		// stack 1: lwpid
> +	load I8_TS_REG_OFFSET
> +		// stack 0: I8_TS_REG_OFFSET
> +		// stack 1: procservice::get_thread_area
> +		// stack 2: lwpid
> +	swap
> +		// stack 0: procservice::get_thread_area
> +		// stack 1: I8_TS_REG_OFFSET
> +		// stack 2: lwpid
> +	load I8_TS_REG_SIZE
> +		// stack 0: I8_TS_REG_SIZE
> +		// stack 1: procservice::get_thread_area
> +		// stack 2: I8_TS_REG_OFFSET
> +		// stack 3: lwpid
> +	swap
> +		// stack 1: procservice::get_thread_area
> +		// stack 0: I8_TS_REG_SIZE
> +		// stack 2: I8_TS_REG_OFFSET
> +		// stack 3: lwpid
> +	call
> +		// stack 0: PS_OK (hopefully) or something else
> +		// stack 1: contents of register (hopefully) or junk
> +	load PS_OK
> +		// stack 0: PS_OK
> +		// stack 1: PS_OK (hopefully) or something else
> +		// stack 2: contents of register (hopefully) or junk
> +	bne get_register_failed
> +		// stack 0: contents of register
> +	load I8_TS_REG_BIAS
> +		// stack 0: I8_TS_REG_BIAS
> +		// stack 1: contents of register
> +	add
> +		// stack 0: biased contents of register
> +	load TD_OK
> +		// stack 0: TD_OK
> +		// stack 1: biased contents of register
> +	return
> +
> +get_register_failed:
> +		// stack 0: junk
> +	load TD_ERR
> +		// stack 0: TD_OK
> +		// stack 1: junk
> +	return
> diff --git a/nptl/infinity-lookup_th_unique_rta.i8 b/nptl/infinity-lookup_th_unique_rta.i8
> new file mode 100644
> index 0000000..d892566
> --- /dev/null
> +++ b/nptl/infinity-lookup_th_unique_rta.i8
> @@ -0,0 +1,140 @@
> +/* Which thread is running on an LWP?
> +   Copyright (C) 2003-2015 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +
> +/* Given an lwpid_t identifying an LWP, return TD_OK and the
> +   descriptor of the thread running on it, or a non-TD_OK
> +   td_err_e code indicating the reason for failure and an
> +   undefined value that must be ignored.  The caller must
> +   ensure that __pthread_initialize_minimal has gotten far
> +   enough; see the comments in infinity_map_lwp2thr.i8 for
> +   specifics.  */
> +
> +define libpthread::__lookup_th_unique returns td_err_e, ptr
> +	argument lwpid_t lwpid
> +	extern ps_getreg_f procservice::get_register
> +	extern ps_get_ta_f procservice::get_thread_area
> +
> +		// stack 0: procservice::get_thread_area
> +		// stack 1: procservice::get_reg
> +		// stack 2: lwpid
> +	load lwpid
> +		// stack 0: lwpid
> +		// stack 1: procservice::get_thread_area
> +		// stack 2: procservice::get_reg
> +		// stack 3: lwpid
> +	rot
> +		// stack 0: procservice::get_thread_area
> +		// stack 1: procservice::get_reg
> +		// stack 2: lwpid
> +		// stack 3: lwpid
> +	rot
> +		// stack 0: procservice::get_reg
> +		// stack 1: lwpid
> +		// stack 2: procservice::get_thread_area
> +		// stack 3: lwpid
> +	load I8_TS_RTA_OFFSET
> +		// stack 0: I8_TS_RTA_OFFSET
> +		// stack 1: procservice::get_thread_area
> +		// stack 2: lwpid
> +		// stack 3: procservice::get_thread_area
> +		// stack 4: lwpid
> +	swap
> +		// stack 0: procservice::get_thread_area
> +		// stack 1: I8_TS_RTA_OFFSET
> +		// stack 2: lwpid
> +		// stack 3: procservice::get_thread_area
> +		// stack 4: lwpid
> +	load I8_TS_RTA_SIZE
> +		// stack 0: I8_TS_RTA_SIZE
> +		// stack 1: procservice::get_thread_area
> +		// stack 2: I8_TS_RTA_OFFSET
> +		// stack 3: lwpid
> +		// stack 4: procservice::get_thread_area
> +		// stack 5: lwpid
> +	swap
> +		// stack 0: procservice::get_thread_area
> +		// stack 1: I8_TS_RTA_SIZE
> +		// stack 2: I8_TS_RTA_OFFSET
> +		// stack 3: lwpid
> +		// stack 4: procservice::get_thread_area
> +		// stack 5: lwpid
> +	call
> +		// stack 0: PS_OK (hopefully) or something else
> +		// stack 1: contents of register (hopefully) or junk
> +		// stack 2: procservice::get_thread_area
> +		// stack 3: lwpid
> +	load PS_OK
> +		// stack 0: PS_OK
> +		// stack 1: PS_OK (hopefully) or something else
> +		// stack 2: contents of register (hopefully) or junk
> +		// stack 3: procservice::get_thread_area
> +		// stack 4: lwpid
> +	bne get_register_failed
> +		// stack 0: contents of register
> +		// stack 1: procservice::get_thread_area
> +		// stack 2: lwpid
> +	cast 0 int
> +		// stack 0: I8_TS_RTA_SCALE
> +		// stack 1: contents of register
> +		// stack 2: procservice::get_thread_area
> +		// stack 3: lwpid
> +	load I8_TS_RTA_SCALE
> +		// stack 0: I8_TS_RTA_SCALE
> +		// stack 1: contents of register
> +		// stack 2: procservice::get_thread_area
> +		// stack 3: lwpid
> +	shr
> +		// stack 0: scaled contents of register
> +		// stack 1: procservice::get_thread_area
> +		// stack 2: lwpid
> +	swap
> +		// stack 0: procservice::get_thread_area
> +		// stack 1: scaled contents of register
> +		// stack 2: lwpid
> +	call
> +		// stack 0: PS_OK (hopefully) or something else
> +		// stack 1: the thing we want (hopefully) or junk
> +	load PS_OK
> +		// stack 0: PS_OK
> +		// stack 1: PS_OK (hopefully) or something else
> +		// stack 2: the thing we want (hopefully) or junk
> +	bne get_thread_area_failed
> +		// stack 0: the thing we want
> +	load TD_OK
> +		// stack 0: TD_OK
> +		// stack 1: the thing we want
> +	return
> +
> +get_register_failed:
> +		// stack 0: junk
> +		// stack 1: procservice::get_thread_area
> +		// stack 2: lwpid
> +	load TD_ERR
> +		// stack 0: TD_OK
> +		// stack 1: junk
> +		// stack 2: procservice::get_thread_area
> +		// stack 3: lwpid
> +	return
> +
> +get_thread_area_failed:
> +		// stack 0: junk
> +	load TD_ERR
> +		// stack 0: TD_ERR
> +		// stack 1: junk
> +	return
> diff --git a/nptl/infinity-map_lwp2thr.i8 b/nptl/infinity-map_lwp2thr.i8
> new file mode 100644
> index 0000000..51b21ea
> --- /dev/null
> +++ b/nptl/infinity-map_lwp2thr.i8
> @@ -0,0 +1,121 @@
> +/* Which thread is running on an LWP?
> +   Copyright (C) 2003-2015 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include "infinity-nptl.i8"
> +#include "infinity-thread_self.h"
> +
> +#if I8_THREAD_SELF == I8_TS_CONST_THREAD_AREA
> +# include "infinity-lookup_th_unique_cta.i8"
> +#endif
> +#if I8_THREAD_SELF == I8_TS_REGISTER
> +# include "infinity-lookup_th_unique_reg.i8"
> +#endif
> +#if I8_THREAD_SELF == I8_TS_REGISTER_THREAD_AREA
> +# include "infinity-lookup_th_unique_rta.i8"
> +#endif
> +
> +/* Given an lwpid_t identifying an LWP, return TD_OK and the
> +   descriptor of the thread running on it, or a non-TD_OK
> +   td_err_e code indicating the reason for failure and an
> +   undefined value that must be ignored.  Thread descriptors
> +   are opaque pointers and should not be dereferenced outside
> +   of this library.  */
> +
> +define libpthread::map_lwp2thr returns td_err_e, ptr
> +	argument lwpid_t lwpid
> +	extern func td_err_e, ptr (lwpid_t) __lookup_th_unique
> +	extern func pid_t () i8core::getpid
> +	extern ptr __stack_user
> +
> +  /* We cannot rely on thread registers and such information at all
> +     before __pthread_initialize_minimal has gotten far enough: they
> +     sometimes contain garbage left by the kernel at exec that would
> +     confuse us.  If it looks like initialization is incomplete we
> +     fake a special descriptor of NULL to indicate the initial thread.
> +     Other routines in this library recognise this special descriptor
> +     and act accordingly.  */
> +
> +     		// stack 0: __stack_user
> +		// stack 1: i8core::getpid
> +		// stack 2: __lookup_th_unique
> +		// stack 3: lwpid
> +	load LIST_T_NEXT_OFFSET
> +		// stack 0: LIST_T_NEXT_OFFSET
> +		// stack 1: __stack_user
> +		// stack 2: i8core::getpid
> +		// stack 3: __lookup_th_unique
> +		// stack 4: lwpid
> +	add
> +		// stack 0: __stack_user + LIST_T_NEXT_OFFSET
> +		// stack 1: i8core::getpid
> +		// stack 2: __lookup_th_unique
> +		// stack 3: lwpid
> +	deref ptr
> +		// stack 0: __stack_user->next
> +		// stack 1: i8core::getpid
> +		// stack 2: __lookup_th_unique
> +		// stack 3: lwpid
> +	load NULL
> +	bne libpthread_is_initialized
> +
> +initialization_is_incomplete:
> +		// stack 0: i8core::getpid
> +		// stack 1: __lookup_th_unique
> +		// stack 2: lwpid
> +	swap
> +		// stack 0: __lookup_th_unique
> +		// stack 1: i8core::getpid
> +		// stack 2: lwpid
> +	drop
> +		// stack 0: i8core::getpid
> +		// stack 1: lwpid
> +	load NULL
> +		// stack 0: NULL
> +		// stack 1: i8core::getpid
> +		// stack 2: lwpid
> +	rot
> +		// stack 0: i8core::getpid
> +		// stack 1: lwpid
> +		// stack 2: NULL
> +	call
> +		// stack 0: main pid
> +		// stack 1: lwpid
> +		// stack 2: NULL
> +	beq is_main_thread
> +
> +not_main_thread:
> +		// stack 0: NULL
> +	load TD_ERR
> +	return
> +
> +is_main_thread:
> +		// stack 0: NULL
> +	load TD_OK
> +	return
> +
> +libpthread_is_initialized:
> +		// stack 0: i8core::getpid
> +		// stack 1: __lookup_th_unique
> +		// stack 2: lwpid
> +	drop
> +		// stack 0: __lookup_th_unique
> +		// stack 1: lwpid
> +	call
> +		// stack 0: TD_OK (or not)
> +		// stack 1: descriptor (or junk)
> +	return
> diff --git a/nptl/infinity-nptl.i8 b/nptl/infinity-nptl.i8
> new file mode 100644
> index 0000000..62c6012
> --- /dev/null
> +++ b/nptl/infinity-nptl.i8
> @@ -0,0 +1,36 @@
> +/* Common definitions for NPTL Infinity functions.
> +   Copyright (C) 2015 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +/* libpthread and libthread_db generated constants.  */
> +#include "infinity-nptl-constants.h"
> +#include "infinity-nptl_db-constants.h"
> +
> +/* XXX.  */
> +typedef int size_t
> +
> +/* XXX.  */
> +typedef s32 pid_t
> +typedef pid_t lwpid_t
> +
> +/* XXX.  */
> +typedef s32 td_err_e
> +typedef s32 ps_err_e
> +
> +/* XXX.  */
> +typedef func ps_err_e, ptr (lwpid_t, int, int) ps_getreg_f
> +typedef func ps_err_e, ptr (lwpid_t, int) ps_get_ta_f
> diff --git a/nptl/tst-infinity-map_lwp2thr.py b/nptl/tst-infinity-map_lwp2thr.py
> new file mode 100644
> index 0000000..6c7e37e
> --- /dev/null
> +++ b/nptl/tst-infinity-map_lwp2thr.py
> @@ -0,0 +1,155 @@
> +from i8c.runtime import TestCase
> +import struct
> +
> +TestCase.import_builtin_constants()
> +TestCase.import_constants_from("infinity-nptl-constants.h")
> +TestCase.import_constants_from("infinity-nptl_db-constants.h")
> +
> +class TestMapLwp2Thr(TestCase):
> +    TESTFUNC = "libpthread::map_lwp2thr(i)ip"
> +    MAIN_PID = 30000
> +
> +    def setUp(self):
> +        # Create flags
> +        self.ps_get_register_called = False
> +        self.ps_get_thread_area_called = False
> +        # Store the address of __stack_user
> +        note = self.i8ctx.get_function(self.TESTFUNC)
> +        symbols = note.external_pointers
> +        self.assertEqual(len(symbols), 1)
> +        self.stack_user_p = symbols[0]
> +
> +    def read_memory(self, fmt, addr):
> +        # The only dereference we do is __stack_user.next
> +        self.assertEqual(addr, self.stack_user_p + LIST_T_NEXT_OFFSET)
> +        return struct.pack(fmt, self.STACK_USER_NEXT)
> +
> +    def call_i8core_getpid(self):
> +        """Implementation of i8core::getpid."""
> +        return self.MAIN_PID
> +
> +    def call_procservice_get_register(self, lwpid, offset, size):
> +        """Implementation of procservice::get_register."""
> +        self.assertFalse(self.ps_get_register_called)
> +        result = getattr(self, "PS_GETREG_RESULT", None)
> +        if result is None:
> +            self.fail("unexpected ps_get_register")
> +        self.assertEqual(lwpid, self.lwpid)
> +        self.assertNotEqual(offset, self.lwpid)
> +        self.assertGreaterEqual(offset, 0)
> +        # We can't really say much about offset.  It's an offset into
> +        # a prgregset_t structure, so it's probably not huge and it's
> +        # probably aligned to the machine's wordsize.
> +        self.assertLess(offset, 128 * 8) # =128 64-bit registers (IA-64)
> +        bytes_per_word, check = divmod(self.i8ctx.wordsize, 8)
> +        self.assertNotEqual(bytes_per_word, 0)
> +        self.assertEqual(check, 0)
> +        self.assertEqual(offset % bytes_per_word, 0)
> +        self.assertIn(size, (8, 16, 32, 64))
> +        self.assertLessEqual(size, self.i8ctx.wordsize)
> +        self.ps_get_register_called = True
> +        return result
> +
> +    def call_procservice_get_thread_area(self, lwpid, idx):
> +        """Implementation of procservice::get_thread_area."""
> +        self.assertFalse(self.ps_get_thread_area_called)
> +        result = getattr(self, "PS_GET_TA_RESULT", None)
> +        if result is None:
> +            self.fail("unexpected ps_get_thread_area")
> +        self.assertEqual(lwpid, self.lwpid)
> +        self.assertNotEqual(idx, self.lwpid)
> +        self.ps_get_thread_area_called = True
> +        return result
> +
> +    def check_I8_TS_CONST_THREAD_AREA_result(self, result):
> +        # The result is whatever ps_get_thread_area returned
> +        self.assertTrue(self.ps_get_thread_area_called)
> +        self.assertEqual(result[0], TD_OK)
> +        self.assertNotEqual(result[1], 0)
> +        self.assertEqual(result[1], self.PS_GET_TA_RESULT[1])
> +
> +    def check_I8_TS_REGISTER_result(self, result):
> +        # The result is what ps_get_register returned with some
> +        # bias added.  We'll assume the bias is fairly small.
> +        self.assertTrue(self.ps_get_register_called)
> +        self.assertEqual(result[0], TD_OK)
> +        self.assertNotEqual(result[1], 0)
> +        bias = result[1] - self.PS_GETREG_RESULT[1]
> +        self.assertLess(abs(bias), 16384)
> +
> +    def check_I8_TS_REGISTER_THREAD_AREA_result(self, result):
> +        # The result is whatever ps_get_thread_area returned
> +        self.assertTrue(self.ps_get_register_called)
> +        self.assertTrue(self.ps_get_thread_area_called)
> +        self.assertEqual(result[0], TD_OK)
> +        self.assertNotEqual(result[1], 0)
> +        self.assertEqual(result[1], self.PS_GET_TA_RESULT[1])
> +
> +class TestMapLwp2Thr_uninit(TestMapLwp2Thr):
> +    STACK_USER_NEXT = NULL
> +
> +    def test_map_lwp2thr(self):
> +        """map_lwp2thr (nptl uninitialized, lwpid == main PID)"""
> +        result = self.i8ctx.call(self.TESTFUNC, self.MAIN_PID)
> +        self.assertEqual(len(result), 2)
> +        self.assertEqual(result[0], TD_OK)
> +        self.assertEqual(result[1], NULL)
> +
> +class TestMapLwp2Thr_uninit_wrongpid(TestMapLwp2Thr):
> +    STACK_USER_NEXT = NULL
> +
> +    def test_map_lwp2thr(self):
> +        """map_lwp2thr (nptl uninitialized, lwpid != main PID)"""
> +        result = self.i8ctx.call(self.TESTFUNC, self.MAIN_PID + 1)
> +        self.assertEqual(len(result), 2)
> +        self.assertEqual(result[0], TD_ERR)
> +
> +class TestMapLwp2Thr_init_getreg_fail(TestMapLwp2Thr):
> +    STACK_USER_NEXT = 0x1fff
> +    PS_GETREG_RESULT = PS_ERR, 0x23ff00fa
> +    PS_GET_TA_RESULT = PS_OK, 0x89ab1234
> +
> +    def test_map_lwp2thr(self):
> +        """map_lwp2thr (nptl initialized, ps_get_register fails)"""
> +        self.lwpid = self.MAIN_PID + 1
> +        result = self.i8ctx.call(self.TESTFUNC, self.lwpid)
> +        self.assertEqual(len(result), 2)
> +        if self.ps_get_register_called:
> +            self.assertEqual(result[0], TD_ERR)
> +        else:
> +            # This failure isn't a problem for this platform
> +            self.check_I8_TS_CONST_THREAD_AREA_result(result)
> +
> +class TestMapLwp2Thr_init_gta_fail(TestMapLwp2Thr):
> +    STACK_USER_NEXT = 0x1fff
> +    PS_GETREG_RESULT = PS_OK, 0x23ff00fa
> +    PS_GET_TA_RESULT = PS_ERR, 0x89ab1234
> +
> +    def test_map_lwp2thr(self):
> +        """map_lwp2thr (nptl initialized, ps_get_thread_area fails)"""
> +        self.lwpid = self.MAIN_PID + 1
> +        result = self.i8ctx.call(self.TESTFUNC, self.lwpid)
> +        self.assertEqual(len(result), 2)
> +        if self.ps_get_thread_area_called:
> +            self.assertEqual(result[0], TD_ERR)
> +        else:
> +            # This failure isn't a problem for this platform
> +            self.check_I8_TS_REGISTER_result(result)
> +
> +class TestMapLwp2Thr_init_gta_ok(TestMapLwp2Thr):
> +    STACK_USER_NEXT = 0x1fff
> +    PS_GETREG_RESULT = PS_OK, 0x23ff00fa
> +    PS_GET_TA_RESULT = PS_OK, 0x89ab1234
> +
> +    def test_map_lwp2thr(self):
> +        """map_lwp2thr (nptl initialized, everything worked)"""
> +        self.lwpid = self.MAIN_PID + 1
> +        result = self.i8ctx.call(self.TESTFUNC, self.lwpid)
> +        self.assertEqual(len(result), 2)
> +        if self.ps_get_thread_area_called:
> +            if self.ps_get_register_called:
> +                self.check_I8_TS_REGISTER_THREAD_AREA_result(result)
> +            else:
> +                self.check_I8_TS_CONST_THREAD_AREA_result(result)
> +        else:
> +            self.check_I8_TS_REGISTER_result(result)
> 


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