Merge "Fix linkage of grantpt(3)."
diff --git a/libc/Android.mk b/libc/Android.mk
index d641d89..15a68b9 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -90,6 +90,7 @@
     bionic/access.cpp \
     bionic/assert.cpp \
     bionic/atof.cpp \
+    bionic/bionic_systrace.cpp \
     bionic/bionic_time_conversions.cpp \
     bionic/brk.cpp \
     bionic/c16rtomb.cpp \
diff --git a/libc/bionic/bionic_systrace.cpp b/libc/bionic/bionic_systrace.cpp
new file mode 100644
index 0000000..b8e892e
--- /dev/null
+++ b/libc/bionic/bionic_systrace.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cutils/trace.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "private/bionic_systrace.h"
+#include "private/libc_logging.h"
+
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+
+#define WRITE_OFFSET   32
+
+static const prop_info* g_pinfo = NULL;
+static uint32_t g_serial = -1;
+static uint64_t g_tags = 0;
+static int g_trace_marker_fd = -1;
+
+static bool should_trace() {
+  // If g_pinfo is null, this means that systrace hasn't been run and it's safe to
+  // assume that no trace writing will need to take place.  However, to avoid running
+  // this costly find check each time, we set it to a non-tracing value so that next
+  // time, it will just check the serial to see if the value has been changed.
+  // this function also deals with the bootup case, during which the call to property
+  // set will fail if the property server hasn't yet started.
+  if (g_pinfo == NULL) {
+    g_pinfo = __system_property_find("debug.atrace.tags.enableflags");
+    if (g_pinfo == NULL) {
+      __system_property_set("debug.atrace.tags.enableflags", "0");
+      g_pinfo = __system_property_find("debug.atrace.tags.enableflags");
+      if (g_pinfo == NULL) {
+        return false;
+      }
+    }
+  }
+
+  // Find out which tags have been enabled on the command line and set
+  // the value of tags accordingly.  If the value of the property changes,
+  // the serial will also change, so the costly system_property_read function
+  // can be avoided by calling the much cheaper system_property_serial
+  // first.  The values within pinfo may change, but its location is guaranteed
+  // not to move.
+  const uint32_t cur_serial = __system_property_serial(g_pinfo);
+  if (cur_serial != g_serial) {
+    g_serial = cur_serial;
+    char value[PROP_VALUE_MAX];
+    __system_property_read(g_pinfo, 0, value);
+    g_tags = strtoull(value, NULL, 0);
+  }
+
+  // Finally, verify that this tag value enables bionic tracing.
+  return ((g_tags & ATRACE_TAG_BIONIC) != 0);
+}
+
+ScopedTrace::ScopedTrace(const char* message) {
+  if (!should_trace()) {
+    return;
+  }
+
+  if (g_trace_marker_fd == -1) {
+    g_trace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY | O_CLOEXEC);
+    if (g_trace_marker_fd == -1) {
+      __libc_fatal("Could not open kernel trace file: %s\n", strerror(errno));
+    }
+  }
+
+  // If bionic tracing has been enabled, then write the message to the
+  // kernel trace_marker.
+  int length = strlen(message);
+  char buf[length + WRITE_OFFSET];
+  size_t len = snprintf(buf, length + WRITE_OFFSET, "B|%d|%s", getpid(), message);
+  ssize_t wbytes = TEMP_FAILURE_RETRY(write(g_trace_marker_fd, buf, len));
+
+  // Error while writing
+  if (static_cast<size_t>(wbytes) != len) {
+    __libc_fatal("Could not write to kernel trace file: %s\n", strerror(errno));
+  }
+}
+
+ScopedTrace::~ScopedTrace() {
+  if (!should_trace()) {
+    return;
+  }
+
+  ssize_t wbytes = TEMP_FAILURE_RETRY(write(g_trace_marker_fd, "E", 1));
+
+  // Error while writing
+  if (static_cast<size_t>(wbytes) != 1) {
+    __libc_fatal("Could not write to kernel trace file: %s\n", strerror(errno));
+  }
+}
diff --git a/libc/bionic/libc_logging.cpp b/libc/bionic/libc_logging.cpp
index b57e242..d0172ed 100644
--- a/libc/bionic/libc_logging.cpp
+++ b/libc/bionic/libc_logging.cpp
@@ -230,7 +230,6 @@
 /* Perform formatted output to an output target 'o' */
 template <typename Out>
 static void out_vformat(Out& o, const char* format, va_list args) {
-    int caller_errno = errno;
     int nn = 0;
 
     for (;;) {
@@ -379,9 +378,6 @@
         } else if (c == '%') {
             buffer[0] = '%';
             buffer[1] = '\0';
-        } else if (c == 'm') {
-            // syslog-like %m for strerror(errno).
-            str = strerror(caller_errno);
         } else {
             __assert(__FILE__, __LINE__, "conversion specifier unsupported");
         }
diff --git a/libc/bionic/pthread_mutex.cpp b/libc/bionic/pthread_mutex.cpp
index 5461661..e00ffb4 100644
--- a/libc/bionic/pthread_mutex.cpp
+++ b/libc/bionic/pthread_mutex.cpp
@@ -39,6 +39,8 @@
 #include "private/bionic_futex.h"
 #include "private/bionic_tls.h"
 
+#include "private/bionic_systrace.h"
+
 extern void pthread_debug_mutex_lock_check(pthread_mutex_t *mutex);
 extern void pthread_debug_mutex_unlock_check(pthread_mutex_t *mutex);
 
@@ -333,6 +335,10 @@
          * that the mutex is in state 2 when we go to sleep on it, which
          * guarantees a wake-up call.
          */
+
+         ScopedTrace trace("Contending for pthread mutex");
+
+
         while (__bionic_swap(locked_contended, &mutex->value) != unlocked) {
             __futex_wait_ex(&mutex->value, shared, locked_contended, NULL);
         }
@@ -473,6 +479,8 @@
         mvalue = mutex->value;
     }
 
+    ScopedTrace trace("Contending for pthread mutex");
+
     for (;;) {
         int newval;
 
@@ -626,6 +634,8 @@
       return 0;
     }
 
+    ScopedTrace trace("Contending for timed pthread mutex");
+
     // Loop while needed.
     while (__bionic_swap(locked_contended, &mutex->value) != unlocked) {
       if (__timespec_from_absolute(&ts, abs_timeout, clock) < 0) {
@@ -658,6 +668,8 @@
     mvalue = mutex->value;
   }
 
+  ScopedTrace trace("Contending for timed pthread mutex");
+
   while (true) {
     // If the value is 'unlocked', try to acquire it directly.
     // NOTE: put state to 2 since we know there is contention.
diff --git a/libc/bionic/syslog.cpp b/libc/bionic/syslog.cpp
index 29f892a..d8b8b19 100644
--- a/libc/bionic/syslog.cpp
+++ b/libc/bionic/syslog.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <errno.h>
 #include <stdlib.h>
 #include <syslog.h>
 
@@ -47,6 +48,8 @@
 }
 
 void vsyslog(int priority, const char* fmt, va_list args) {
+  int caller_errno = errno;
+
   // Check whether we're supposed to be logging messages of this priority.
   if ((syslog_priority_mask & LOG_MASK(LOG_PRI(priority))) == 0) {
     return;
@@ -71,5 +74,48 @@
     android_log_priority = ANDROID_LOG_DEBUG;
   }
 
-  __libc_format_log_va_list(android_log_priority, log_tag, fmt, args);
+  // glibc's printf family support %m directly, but our BSD-based one doesn't.
+  // If the format string seems to contain "%m", rewrite it.
+  const char* log_fmt = fmt;
+  if (strstr(fmt, "%m") != NULL) {
+    size_t dst_len = 1024;
+    char* dst = reinterpret_cast<char*>(malloc(dst_len));
+    log_fmt = dst;
+
+    const char* src = fmt;
+    for (; dst_len > 0 && *src != '\0'; ++src) {
+      if (*src == '%' && *(src + 1) == 'm') {
+        // Expand %m.
+        size_t n = strlcpy(dst, strerror(caller_errno), dst_len);
+        if (n >= dst_len) {
+          n = dst_len;
+        }
+        dst += n;
+        dst_len -= n;
+        ++src;
+      } else if (*src == '%' && *(src + 1) == '%') {
+        // We need to copy pairs of '%'s so the %m test works.
+        if (dst_len <= 2) {
+          break;
+        }
+        *dst++ = '%'; --dst_len;
+        *dst++ = '%'; --dst_len;
+        ++src;
+      } else {
+        *dst++ = *src; --dst_len;
+      }
+    }
+    *dst = '\0';
+  }
+
+  // We can't let __libc_format_log do the formatting because it doesn't support
+  // all the printf functionality.
+  char log_line[1024];
+  vsnprintf(log_line, sizeof(log_line), log_fmt, args);
+
+  if (log_fmt != fmt) {
+    free(const_cast<char*>(log_fmt));
+  }
+
+  __libc_format_log(android_log_priority, log_tag, "%s", log_line);
 }
diff --git a/libc/include/sys/syscall.h b/libc/include/sys/syscall.h
index a44b2e5..34a29df 100644
--- a/libc/include/sys/syscall.h
+++ b/libc/include/sys/syscall.h
@@ -37,7 +37,7 @@
 
 __BEGIN_DECLS
 
-int syscall(int number, ...);
+long syscall(long number, ...);
 
 __END_DECLS
 
diff --git a/libc/private/bionic_systrace.h b/libc/private/bionic_systrace.h
new file mode 100644
index 0000000..ad9ff7f
--- /dev/null
+++ b/libc/private/bionic_systrace.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BIONIC_SYSTRACE_H
+#define BIONIC_SYSTRACE_H
+
+#include "bionic_macros.h"
+
+// Tracing class for bionic. To begin a trace at a specified point:
+//   ScopedTrace("Trace message");
+// The trace will end when the contructor goes out of scope.
+
+class ScopedTrace {
+ public:
+  explicit ScopedTrace(const char* message);
+  ~ScopedTrace();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ScopedTrace);
+};
+
+#endif
diff --git a/libc/tzcode/localtime.c b/libc/tzcode/localtime.c
index 2e6804e..5e4e962 100644
--- a/libc/tzcode/localtime.c
+++ b/libc/tzcode/localtime.c
@@ -2310,20 +2310,4 @@
   return return_value;
 }
 
-// Non-standard API: localtime(3) but with an explicit timezone parameter.
-#if !defined(__LP64__)
-__attribute__((visibility("default"))) void localtime_tz(const time_t* const timep, struct tm* tmp, const char* tz) {
-  struct state* st = malloc(sizeof(*st));
-
-  if (st == NULL)
-    return;
-  if (__bionic_tzload_cached(tz, st, TRUE) != 0) {
-    // TODO: not sure what's best here, but for now, we fall back to gmt.
-    gmtload(st);
-  }
-  localsub(timep, 0L, tmp, st);
-  free(st);
-}
-#endif
-
 // END android-added
diff --git a/libc/tzcode/strftime.c b/libc/tzcode/strftime.c
index c4ff198..4328b4c 100644
--- a/libc/tzcode/strftime.c
+++ b/libc/tzcode/strftime.c
@@ -30,25 +30,6 @@
 
 #if __ANDROID__
 
-/*
- * This has an extra standalone_month array field compared to upstream.
- * We only need to keep that if we leave the strftime_tz symbol exposed.
- * Even then, this structure was never in an NDK header file.
- */
-struct lc_time_T {
-  const char *  mon[12];
-  const char *  month[12];
-  const char *  standalone_month[12];
-  const char *  wday[7];
-  const char *  weekday[7];
-  const char *  X_fmt;
-  const char *  x_fmt;
-  const char *  c_fmt;
-  const char *  am;
-  const char *  pm;
-  const char *  date_fmt;
-};
-
 /* LP32 had a 32-bit time_t, so we need to work around that here. */
 #if defined(__LP64__)
 #define time64_t time_t
@@ -59,9 +40,8 @@
 
 #include <ctype.h>
 
-size_t strftime_tz(char*, size_t, const char*, const struct tm*, const struct lc_time_T*);
+#endif
 
-#else // not __ANDROID__
 struct lc_time_T {
     const char *    mon[MONSPERYEAR];
     const char *    month[MONSPERYEAR];
@@ -74,9 +54,8 @@
     const char *    pm;
     const char *    date_fmt;
 };
-#endif
 
-#if LOCALE_HOME
+#ifdef LOCALE_HOME
 #include "sys/stat.h"
 static struct lc_time_T                localebuf;
 static struct lc_time_T *      _loc(void);
@@ -94,9 +73,6 @@
         "January", "February", "March", "April", "May", "June",
         "July", "August", "September", "October", "November", "December"
     }, {
-        "January", "February", "March", "April", "May", "June",
-        "July", "August", "September", "October", "November", "December"
-    }, {
         "Sun", "Mon", "Tue", "Wed",
         "Thu", "Fri", "Sat"
     }, {
@@ -138,7 +114,7 @@
 static char *   _add(const char *, char *, const char *, int);
 static char *   _conv(int, const char *, char *, const char *);
 static char *   _fmt(const char *, const struct tm *, char *, const char *,
-            int *, const struct lc_time_T*);
+            int *);
 static char *   _yconv(int, int, int, int, char *, const char *, int);
 static char *   getformat(int, char *, char *, char *, char *);
 
@@ -156,28 +132,18 @@
 #define FORCE_LOWER_CASE 0x100
 
 size_t
-strftime(s, maxsize, format, t)
-char * const        s;
-const size_t        maxsize;
-const char * const  format;
-const struct tm * const t;
-{
-    return strftime_tz(s, maxsize, format, t, Locale);
-}
-
-__LIBC64_HIDDEN__ size_t strftime_tz(s, maxsize, format, t, locale)
-char * const        s;
-const size_t        maxsize;
-const char * const  format;
-const struct tm * const t;
-const struct lc_time_T *locale;
+strftime(char * const s, const size_t maxsize, const char *const format,
+        const struct tm *const t)
 {
     char *  p;
     int warn;
 
     tzset();
+#ifdef LOCALE_HOME
+    localebuf.mon[0] = 0;
+#endif /* defined LOCALE_HOME */
     warn = IN_NONE;
-    p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn, locale);
+    p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn);
 #ifndef NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU
     if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) {
         (void) fprintf(stderr, "\n");
@@ -217,13 +183,8 @@
 }
 
 static char *
-_fmt(format, t, pt, ptlim, warnp, locale)
-const char *        format;
-const struct tm * const t;
-char *          pt;
-const char * const  ptlim;
-int *           warnp;
-const struct lc_time_T* locale;
+_fmt(const char *format, const struct tm *const t, char * pt,
+        const char *const ptlim, int *warnp)
 {
     for ( ; *format; ++format) {
         if (*format == '%') {
@@ -236,33 +197,26 @@
             case 'A':
                 pt = _add((t->tm_wday < 0 ||
                     t->tm_wday >= DAYSPERWEEK) ?
-                    "?" : locale->weekday[t->tm_wday],
+                    "?" : Locale->weekday[t->tm_wday],
                     pt, ptlim, modifier);
                 continue;
             case 'a':
                 pt = _add((t->tm_wday < 0 ||
                     t->tm_wday >= DAYSPERWEEK) ?
-                    "?" : locale->wday[t->tm_wday],
+                    "?" : Locale->wday[t->tm_wday],
                     pt, ptlim, modifier);
                 continue;
             case 'B':
-                if (modifier == '-') {
-                    pt = _add((t->tm_mon < 0 ||
+                pt = _add((t->tm_mon < 0 ||
                                 t->tm_mon >= MONSPERYEAR) ?
-                                "?" : locale->standalone_month[t->tm_mon],
+                                "?" : Locale->month[t->tm_mon],
                                 pt, ptlim, modifier);
-                } else {
-                    pt = _add((t->tm_mon < 0 ||
-                                t->tm_mon >= MONSPERYEAR) ?
-                                "?" : locale->month[t->tm_mon],
-                                pt, ptlim, modifier);
-                }
                 continue;
             case 'b':
             case 'h':
                 pt = _add((t->tm_mon < 0 ||
                     t->tm_mon >= MONSPERYEAR) ?
-                    "?" : locale->mon[t->tm_mon],
+                    "?" : Locale->mon[t->tm_mon],
                     pt, ptlim, modifier);
                 continue;
             case 'C':
@@ -280,7 +234,7 @@
                 {
                 int warn2 = IN_SOME;
 
-                pt = _fmt(locale->c_fmt, t, pt, ptlim, warnp, locale);
+                pt = _fmt(Locale->c_fmt, t, pt, ptlim, &warn2);
                 if (warn2 == IN_ALL)
                     warn2 = IN_THIS;
                 if (warn2 > *warnp)
@@ -288,7 +242,7 @@
                 }
                 continue;
             case 'D':
-                                pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp, locale);
+                                pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp);
                 continue;
             case 'd':
                                 pt = _conv(t->tm_mday,
@@ -322,7 +276,7 @@
                                            pt, ptlim);
                 continue;
             case 'F':
-                pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp, locale);
+                pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp);
                 continue;
             case 'H':
                 pt = _conv(t->tm_hour,
@@ -363,7 +317,7 @@
                 /*
                 ** After all this time, still unclaimed!
                 */
-                pt = _add("kitchen sink", pt, ptlim, modifier);
+                pt = _add("kitchen sink", pt, ptlim);
                 continue;
 #endif /* defined KITCHEN_SINK */
             case 'l':
@@ -399,21 +353,21 @@
                 continue;
             case 'p':
                 pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
-                    locale->pm :
-                    locale->am,
+                    Locale->pm :
+                    Locale->am,
                     pt, ptlim, modifier);
                 continue;
             case 'P':
                 pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
-                    locale->pm :
-                    locale->am,
+                    Locale->pm :
+                    Locale->am,
                     pt, ptlim, FORCE_LOWER_CASE);
                 continue;
             case 'R':
-                pt = _fmt("%H:%M", t, pt, ptlim, warnp, locale);
+                pt = _fmt("%H:%M", t, pt, ptlim, warnp);
                 continue;
             case 'r':
-                pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp, locale);
+                pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp);
                 continue;
             case 'S':
                 pt = _conv(t->tm_sec,
@@ -439,7 +393,7 @@
                 }
                 continue;
             case 'T':
-                pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp, locale);
+                pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp);
                 continue;
             case 't':
                 pt = _add("\t", pt, ptlim, modifier);
@@ -470,7 +424,7 @@
 ** (01-53)."
 ** (ado, 1993-05-24)
 **
-** From "http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html" by Markus Kuhn:
+** From <http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html> by Markus Kuhn:
 ** "Week 01 of a year is per definition the first week which has the
 ** Thursday in this year, which is equivalent to the week which contains
 ** the fourth day of January. In other words, the first week of a new year
@@ -540,11 +494,7 @@
 #endif /* defined XPG4_1994_04_09 */
                     if (*format == 'V')
                         pt = _conv(w,
-                                                           getformat(modifier,
-                                                                     "%02d",
-                                                                     "%2d",
-                                                                     "%d",
-                                                                     "%02d"),
+                                getformat(modifier, "%02d", "%2d", "%d", "%02d"),
                                pt, ptlim);
                     else if (*format == 'g') {
                         *warnp = IN_ALL;
@@ -560,7 +510,7 @@
                 ** "date as dd-bbb-YYYY"
                 ** (ado, 1993-05-24)
                 */
-                pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp, locale);
+                pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp);
                 continue;
             case 'W':
                 pt = _conv((t->tm_yday + DAYSPERWEEK -
@@ -575,13 +525,13 @@
                 pt = _conv(t->tm_wday, "%d", pt, ptlim);
                 continue;
             case 'X':
-                pt = _fmt(locale->X_fmt, t, pt, ptlim, warnp, locale);
+                pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp);
                 continue;
             case 'x':
                 {
                 int warn2 = IN_SOME;
 
-                pt = _fmt(locale->x_fmt, t, pt, ptlim, &warn2, locale);
+                pt = _fmt(Locale->x_fmt, t, pt, ptlim, &warn2);
                 if (warn2 == IN_ALL)
                     warn2 = IN_THIS;
                 if (warn2 > *warnp)
@@ -670,8 +620,8 @@
                 }
                 continue;
             case '+':
-                pt = _fmt(locale->date_fmt, t, pt, ptlim,
-                    warnp, locale);
+                pt = _fmt(Locale->date_fmt, t, pt, ptlim,
+                    warnp);
                 continue;
             case '%':
             /*
@@ -691,11 +641,8 @@
 }
 
 static char *
-_conv(n, format, pt, ptlim)
-const int       n;
-const char * const  format;
-char * const        pt;
-const char * const  ptlim;
+_conv(const int n, const char *const format, char *const pt,
+        const char *const ptlim)
 {
     char    buf[INT_STRLEN_MAXIMUM(int) + 1];
 
@@ -704,11 +651,7 @@
 }
 
 static char *
-_add(str, pt, ptlim, modifier)
-const char *        str;
-char *          pt;
-const char * const  ptlim;
-int                     modifier;
+_add(const char *str, char *pt, const char *const ptlim, int modifier)
 {
         int c;
 
@@ -756,14 +699,8 @@
 */
 
 static char *
-_yconv(a, b, convert_top, convert_yy, pt, ptlim, modifier)
-const int       a;
-const int       b;
-const int       convert_top;
-const int       convert_yy;
-char *          pt;
-const char * const  ptlim;
-int                     modifier;
+_yconv(const int a, const int b, const int convert_top, const int convert_yy,
+        char *pt, const char *const ptlim, int modifier)
 {
     register int    lead;
     register int    trail;
@@ -782,13 +719,9 @@
     if (convert_top) {
         if (lead == 0 && trail < 0)
             pt = _add("-0", pt, ptlim, modifier);
-        else    pt = _conv(lead, getformat(modifier, "%02d",
-                                                   "%2d", "%d", "%02d"),
-                                   pt, ptlim);
+        else    pt = _conv(lead, getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
     }
     if (convert_yy)
-        pt = _conv(((trail < 0) ? -trail : trail),
-                           getformat(modifier, "%02d", "%2d", "%d", "%02d"),
-                           pt, ptlim);
+        pt = _conv(((trail < 0) ? -trail : trail), getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
     return pt;
 }
diff --git a/linker/arch/mips/begin.S b/linker/arch/mips/begin.S
index 4a855e6..cbe1e37 100644
--- a/linker/arch/mips/begin.S
+++ b/linker/arch/mips/begin.S
@@ -32,7 +32,9 @@
 
     .ent    __start
     .globl    __start
+    .globl    _start
 __start:
+_start:
     .set    noreorder
     bal    1f
     nop
diff --git a/linker/arch/mips64/begin.S b/linker/arch/mips64/begin.S
index 6827a2c..8f6b94a 100644
--- a/linker/arch/mips64/begin.S
+++ b/linker/arch/mips64/begin.S
@@ -46,7 +46,9 @@
 
     .ent	__start
     .globl	__start
+    .globl	_start
 __start:
+_start:
     .set	noreorder
     bal		1f
      nop
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 4c76594..59b9938 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -2221,6 +2221,8 @@
   return 0;
 }
 
+extern "C" void _start();
+
 /*
  * This is the entry point for the linker, called from begin.S. This
  * method is responsible for fixing the linker's own relocations, and
@@ -2238,12 +2240,23 @@
   KernelArgumentBlock args(raw_args);
 
   ElfW(Addr) linker_addr = args.getauxval(AT_BASE);
+  ElfW(Addr) entry_point = args.getauxval(AT_ENTRY);
   ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr);
   ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff);
 
   soinfo linker_so;
   memset(&linker_so, 0, sizeof(soinfo));
 
+  // If the linker is not acting as PT_INTERP entry_point is equal to
+  // _start. Which means that the linker is running as an executable and
+  // already linked by PT_INTERP.
+  //
+  // This happens when user tries to run 'adb shell /system/bin/linker'
+  // see also https://code.google.com/p/android/issues/detail?id=63174
+  if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) {
+    __libc_fatal("This is %s, the helper program for shared library executables.\n", args.argv[0]);
+  }
+
   strcpy(linker_so.name, "[dynamic linker]");
   linker_so.base = linker_addr;
   linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum);
@@ -2265,7 +2278,7 @@
     _exit(EXIT_FAILURE);
   }
 
-  // lets properly initialize global variables
+  // Initialize the linker's own global variables
   linker_so.CallConstructors();
 
   // We have successfully fixed our own relocations. It's safe to run
diff --git a/tests/libc_logging_test.cpp b/tests/libc_logging_test.cpp
index ef39d1c..950161e 100644
--- a/tests/libc_logging_test.cpp
+++ b/tests/libc_logging_test.cpp
@@ -176,14 +176,3 @@
   GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif // __BIONIC__
 }
-
-TEST(libc_logging, m) {
-#if defined(__BIONIC__)
-  char buf[BUFSIZ];
-  errno = EBADF;
-  __libc_format_buffer(buf, sizeof(buf), "<%m>");
-  EXPECT_STREQ("<Bad file number>", buf);
-#else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif // __BIONIC__
-}
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 58c9ad9..2a65657 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -20,6 +20,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <limits.h>
 #include <stdint.h>
 #include <unistd.h>
 #include <sys/syscall.h>
@@ -212,6 +213,14 @@
   ASSERT_EQ(EBADF, errno);
 }
 
+TEST(unistd, syscall_long) {
+  // Check that syscall(3) correctly returns long results.
+  // https://code.google.com/p/android/issues/detail?id=73952
+  // We assume that the break is > 4GiB, but this is potentially flaky.
+  uintptr_t p = reinterpret_cast<uintptr_t>(sbrk(0));
+  ASSERT_EQ(p, static_cast<uintptr_t>(syscall(__NR_brk, 0)));
+}
+
 TEST(unistd, alarm) {
   ASSERT_EQ(0U, alarm(0));
 }