Track whether a thread is currently vforked.

Our various fd debugging facilities get extremely confused by a vforked
process closing file descriptors in preparation to exec: fdsan can
abort, and fdtrack will delete backtraces for any file descriptors that
get closed. Keep track of whether we're in a vforked child in order to
be able to detect this.

Bug: http://b/153926671
Test: 32/64-bit bionic-unit-tests on blueline, x86_64 emulator
Change-Id: I8a082fd06bfdfef0e2a88dbce350b6f667f7df9f
diff --git a/libc/arch-x86/bionic/vfork.S b/libc/arch-x86/bionic/vfork.S
index 663169c..231a36e 100644
--- a/libc/arch-x86/bionic/vfork.S
+++ b/libc/arch-x86/bionic/vfork.S
@@ -37,13 +37,25 @@
   .cfi_adjust_cfa_offset 4
   .cfi_rel_offset ecx, 0
 
-  // __get_tls()[TLS_SLOT_THREAD_ID]->cached_pid_ = 0
+  // Set cached_pid_ to 0, vforked_ to 1, and stash the previous value.
   movl    %gs:0, %eax
   movl    (TLS_SLOT_THREAD_ID * 4)(%eax), %eax
-  movl    $0, 12(%eax)
+  movl    12(%eax), %edx
+  movl    $0x80000000, 12(%eax)
 
   movl    $__NR_vfork, %eax
   int     $0x80
+
+  test    %eax, %eax
+  jz      1f
+
+  // rc != 0: restore the previous cached_pid_/vforked_ values.
+  pushl   %ecx
+  movl    %gs:0, %ecx
+  movl    (TLS_SLOT_THREAD_ID * 4)(%ecx), %ecx
+  movl    %edx, 12(%ecx)
+  popl    %ecx
+
   cmpl    $-MAX_ERRNO, %eax
   jb      1f
   negl    %eax