Merge "Copy the entire zero-separated DNS seach domain string."
diff --git a/libc/Android.bp b/libc/Android.bp
index ca926d6..89a41cb 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -23,38 +23,6 @@
     "stdio/stdio_ext.cpp",
     "stdlib/atexit.c",
     "stdlib/exit.c",
-
-    // Fortify implementations of libc functions.
-    "bionic/__FD_chk.cpp",
-    "bionic/__fgets_chk.cpp",
-    "bionic/__fread_chk.cpp",
-    "bionic/__fwrite_chk.cpp",
-    "bionic/__getcwd_chk.cpp",
-    "bionic/__memchr_chk.cpp",
-    "bionic/__memmove_chk.cpp",
-    "bionic/__memrchr_chk.cpp",
-    "bionic/__poll_chk.cpp",
-    "bionic/__pread64_chk.cpp",
-    "bionic/__pread_chk.cpp",
-    "bionic/__pwrite64_chk.cpp",
-    "bionic/__pwrite_chk.cpp",
-    "bionic/__read_chk.cpp",
-    "bionic/__readlink_chk.cpp",
-    "bionic/__readlinkat_chk.cpp",
-    "bionic/__recvfrom_chk.cpp",
-    "bionic/__stpcpy_chk.cpp",
-    "bionic/__stpncpy_chk.cpp",
-    "bionic/__strchr_chk.cpp",
-    "bionic/__strlcat_chk.cpp",
-    "bionic/__strlcpy_chk.cpp",
-    "bionic/__strlen_chk.cpp",
-    "bionic/__strncat_chk.cpp",
-    "bionic/__strncpy_chk.cpp",
-    "bionic/__strrchr_chk.cpp",
-    "bionic/__umask_chk.cpp",
-    "bionic/__vsnprintf_chk.cpp",
-    "bionic/__vsprintf_chk.cpp",
-    "bionic/__write_chk.cpp",
 ]
 
 // Various kinds of cruft.
@@ -102,11 +70,6 @@
     include_dirs: ["external/jemalloc/include"],
 
     arch: {
-        // Clang/llvm has incompatible long double (fp128) for x86_64.
-        // https://llvm.org/bugs/show_bug.cgi?id=23897
-        x86_64: {
-            clang: false,
-        },
         // b/25291096, Clang/llvm compiled libc.so for mips/mips64 failed to boot.
         mips: {
             clang: false,
@@ -148,7 +111,7 @@
             srcs: ["arch-arm64/bionic/__set_tls.c"],
         },
         x86: {
-            srcs: ["arch-x86/bionic/__set_tls.c"],
+            srcs: ["arch-x86/bionic/__set_tls.cpp"],
         },
         x86_64: {
             srcs: ["arch-x86_64/bionic/__set_tls.c"],
@@ -385,6 +348,7 @@
     cflags: [
         "-Wno-sign-compare",
         "-Wno-uninitialized",
+        "-Wno-unused-parameter",
         "-DPOSIX_MISTAKE",
         "-include netbsd-compat.h",
     ],
@@ -1114,6 +1078,7 @@
                 "arch-mips/bionic/bzero.S",
                 "arch-mips/bionic/cacheflush.cpp",
                 "arch-mips/bionic/_exit_with_stack_teardown.S",
+                "arch-mips/bionic/libgcc_compat.c",
                 "arch-mips/bionic/setjmp.S",
                 "arch-mips/bionic/syscall.S",
                 "arch-mips/bionic/vfork.S",
@@ -1317,6 +1282,7 @@
         "bionic/fgetxattr.cpp",
         "bionic/flistxattr.cpp",
         "bionic/flockfile.cpp",
+        "bionic/fortify.cpp",
         "bionic/fpclassify.cpp",
         "bionic/fsetxattr.cpp",
         "bionic/ftruncate.cpp",
diff --git a/libc/malloc_debug/Config.cpp b/libc/malloc_debug/Config.cpp
index ce83aa4..4586fda3 100644
--- a/libc/malloc_debug/Config.cpp
+++ b/libc/malloc_debug/Config.cpp
@@ -44,6 +44,26 @@
 #include "Config.h"
 #include "debug_log.h"
 
+// Config constants
+static constexpr uint8_t DEFAULT_FILL_ALLOC_VALUE = 0xeb;
+static constexpr uint8_t DEFAULT_FILL_FREE_VALUE = 0xef;
+
+static constexpr uint8_t DEFAULT_FRONT_GUARD_VALUE = 0xaa;
+static constexpr uint8_t DEFAULT_REAR_GUARD_VALUE = 0xbb;
+
+// Used as the default for all guard values.
+static constexpr size_t DEFAULT_GUARD_BYTES = 32;
+static constexpr size_t MAX_GUARD_BYTES = 16384;
+
+static constexpr size_t DEFAULT_BACKTRACE_FRAMES = 16;
+static constexpr size_t MAX_BACKTRACE_FRAMES = 256;
+
+static constexpr size_t DEFAULT_EXPAND_BYTES = 16;
+static constexpr size_t MAX_EXPAND_BYTES = 16384;
+
+static constexpr size_t DEFAULT_FREE_TRACK_ALLOCATIONS = 100;
+static constexpr size_t MAX_FREE_TRACK_ALLOCATIONS = 16384;
+
 struct Feature {
   Feature(std::string name, size_t default_value, size_t min_value, size_t max_value,
           uint64_t option, size_t* value, bool* config, bool combo_option)
@@ -72,12 +92,6 @@
 
   void LogUsage();
 
-  static constexpr uint8_t DEFAULT_FILL_ALLOC_VALUE = 0xeb;
-  static constexpr uint8_t DEFAULT_FILL_FREE_VALUE = 0xef;
-
-  static constexpr uint8_t DEFAULT_FRONT_GUARD_VALUE = 0xaa;
-  static constexpr uint8_t DEFAULT_REAR_GUARD_VALUE = 0xbb;
-
  private:
   const char* cur_ = nullptr;
 
@@ -144,28 +158,31 @@
   error_log("  front_guard[=XX]");
   error_log("    Enables a front guard on all allocations. If XX is set");
   error_log("    it sets the number of bytes in the guard. The default is");
-  error_log("    32 bytes.");
+  error_log("    %zu bytes, the max bytes is %zu.", DEFAULT_GUARD_BYTES, MAX_GUARD_BYTES);
   error_log("");
   error_log("  rear_guard[=XX]");
   error_log("    Enables a rear guard on all allocations. If XX is set");
   error_log("    it sets the number of bytes in the guard. The default is");
-  error_log("    32 bytes.");
+  error_log("    %zu bytes, the max bytes is %zu.", DEFAULT_GUARD_BYTES, MAX_GUARD_BYTES);
   error_log("");
   error_log("  guard[=XX]");
   error_log("    Enables both a front guard and a rear guard on all allocations.");
   error_log("    If XX is set it sets the number of bytes in both guards.");
-  error_log("    The default is 32 bytes.");
+  error_log("    The default is %zu bytes, the max bytes is %zu.",
+            DEFAULT_GUARD_BYTES, MAX_GUARD_BYTES);
   error_log("");
   error_log("  backtrace[=XX]");
   error_log("    Enable capturing the backtrace at the point of allocation.");
   error_log("    If XX is set it sets the number of backtrace frames.");
-  error_log("    The default is 16 frames.");
+  error_log("    The default is %zu frames, the max number of frames is %zu.",
+            DEFAULT_BACKTRACE_FRAMES, MAX_BACKTRACE_FRAMES);
   error_log("");
   error_log("  backtrace_enable_on_signal[=XX]");
   error_log("    Enable capturing the backtrace at the point of allocation.");
   error_log("    The backtrace capture is not enabled until the process");
   error_log("    receives a signal. If XX is set it sets the number of backtrace");
-  error_log("    frames. The default is 16 frames.");
+  error_log("    frames. The default is %zu frames, the max number of frames is %zu.",
+            DEFAULT_BACKTRACE_FRAMES, MAX_BACKTRACE_FRAMES);
   error_log("");
   error_log("  fill_on_alloc[=XX]");
   error_log("    On first allocation, fill with the value 0x%02x.", DEFAULT_FILL_ALLOC_VALUE);
@@ -188,7 +205,8 @@
   error_log("  expand_alloc[=XX]");
   error_log("    Allocate an extra number of bytes for every allocation call.");
   error_log("    If XX is set, that is the number of bytes to expand the");
-  error_log("    allocation by. The default is 16 bytes.");
+  error_log("    allocation by. The default is %zu bytes, the max bytes is %zu.",
+            DEFAULT_EXPAND_BYTES, MAX_EXPAND_BYTES);
   error_log("");
   error_log("  free_track[=XX]");
   error_log("    When a pointer is freed, do not free the memory right away.");
@@ -197,14 +215,17 @@
   error_log("    allocations exceeds the XX amount. When the program terminates,");
   error_log("    the rest of these allocations are verified. When this option is");
   error_log("    enabled, it automatically records the backtrace at the time of the free.");
-  error_log("    The default is to record 100 allocations.");
+  error_log("    The default is to record %zu allocations, the max allocations",
+            DEFAULT_FREE_TRACK_ALLOCATIONS);
+  error_log("    to record is %zu.", MAX_FREE_TRACK_ALLOCATIONS);
   error_log("");
   error_log("  free_track_backtrace_num_frames[=XX]");
   error_log("    This option only has meaning if free_track is set. This indicates");
   error_log("    how many backtrace frames to capture when an allocation is freed.");
   error_log("    If XX is set, that is the number of frames to capture. If XX");
   error_log("    is set to zero, then no backtrace will be captured.");
-  error_log("    The default is to record 16 frames.");
+  error_log("    The default is to record %zu frames, the max number of frames is %zu.",
+            DEFAULT_BACKTRACE_FRAMES, MAX_BACKTRACE_FRAMES);
   error_log("");
   error_log("  leak_track");
   error_log("    Enable the leak tracking of memory allocations.");
@@ -248,10 +269,10 @@
   }
 
   // Initialize a few default values.
-  fill_alloc_value = PropertyParser::DEFAULT_FILL_ALLOC_VALUE;
-  fill_free_value = PropertyParser::DEFAULT_FILL_FREE_VALUE;
-  front_guard_value = PropertyParser::DEFAULT_FRONT_GUARD_VALUE;
-  rear_guard_value = PropertyParser::DEFAULT_REAR_GUARD_VALUE;
+  fill_alloc_value = DEFAULT_FILL_ALLOC_VALUE;
+  fill_free_value = DEFAULT_FILL_FREE_VALUE;
+  front_guard_value = DEFAULT_FRONT_GUARD_VALUE;
+  rear_guard_value = DEFAULT_REAR_GUARD_VALUE;
   backtrace_signal = SIGRTMIN + 10;
   free_track_backtrace_num_frames = 16;
 
@@ -260,19 +281,22 @@
 
   // Supported features:
   const Feature features[] = {
-    Feature("guard", 32, 1, 16384, 0, nullptr, nullptr, true),
+    Feature("guard", DEFAULT_GUARD_BYTES, 1, MAX_GUARD_BYTES, 0, nullptr, nullptr, true),
     // Enable front guard. Value is the size of the guard.
-    Feature("front_guard", 32, 1, 16384, FRONT_GUARD, &this->front_guard_bytes, nullptr, true),
+    Feature("front_guard", DEFAULT_GUARD_BYTES, 1, MAX_GUARD_BYTES, FRONT_GUARD,
+            &this->front_guard_bytes, nullptr, true),
     // Enable end guard. Value is the size of the guard.
-    Feature("rear_guard", 32, 1, 16384, REAR_GUARD, &this->rear_guard_bytes, nullptr, true),
+    Feature("rear_guard", DEFAULT_GUARD_BYTES, 1, MAX_GUARD_BYTES, REAR_GUARD,
+            &this->rear_guard_bytes, nullptr, true),
 
     // Enable logging the backtrace on allocation. Value is the total
     // number of frames to log.
-    Feature("backtrace", 16, 1, 256, BACKTRACE | TRACK_ALLOCS, &this->backtrace_frames,
-            &this->backtrace_enabled, false),
+    Feature("backtrace", DEFAULT_BACKTRACE_FRAMES, 1, MAX_BACKTRACE_FRAMES,
+            BACKTRACE | TRACK_ALLOCS, &this->backtrace_frames, &this->backtrace_enabled, false),
     // Enable gathering backtrace values on a signal.
-    Feature("backtrace_enable_on_signal", 16, 1, 256, BACKTRACE | TRACK_ALLOCS,
-            &this->backtrace_frames, &this->backtrace_enable_on_signal, false),
+    Feature("backtrace_enable_on_signal", DEFAULT_BACKTRACE_FRAMES, 1, MAX_BACKTRACE_FRAMES,
+            BACKTRACE | TRACK_ALLOCS, &this->backtrace_frames, &this->backtrace_enable_on_signal,
+            false),
 
     Feature("fill", SIZE_MAX, 1, SIZE_MAX, 0, nullptr, nullptr, true),
     // Fill the allocation with an arbitrary pattern on allocation.
@@ -287,18 +311,18 @@
 
     // Expand the size of every alloc by this number bytes. Value is
     // the total number of bytes to expand every allocation by.
-    Feature ("expand_alloc", 16, 1, 16384, EXPAND_ALLOC, &this->expand_alloc_bytes,
-             nullptr, false),
+    Feature ("expand_alloc", DEFAULT_EXPAND_BYTES, 1, MAX_EXPAND_BYTES, EXPAND_ALLOC,
+             &this->expand_alloc_bytes, nullptr, false),
 
     // Keep track of the freed allocations and verify at a later date
     // that they have not been used. Turning this on, also turns on
     // fill on free.
-    Feature("free_track", 100, 1, 16384, FREE_TRACK | FILL_ON_FREE, &this->free_track_allocations,
-            nullptr, false),
+    Feature("free_track", DEFAULT_FREE_TRACK_ALLOCATIONS, 1, MAX_FREE_TRACK_ALLOCATIONS,
+            FREE_TRACK | FILL_ON_FREE, &this->free_track_allocations, nullptr, false),
     // Number of backtrace frames to keep when free_track is enabled. If this
     // value is set to zero, no backtrace will be kept.
-    Feature("free_track_backtrace_num_frames", 16, 0, 256, 0,
-            &this->free_track_backtrace_num_frames, nullptr, false),
+    Feature("free_track_backtrace_num_frames", DEFAULT_BACKTRACE_FRAMES,
+            0, MAX_BACKTRACE_FRAMES, 0, &this->free_track_backtrace_num_frames, nullptr, false),
 
     // Enable printing leaked allocations.
     Feature("leak_track", 0, 0, 0, LEAK_TRACK | TRACK_ALLOCS, nullptr, nullptr, false),
diff --git a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
index b8535e1..a6cea98 100644
--- a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
@@ -51,28 +51,28 @@
   "6 malloc_debug   front_guard[=XX]\n"
   "6 malloc_debug     Enables a front guard on all allocations. If XX is set\n"
   "6 malloc_debug     it sets the number of bytes in the guard. The default is\n"
-  "6 malloc_debug     32 bytes.\n"
+  "6 malloc_debug     32 bytes, the max bytes is 16384.\n"
   "6 malloc_debug \n"
   "6 malloc_debug   rear_guard[=XX]\n"
   "6 malloc_debug     Enables a rear guard on all allocations. If XX is set\n"
   "6 malloc_debug     it sets the number of bytes in the guard. The default is\n"
-  "6 malloc_debug     32 bytes.\n"
+  "6 malloc_debug     32 bytes, the max bytes is 16384.\n"
   "6 malloc_debug \n"
   "6 malloc_debug   guard[=XX]\n"
   "6 malloc_debug     Enables both a front guard and a rear guard on all allocations.\n"
   "6 malloc_debug     If XX is set it sets the number of bytes in both guards.\n"
-  "6 malloc_debug     The default is 32 bytes.\n"
+  "6 malloc_debug     The default is 32 bytes, the max bytes is 16384.\n"
   "6 malloc_debug \n"
   "6 malloc_debug   backtrace[=XX]\n"
   "6 malloc_debug     Enable capturing the backtrace at the point of allocation.\n"
   "6 malloc_debug     If XX is set it sets the number of backtrace frames.\n"
-  "6 malloc_debug     The default is 16 frames.\n"
+  "6 malloc_debug     The default is 16 frames, the max number of frames is 256.\n"
   "6 malloc_debug \n"
   "6 malloc_debug   backtrace_enable_on_signal[=XX]\n"
   "6 malloc_debug     Enable capturing the backtrace at the point of allocation.\n"
   "6 malloc_debug     The backtrace capture is not enabled until the process\n"
   "6 malloc_debug     receives a signal. If XX is set it sets the number of backtrace\n"
-  "6 malloc_debug     frames. The default is 16 frames.\n"
+  "6 malloc_debug     frames. The default is 16 frames, the max number of frames is 256.\n"
   "6 malloc_debug \n"
   "6 malloc_debug   fill_on_alloc[=XX]\n"
   "6 malloc_debug     On first allocation, fill with the value 0xeb.\n"
@@ -92,7 +92,7 @@
   "6 malloc_debug   expand_alloc[=XX]\n"
   "6 malloc_debug     Allocate an extra number of bytes for every allocation call.\n"
   "6 malloc_debug     If XX is set, that is the number of bytes to expand the\n"
-  "6 malloc_debug     allocation by. The default is 16 bytes.\n"
+  "6 malloc_debug     allocation by. The default is 16 bytes, the max bytes is 16384.\n"
   "6 malloc_debug \n"
   "6 malloc_debug   free_track[=XX]\n"
   "6 malloc_debug     When a pointer is freed, do not free the memory right away.\n"
@@ -101,14 +101,15 @@
   "6 malloc_debug     allocations exceeds the XX amount. When the program terminates,\n"
   "6 malloc_debug     the rest of these allocations are verified. When this option is\n"
   "6 malloc_debug     enabled, it automatically records the backtrace at the time of the free.\n"
-  "6 malloc_debug     The default is to record 100 allocations.\n"
+  "6 malloc_debug     The default is to record 100 allocations, the max allocations\n"
+  "6 malloc_debug     to record is 16384.\n"
   "6 malloc_debug \n"
   "6 malloc_debug   free_track_backtrace_num_frames[=XX]\n"
   "6 malloc_debug     This option only has meaning if free_track is set. This indicates\n"
   "6 malloc_debug     how many backtrace frames to capture when an allocation is freed.\n"
   "6 malloc_debug     If XX is set, that is the number of frames to capture. If XX\n"
   "6 malloc_debug     is set to zero, then no backtrace will be captured.\n"
-  "6 malloc_debug     The default is to record 16 frames.\n"
+  "6 malloc_debug     The default is to record 16 frames, the max number of frames is 256.\n"
   "6 malloc_debug \n"
   "6 malloc_debug   leak_track\n"
   "6 malloc_debug     Enable the leak tracking of memory allocations.\n"
diff --git a/libm/Android.bp b/libm/Android.bp
index 081a139..a4f6135 100644
--- a/libm/Android.bp
+++ b/libm/Android.bp
@@ -437,8 +437,6 @@
                 ],
             },
             local_include_dirs: ["i387"],
-            // Clang has wrong long double sizes for x86.
-            clang: false,
             ldflags: ["-Wl,--hash-style=both"],
             version_script: "libm.x86.map",
         },
@@ -507,8 +505,6 @@
                     "upstream-freebsd/lib/msun/src/s_truncf.c",
                 ],
             },
-            // Clang has wrong long double sizes for x86.
-            clang: false,
             version_script: "libm.x86_64.map",
         },
     },
diff --git a/tests/ifaddrs_test.cpp b/tests/ifaddrs_test.cpp
index c3f0273..9f01619 100644
--- a/tests/ifaddrs_test.cpp
+++ b/tests/ifaddrs_test.cpp
@@ -107,9 +107,35 @@
                                   sys_class_net.begin()));
 }
 
+static void CheckAddressIsInSet(const std::string& if_name, bool unicast,
+                                const std::set<in_addr_t>& addrs) {
+  ifreq ifr;
+  memset(&ifr, 0, sizeof(ifr));
+  ifr.ifr_addr.sa_family = AF_INET;
+  if_name.copy(ifr.ifr_name, IFNAMSIZ - 1);
+
+  int fd = socket(AF_INET, SOCK_DGRAM, 0);
+  ASSERT_TRUE(fd != -1);
+
+  int request = SIOCGIFADDR;
+  if (!unicast) {
+    // For non-unicast, the specific ioctl to use depends on whether the IFF_BROADCAST flag is set.
+    ASSERT_EQ(0, ioctl(fd, SIOCGIFFLAGS, &ifr)) << if_name << ' ' << strerror(errno);
+    request = ((ifr.ifr_flags & IFF_BROADCAST) != 0) ? SIOCGIFBRDADDR : SIOCGIFDSTADDR;
+  }
+
+  ASSERT_EQ(0, ioctl(fd, request, &ifr)) << if_name << ' ' << strerror(errno);
+  close(fd);
+
+  sockaddr_in* sock = reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr);
+  in_addr_t addr = sock->sin_addr.s_addr;
+
+  EXPECT_TRUE(addrs.find(addr) != addrs.end()) << if_name << ' ' << std::hex << ntohl(addr);
+}
+
 TEST(ifaddrs, getifaddrs_INET) {
-  std::multimap<std::string, in_addr_t> inetaddrs;
-  std::multimap<std::string, in_addr_t> broadinetaddrs;
+  std::map<std::string, std::set<in_addr_t>> inet_addrs;
+  std::map<std::string, std::set<in_addr_t>> broad_addrs;
 
   // Collect the IPv4 addresses for each interface.
   ifaddrs* addrs;
@@ -117,47 +143,19 @@
   for (ifaddrs* addr = addrs; addr != nullptr; addr = addr->ifa_next) {
     if (addr->ifa_name && addr->ifa_addr && addr->ifa_addr->sa_family == AF_INET) {
       auto sock = reinterpret_cast<sockaddr_in*>(addr->ifa_addr);
-      inetaddrs.emplace(std::string(addr->ifa_name), sock->sin_addr.s_addr);
+      inet_addrs[addr->ifa_name].insert(sock->sin_addr.s_addr);
     }
     if (addr->ifa_name && addr->ifa_broadaddr && addr->ifa_broadaddr->sa_family == AF_INET) {
       auto sock = reinterpret_cast<sockaddr_in*>(addr->ifa_broadaddr);
-      broadinetaddrs.emplace(std::string(addr->ifa_name), sock->sin_addr.s_addr);
+      broad_addrs[addr->ifa_name].insert(sock->sin_addr.s_addr);
     }
   }
   freeifaddrs(addrs);
 
-  // Check that the addresses returned by the SIOCGIFADDR and SIOCGIFBRDADDR ioctls
+  // Check that the addresses returned by the SIOCGIFADDR and SIOCGIFBRDADDR/SIOCGIFDSTADDR ioctls
   // are in our collections.
-  auto check_inet_agrees = [&](std::multimap<std::string, in_addr_t> addrs, int request)->void {
-    for (auto it = addrs.begin(); it != addrs.end(); ) {
-      std::string if_name(it->first);
-
-      ifreq ifr;
-      memset(&ifr, 0, sizeof(ifr));
-      ifr.ifr_addr.sa_family = AF_INET;
-      if_name.copy(ifr.ifr_name, IFNAMSIZ - 1);
-
-      int fd = socket(AF_INET, SOCK_DGRAM, 0);
-      ASSERT_TRUE(fd != -1);
-      ASSERT_EQ(0, ioctl(fd, request, &ifr)) << if_name << ' ' << strerror(errno);
-      close(fd);
-
-      sockaddr_in* sock = reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr);
-      in_addr_t addr = sock->sin_addr.s_addr;
-
-      bool found = false;
-      for (auto ub = addrs.upper_bound(it->first); it != ub; ++it) {
-        if (it->second == addr) {
-          found = true;
-          break;
-        }
-      }
-      EXPECT_TRUE(found) << if_name;
-    }
-  };
-
-  check_inet_agrees(inetaddrs, SIOCGIFADDR);
-  check_inet_agrees(broadinetaddrs, SIOCGIFBRDADDR);
+  for (const auto& it : inet_addrs) CheckAddressIsInSet(it.first, true, it.second);
+  for (const auto& it : broad_addrs) CheckAddressIsInSet(it.first, false, it.second);
 }
 
 static void print_sockaddr_ll(const char* what, const sockaddr* p) {
@@ -183,7 +181,7 @@
   printf("\t\t%s: <%s>\n", what, host);
 }
 
-static const char* family_to_name(int family) {
+static const char* FamilyToName(int family) {
   if (family == AF_INET) return "AF_INET";
   if (family == AF_INET6) return "AF_INET6";
   if (family == AF_PACKET) return "AF_PACKET";
@@ -191,6 +189,36 @@
   return "?";
 }
 
+static std::string FlagsToString(short flags) {
+  std::string result;
+  if ((flags & IFF_UP) != 0) result += " UP";
+  if ((flags & IFF_BROADCAST) != 0) result += " BROADCAST";
+  if ((flags & IFF_DEBUG) != 0) result += " DEBUG";
+  if ((flags & IFF_LOOPBACK) != 0) result += " LOOPBACK";
+  if ((flags & IFF_POINTOPOINT) != 0) result += " POINTOPOINT";
+  if ((flags & IFF_NOTRAILERS) != 0) result += " NOTRAILERS";
+  if ((flags & IFF_RUNNING) != 0) result += " RUNNING";
+  if ((flags & IFF_NOARP) != 0) result += " NOARP";
+  if ((flags & IFF_PROMISC) != 0) result += " PROMISC";
+  if ((flags & IFF_ALLMULTI) != 0) result += " ALLMULTI";
+  if ((flags & IFF_MASTER) != 0) result += " MASTER";
+  if ((flags & IFF_SLAVE) != 0) result += " SLAVE";
+  if ((flags & IFF_MULTICAST) != 0) result += " MULTICAST";
+  if ((flags & IFF_PORTSEL) != 0) result += " PORTSEL";
+  if ((flags & IFF_AUTOMEDIA) != 0) result += " AUTOMEDIA";
+  if ((flags & IFF_DYNAMIC) != 0) result += " DYNAMIC";
+#if defined(IFF_LOWER_UP)
+  if ((flags & IFF_LOWER_UP) != 0) result += " LOWER_UP";
+#endif
+#if defined(IFF_DORMANT)
+  if ((flags & IFF_DORMANT) != 0) result += " DORMANT";
+#endif
+#if defined(IFF_ECHO)
+  if ((flags & IFF_ECHO) != 0) result += " ECHO";
+#endif
+  return result;
+}
+
 // Not really a test, but a useful debugging tool.
 TEST(ifaddrs, dump) {
   ifaddrs* addrs;
@@ -201,8 +229,9 @@
                                  ifa->ifa_broadaddr ? ifa->ifa_broadaddr->sa_family : AF_UNSPEC;
 
     printf("\t%s\n"
-           "\t\t%s (%d) flags=%#x\n",
-           ifa->ifa_name, family_to_name(family), family, ifa->ifa_flags);
+           "\t\t%s (%d) flags=%#x%s\n",
+           ifa->ifa_name, FamilyToName(family), family,
+           ifa->ifa_flags, FlagsToString(ifa->ifa_flags).c_str());
 
     if (family == AF_PACKET) {
       if (ifa->ifa_addr) print_sockaddr_ll("hwaddr", ifa->ifa_addr);