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)
