Add demangling support to nm
diff --git a/src/nm.c b/src/nm.c
index f78861e..1d18e57 100644
--- a/src/nm.c
+++ b/src/nm.c
@@ -1,5 +1,5 @@
 /* Print symbol information from ELF file in human-readable form.
-   Copyright (C) 2000-2008, 2009 Red Hat, Inc.
+   Copyright (C) 2000-2008, 2009, 2011 Red Hat, Inc.
    This file is part of Red Hat elfutils.
    Written by Ulrich Drepper <drepper@redhat.com>, 2000.
 
@@ -100,6 +100,10 @@
     0 },
   { "no-sort", 'p', NULL, 0, N_("Do not sort the symbols"), 0 },
   { "reverse-sort", 'r', NULL, 0, N_("Reverse the sense of the sort"), 0 },
+#ifdef USE_DEMANGLE
+  { "demangle", 'C', NULL, 0,
+    N_("Decode low-level symbol names into source code names"), 0 },
+#endif
   { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 },
   { NULL, 0, NULL, 0, NULL, 0 }
 };
@@ -175,6 +179,11 @@
 /* If true reverse sorting.  */
 static bool reverse_sort;
 
+#ifdef USE_DEMANGLE
+/* If true demangle symbols.  */
+static bool demangle;
+#endif
+
 /* Type of the section we are printing.  */
 static GElf_Word symsec_type = SHT_SYMTAB;
 
@@ -270,6 +279,12 @@
       /* XXX */
       break;
 
+#ifdef USE_DEMANGLE
+    case 'C':
+      demangle = true;
+      break;
+#endif
+
     case 'f':
       if (strcmp (arg, "bsd") == 0)
 	format = format_bsd;
@@ -783,6 +798,11 @@
   else
     fmtstr = "%-*s|%0*" PRIo64 "|%-6s|%-8s|%*" PRIo64 "|%*s|%s\n";
 
+#ifdef USE_DEMANGLE
+  size_t demangle_buffer_len = 0;
+  char *demangle_buffer = NULL;
+#endif
+
   /* Iterate over all symbols.  */
   for (cnt = 0; cnt < nsyms; ++cnt)
     {
@@ -790,6 +810,19 @@
       const char *symstr = sym_name (ebl->elf, strndx, syms[cnt].sym.st_name,
 				     symstrbuf, sizeof symstrbuf);
 
+#ifdef USE_DEMANGLE
+      /* Demangle if necessary.  */
+      if (demangle)
+	{
+	  int status = -1;
+	  char *dmsymstr = __cxa_demangle (symstr, demangle_buffer,
+					   &demangle_buffer_len, &status);
+
+	  if (status == 0)
+	    symstr = dmsymstr;
+	}
+#endif
+
       char symbindbuf[50];
       char symtypebuf[50];
       char secnamebuf[1024];
@@ -816,6 +849,10 @@
 				shnum));
     }
 
+#ifdef USE_DEMANGLE
+  free (demangle_buffer);
+#endif
+
   if (scnnames_malloced)
     free (scnnames);
 }
@@ -863,6 +900,11 @@
       [radix_octal] = "%2$0*1$" PRIo64 " %7$0*6$" PRIo64 " %3$c%4$s %5$s\n"
     };
 
+#ifdef USE_DEMANGLE
+  size_t demangle_buffer_len = 0;
+  char *demangle_buffer = NULL;
+#endif
+
   /* Iterate over all symbols.  */
   for (size_t cnt = 0; cnt < nsyms; ++cnt)
     {
@@ -876,6 +918,19 @@
       if (symstr[0] == '\0')
 	continue;
 
+#ifdef USE_DEMANGLE
+      /* Demangle if necessary.  */
+      if (demangle)
+	{
+	  int status = -1;
+	  char *dmsymstr = __cxa_demangle (symstr, demangle_buffer,
+					   &demangle_buffer_len, &status);
+
+	  if (status == 0)
+	    symstr = dmsymstr;
+	}
+#endif
+
       /* If we have to precede the line with the file name.  */
       if (print_file_name)
 	{
@@ -902,6 +957,10 @@
 		symstr,
 		digits, (uint64_t) syms[cnt].sym.st_size);
     }
+
+#ifdef USE_DEMANGLE
+  free (demangle_buffer);
+#endif
 }
 
 
@@ -922,6 +981,11 @@
 
   int digits = length_map[gelf_getclass (elf) - 1][radix];
 
+#ifdef USE_DEMANGLE
+  size_t demangle_buffer_len = 0;
+  char *demangle_buffer = NULL;
+#endif
+
   /* Iterate over all symbols.  */
   for (size_t cnt = 0; cnt < nsyms; ++cnt)
     {
@@ -935,6 +999,19 @@
       if (symstr[0] == '\0')
 	continue;
 
+#ifdef USE_DEMANGLE
+      /* Demangle if necessary.  */
+      if (demangle)
+	{
+	  int status = -1;
+	  char *dmsymstr = __cxa_demangle (symstr, demangle_buffer,
+					   &demangle_buffer_len, &status);
+
+	  if (status == 0)
+	    symstr = dmsymstr;
+	}
+#endif
+
       /* If we have to precede the line with the file name.  */
       if (print_file_name)
 	{
@@ -952,6 +1029,10 @@
 	      digits, syms[cnt].sym.st_value,
 	      digits, syms[cnt].sym.st_size);
     }
+
+#ifdef USE_DEMANGLE
+  free (demangle_buffer);
+#endif
 }
 
 
@@ -1053,6 +1134,10 @@
     INTERNAL_ERROR (fullname);
 
   /* Iterate over all symbols.  */
+#ifdef USE_DEMANGLE
+  size_t demangle_buffer_len = 0;
+  char *demangle_buffer = NULL;
+#endif
   int longest_name = 4;
   int longest_where = 4;
   size_t nentries_used = 0;
@@ -1065,7 +1150,7 @@
 	INTERNAL_ERROR (fullname);
 
       /* Filter out administrative symbols without a name and those
-	 deselected by ther user with command line options.  */
+	 deselected by the user with command line options.  */
       if ((hide_undefined && sym->st_shndx == SHN_UNDEF)
 	  || (hide_defined && sym->st_shndx != SHN_UNDEF)
 	  || (hide_local && GELF_ST_BIND (sym->st_info) == STB_LOCAL))
@@ -1079,6 +1164,19 @@
 	  if (symstr == NULL)
 	    continue;
 
+#ifdef USE_DEMANGLE
+	  /* Demangle if necessary.  */
+	  if (demangle)
+	    {
+	      int status = -1;
+	      char *dmsymstr = __cxa_demangle (symstr, demangle_buffer,
+					       &demangle_buffer_len, &status);
+
+	      if (status == 0)
+		symstr = dmsymstr;
+	    }
+#endif
+
 	  longest_name = MAX ((size_t) longest_name, strlen (symstr));
 
 	  if (sym->st_shndx != SHN_UNDEF
@@ -1133,7 +1231,7 @@
 		}
 	    }
 
-	  /* Try to find the symol among the local symbols.  */
+	  /* Try to find the symbol among the local symbols.  */
 	  if (sym_mem[nentries_used].where[0] == '\0')
 	    {
 	      struct local_name fake =
@@ -1164,6 +1262,9 @@
       /* We use this entry.  */
       ++nentries_used;
     }
+#ifdef USE_DEMANGLE
+  free (demangle_buffer);
+#endif
   /* Now we know the exact number.  */
   nentries = nentries_used;