Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'oprofile/org.eclipse.linuxtools.oprofile.core/natives/linux/opxml/stable.cc')
-rw-r--r--oprofile/org.eclipse.linuxtools.oprofile.core/natives/linux/opxml/stable.cc294
1 files changed, 294 insertions, 0 deletions
diff --git a/oprofile/org.eclipse.linuxtools.oprofile.core/natives/linux/opxml/stable.cc b/oprofile/org.eclipse.linuxtools.oprofile.core/natives/linux/opxml/stable.cc
new file mode 100644
index 0000000000..5f9e63bfac
--- /dev/null
+++ b/oprofile/org.eclipse.linuxtools.oprofile.core/natives/linux/opxml/stable.cc
@@ -0,0 +1,294 @@
+/* symboltable - A symbol table class
+ Written by Keith Seitz <keiths@redhat.com>
+ Copyright 2004 Red Hat, Inc.
+
+ This program is open source software licensed under the Eclipse
+ Public License ver. 1.
+
+ Alternatively, this program may be used under the terms of the GNU
+ General Public License as published by the Free Software Foundation;
+ either version 2 of the License, or (at your option) any later
+ version. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <iostream>
+#include <fcntl.h>
+#include <algorithm>
+
+#include "stable.h"
+#include "symbol.h"
+
+static bool ltvma (const symbol* a, const symbol* b);
+
+// Stolen from oprofile
+char const* symboltable::_boring_symbols[] = {
+ "gcc2_compiled.",
+ "_init"
+};
+
+// Helper function for sorting symbols by VMA
+static bool
+compare_symbol_with_vma (bfd_vma vma, const symbol* a)
+{
+ return (a->end () > vma);
+}
+
+symboltable::symboltable(const char* file)
+ : _filename (strdup (file)), _abfd (NULL), _symbol_table (NULL), _cache_symbol (NULL)
+{
+}
+
+symboltable::~symboltable ()
+{
+ if (_symbol_table != NULL)
+ free (_symbol_table);
+
+ std::vector<symbol*>::iterator i = _symbols.begin ();
+ while (i != _symbols.end ())
+ {
+ delete (*i);
+ //_symbols.erase (i);
+ ++i;
+ }
+
+ _symbols.clear ();
+ _close_bfd ();
+ free (_filename);
+}
+
+// If this returns NULL, then the VMA is not in any range of
+// msymbols. This is can apparently happen. op_time and friends
+// ignore these samples.
+symbol*
+symboltable::lookup_vma (bfd_vma vma, bfd_vma& real_vma, bool is_kernel)
+{
+ if (is_kernel)
+ real_vma = vma;
+ else
+ real_vma = vma + _start_vma - _text_offset;
+ return (lookup_vma (real_vma));
+}
+
+symbol*
+symboltable::lookup_vma (bfd_vma real_vma)
+{
+ if (_cache_symbol != NULL && _cache_symbol->contains (real_vma))
+ return _cache_symbol;
+
+ std::vector<symbol*>::iterator i;
+ i = upper_bound (_symbols.begin (), _symbols.end (),
+ real_vma, compare_symbol_with_vma);
+ if (i != _symbols.end () && (*i)->contains (real_vma))
+ {
+ _cache_symbol = *i;
+ return *i;
+ }
+
+ return NULL;
+}
+
+bool
+symboltable::read_symbols ()
+{
+ if (_open_bfd ())
+ {
+ long storage_needed = bfd_get_symtab_upper_bound (_abfd);
+ if (storage_needed > 0)
+ {
+ _symbol_table = (asymbol**) malloc (storage_needed);
+ long num_symbols = bfd_canonicalize_symtab (_abfd, _symbol_table);
+ for (int i = 0; i < num_symbols; ++i)
+ {
+ if (_interesting_symbol (_symbol_table[i]))
+ _symbols.push_back (new symbol (_symbol_table[i]));
+ }
+
+ if (_symbols.size() > 0)
+ {
+ // Sort in order of increasing vma and eliminate duplicates
+ stable_sort (_symbols.begin (), _symbols.end (), ltvma);
+
+ // Eliminate duplicates
+ for (size_t i = 0; i < _symbols.size () - 1; ++i)
+ {
+ if (_symbols[i]->start () == _symbols[i+1]->start ())
+ {
+ int erase;
+
+ // Opt to keep FUNCTIONs, first come, first kept
+ if (_symbols[i]->flags () & BSF_FUNCTION)
+ erase = i + 1;
+ else if (_symbols[i+1]->flags () & BSF_FUNCTION)
+ erase = i;
+ else // Don't know. Keep first.
+ erase = i + 1;
+
+ delete *(_symbols.begin () + erase);
+ _symbols.erase (_symbols.begin () + erase);
+ --i;
+ }
+ }
+
+ // Fill in end addresses
+ for (size_t i = 0; i <= _symbols.size () - 1; ++i)
+ {
+ asymbol* this_sym;
+ asymbol* next_sym = NULL;
+ asection* this_sect;
+ asection* next_sect;
+
+ this_sym = _symbols[i]->get_asymbol ();
+ this_sect = bfd_get_section (this_sym);
+ if (i < _symbols.size () - 1)
+ {
+ next_sym = _symbols[i + 1]->get_asymbol ();
+ next_sect = bfd_get_section (next_sym);
+ }
+ else
+ next_sect = NULL;
+
+ if (next_sect != NULL
+ && bfd_get_section (this_sym) == bfd_get_section (next_sym))
+ _symbols[i]->end (_symbols[i + 1]->start ());
+ else
+ {
+ asection* asect = bfd_get_section (this_sym);
+ bfd_vma end = bfd_get_section_vma (_abfd, asect);
+ end += bfd_section_size (_abfd, asect);
+ _symbols[i]->end (end);
+ }
+ }
+
+ return true;
+ }
+ }
+ /* This may not seem correct, since we're pasing pointers of asymbols
+ and the like to other pieces of opxml (class symbol, in particular),
+ but remember that we've allocated memory for the symbol table earlier,
+ and class symbol references that. So as long as the object "class symboltable"
+ is not deleted, all symbols will be valid, and we can close the bfd. */
+ _close_bfd ();
+ }
+
+ return false;
+}
+
+bool
+symboltable::_interesting_symbol (asymbol* sym)
+{
+ if (!(bfd_get_section_flags (bfd_asymbol_bfd (sym), bfd_get_section (sym)) & SEC_CODE))
+ return false;
+
+ const char* name = bfd_asymbol_name (sym);
+ if (name == NULL || name[0] == '\0')
+ return false;
+
+ // C++ exception stuff
+ if (name[0] == '.' && name[1] == 'L')
+ return false;
+
+ for (size_t i = 0; i < sizeof (_boring_symbols) / sizeof (_boring_symbols[0]); i++)
+ {
+ if (strcmp (name, _boring_symbols[i]) == 0)
+ return false;
+ }
+
+ return true;
+}
+
+bool
+symboltable::_open_bfd (void)
+{
+ if (_abfd == NULL)
+ {
+ bfd_init ();
+ int fd = open (_filename, O_RDONLY); // bfd_close will close fd
+ _abfd = bfd_fdopenr (_filename, NULL, fd);
+ if (_abfd != NULL)
+ {
+ char** matches;
+ if (bfd_check_format_matches (_abfd, bfd_object, &matches))
+ {
+ asection const* sect;
+
+ sect = bfd_get_section_by_name(_abfd, ".text");
+ if (sect != NULL) {
+ _text_offset = sect->filepos;
+ } else {
+ return false;
+ }
+
+// //fail: this might not get the text section because
+// // other sections may also have the SEC_CODE flag
+// for (sect = _abfd->sections; sect != NULL; sect = sect->next)
+// {
+// if (sect->flags & SEC_CODE)
+// {
+// _text_offset = sect->filepos;
+// break;
+// }
+// }
+
+ }
+
+ _start_vma = bfd_get_start_address (_abfd);
+ }
+ }
+ return (_abfd != NULL);
+}
+
+void
+symboltable::_close_bfd (void)
+{
+ if (_abfd != NULL)
+ bfd_close (_abfd);
+
+ _abfd = NULL;
+}
+
+bool
+symboltable::get_debug_info (bfd_vma vma, const char*& function,
+ const char*& source_file, unsigned int& line)
+{
+ function = NULL;
+ source_file = NULL;
+ line = 0;
+
+ symbol* symbol = lookup_vma (vma);
+ if (symbol != NULL)
+ {
+ asection* asection = symbol->section ();
+
+ bfd_vma pc = vma - bfd_get_section_vma (_abfd, asection);
+ return bfd_find_nearest_line (_abfd, asection, _symbol_table, pc,
+ &source_file, &function, &line);
+ }
+
+
+ return false;
+}
+
+#if 0
+void
+symboltable::dump_table (void)
+{
+ printf ("%8s\t%8s\t%s\n", "start", "end", "name");
+
+ std::vector<symbol*>::iterator i;
+ for (i = _symbols.begin (); i != _symbols.end (); ++i)
+ {
+ symbol* sym = *i;;
+ printf("%8x\t%8x\t%s\n", (unsigned int)sym->start (), (unsigned int)sym->end (),
+ sym->name ());
+ }
+}
+#endif
+
+// Helper function to sort two symbols based on VMA
+static bool
+ltvma (const symbol* a, const symbol* b)
+{
+ return (a->start () < b->start ());
+}
+

Back to the top