From: Petar Jovanovic Date: Mon, 30 Jan 2017 19:33:47 +0000 (+0000) Subject: mips: implement calculation for static TLS X-Git-Tag: svn/VALGRIND_3_13_0~206 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1f203e73de353c9dad77a4d8b95bd992efb8b27a;p=thirdparty%2Fvalgrind.git mips: implement calculation for static TLS Extend valgrind_get_tls_addr() with static TLS calculation for MIPS. Related issue #375514. Patch by Aleksandar Rikalo. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@16215 --- diff --git a/NEWS b/NEWS index 609e4434f7..96f8c3334c 100644 --- a/NEWS +++ b/NEWS @@ -110,6 +110,7 @@ where XXXXXX is the bug number as listed below. 373192 Calling posix_spawn in glibc 2.24 completely broken 373555 Rename BBPTR to GSPTR as it denotes guest state pointer only 373938 const IRExpr arguments for matchIRExpr() +375514 valgrind_get_tls_addr() does not work in case of static TLS Release 3.12.0 (20 October 2016) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/coregrind/m_gdbserver/target.c b/coregrind/m_gdbserver/target.c index 488730a0f9..f71eaf3ef5 100644 --- a/coregrind/m_gdbserver/target.c +++ b/coregrind/m_gdbserver/target.c @@ -716,9 +716,48 @@ Bool valgrind_get_tls_addr (ThreadState *tst, // Check we can access the dtv entry for modid CHECK_DEREF(dtv + 2 * modid, sizeof(CORE_ADDR), "dtv[2*modid]"); - // And finally compute the address of the tls variable. - *tls_addr = *(dtv + 2 * modid) + offset; - + // Compute the base address of the tls block. + *tls_addr = *(dtv + 2 * modid); + +#if defined(VGA_mips32) || defined(VGA_mips64) + if (*tls_addr & 1) { + /* This means that computed address is not valid, most probably + because given module uses Static TLS. + However, the best we can is to try to compute address using + static TLS. This is what libthread_db does. + Ref. GLIBC/nptl_db/td_thr_tlsbase.c:td_thr_tlsbase(). + */ + + CORE_ADDR tls_offset_addr; + PtrdiffT tls_offset; + + dlog(1, "computing tls_addr using static TLS\n"); + + /* Assumes that tls_offset is placed right before tls_modid. + To check the assumption, start a gdb on none/tests/tls and do: + p &((struct link_map*)0x0)->l_tls_modid + p &((struct link_map*)0x0)->l_tls_offset */ + tls_offset_addr = lm + lm_modid_offset - sizeof(PtrdiffT); + + // Check we can read the tls_offset. + CHECK_DEREF(tls_offset_addr, sizeof(PtrdiffT), "link_map tls_offset"); + tls_offset = *(PtrdiffT *)(tls_offset_addr); + + /* Following two values represent platform dependent constants + NO_TLS_OFFSET and FORCED_DYNAMIC_TLS_OFFSET, respectively. */ + if ((tls_offset == -1) || (tls_offset == -2)) { + dlog(2, "link_map tls_offset is not valid for static TLS\n"); + return False; + } + + // This calculation is also platform dependent. + *tls_addr = ((CORE_ADDR)dtv_loc + 2 * sizeof(CORE_ADDR) + tls_offset); + } +#endif + + // Finally, add tls variable offset to tls block base address. + *tls_addr += offset; + return True; #undef CHECK_DEREF