summaryrefslogtreecommitdiff
path: root/gprofng/src/LoadObject.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gprofng/src/LoadObject.cc')
-rw-r--r--gprofng/src/LoadObject.cc1242
1 files changed, 1242 insertions, 0 deletions
diff --git a/gprofng/src/LoadObject.cc b/gprofng/src/LoadObject.cc
new file mode 100644
index 00000000000..d9ce3e847db
--- /dev/null
+++ b/gprofng/src/LoadObject.cc
@@ -0,0 +1,1242 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#include "config.h"
+#include <errno.h>
+
+#include "util.h"
+#include "StringBuilder.h"
+#include "Application.h"
+#include "DbeSession.h"
+#include "Experiment.h"
+#include "Exp_Layout.h"
+#include "DataObject.h"
+#include "Elf.h"
+#include "Function.h"
+#include "Module.h"
+#include "ClassFile.h"
+#include "Stabs.h"
+#include "LoadObject.h"
+#include "dbe_types.h"
+#include "DbeFile.h"
+#include "ExpGroup.h"
+
+enum
+{
+ LO_InstHTableSize = 4096,
+ HTableSize = 1024
+};
+
+LoadObject *
+LoadObject::create_item (const char *nm, int64_t chksum)
+{
+ LoadObject *lo = new LoadObject (nm);
+ lo->checksum = chksum;
+ dbeSession->append (lo);
+ return lo;
+}
+
+LoadObject *
+LoadObject::create_item (const char *nm, const char *_runTimePath, DbeFile *df)
+{
+ LoadObject *lo = new LoadObject (nm);
+ lo->runTimePath = dbe_strdup (_runTimePath);
+ lo->dbeFile->orig_location = dbe_strdup (_runTimePath);
+ if (df)
+ {
+ if ((df->filetype & DbeFile::F_JAR_FILE) != 0)
+ {
+ if (lo->dbeFile->find_in_jar_file (nm, df->get_jar_file ()))
+ {
+ lo->dbeFile->inArchive = df->inArchive;
+ lo->dbeFile->container = df;
+ }
+ }
+ else
+ {
+ lo->dbeFile->set_location (df->get_location ());
+ lo->dbeFile->sbuf = df->sbuf;
+ lo->dbeFile->inArchive = df->inArchive;
+ }
+ }
+ dbeSession->append (lo);
+ return lo;
+}
+
+LoadObject::LoadObject (const char *loname)
+{
+ flags = 0;
+ size = 0;
+ type = SEG_UNKNOWN;
+ isReadStabs = false;
+ need_swap_endian = false;
+ instHTable = new DbeInstr*[LO_InstHTableSize];
+ for (int i = 0; i < LO_InstHTableSize; i++)
+ instHTable[i] = NULL;
+
+ functions = new Vector<Function*>;
+ funcHTable = new Function*[HTableSize];
+ for (int i = 0; i < HTableSize; i++)
+ funcHTable[i] = NULL;
+
+ seg_modules = new Vector<Module*>;
+ modules = new HashMap<char*, Module*>;
+ platform = Unknown;
+ noname = dbeSession->createUnknownModule (this);
+ modules->put (noname->get_name (), noname);
+ pathname = NULL;
+ arch_name = NULL;
+ runTimePath = NULL;
+ objStabs = NULL;
+ firstExp = NULL;
+ seg_modules_map = NULL;
+ comp_funcs = NULL;
+ warnq = new Emsgqueue (NTXT ("lo_warnq"));
+ commentq = new Emsgqueue (NTXT ("lo_commentq"));
+ elf_lo = NULL;
+ elf_inited = false;
+ checksum = 0;
+ isUsed = false;
+ h_function = NULL;
+ h_instr = NULL;
+
+ char *nm = (char *) loname;
+ if (strncmp (nm, NTXT ("./"), 2) == 0)
+ nm += 2;
+ set_name (nm);
+ dbeFile = new DbeFile (nm);
+ dbeFile->filetype |= DbeFile::F_LOADOBJ | DbeFile::F_FILE;
+}
+
+LoadObject::~LoadObject ()
+{
+ delete seg_modules_map;
+ delete functions;
+ delete[] instHTable;
+ delete[] funcHTable;
+ delete seg_modules;
+ delete modules;
+ delete elf_lo;
+ free (pathname);
+ free (arch_name);
+ free (runTimePath);
+ delete objStabs;
+ delete warnq;
+ delete commentq;
+ delete h_instr;
+}
+
+Elf *
+LoadObject::get_elf ()
+{
+ if (elf_lo == NULL)
+ {
+ if (dbeFile->get_need_refind ())
+ elf_inited = false;
+ if (elf_inited)
+ return NULL;
+ elf_inited = true;
+ char *fnm = dbeFile->get_location ();
+ if (fnm == NULL)
+ {
+ append_msg (CMSG_ERROR, GTXT ("Cannot find file: `%s'"),
+ dbeFile->get_name ());
+ return NULL;
+ }
+ Elf::Elf_status st = Elf::ELF_ERR_CANT_OPEN_FILE;
+ elf_lo = Elf::elf_begin (fnm, &st);
+ if (elf_lo == NULL)
+ switch (st)
+ {
+ case Elf::ELF_ERR_CANT_OPEN_FILE:
+ append_msg (CMSG_ERROR, GTXT ("Cannot open ELF file `%s'"), fnm);
+ break;
+ case Elf::ELF_ERR_BAD_ELF_FORMAT:
+ default:
+ append_msg (CMSG_ERROR, GTXT ("Cannot read ELF header of `%s'"),
+ fnm);
+ break;
+ }
+ }
+ return elf_lo;
+}
+
+Stabs *
+LoadObject::openDebugInfo (char *fname, Stabs::Stab_status *stp)
+{
+ if (objStabs == NULL)
+ {
+ if (fname == NULL)
+ return NULL;
+ objStabs = new Stabs (fname, get_pathname ());
+ Stabs::Stab_status st = objStabs->get_status ();
+ if ((st == Stabs::DBGD_ERR_NONE) && (checksum != 0))
+ {
+ Elf *elf = get_elf ();
+ if (elf && (checksum != elf->elf_checksum ()))
+ {
+ char *buf = dbe_sprintf (GTXT ("*** Note: '%s' has an unexpected checksum value; perhaps it was rebuilt. File ignored"),
+ fname);
+ commentq->append (new Emsg (CMSG_ERROR, buf));
+ delete buf;
+ st = Stabs::DBGD_ERR_CHK_SUM;
+ }
+ }
+ if (stp)
+ *stp = st;
+ if (st != Stabs::DBGD_ERR_NONE)
+ {
+ delete objStabs;
+ objStabs = NULL;
+ }
+ }
+ return objStabs;
+}
+
+uint64_t
+LoadObject::get_addr ()
+{
+ return MAKE_ADDRESS (seg_idx, 0);
+}
+
+bool
+LoadObject::compare (const char *_path, int64_t _checksum)
+{
+ return _checksum == checksum && dbe_strcmp (_path, get_pathname ()) == 0;
+}
+
+int
+LoadObject::compare (const char *_path, const char *_runTimePath, DbeFile *df)
+{
+ int ret = 0;
+ if (dbe_strcmp (_path, get_pathname ()) != 0)
+ return ret;
+ ret |= CMP_PATH;
+ if (_runTimePath)
+ {
+ if (dbe_strcmp (_runTimePath, runTimePath) != 0)
+ return ret;
+ ret |= CMP_RUNTIMEPATH;
+ }
+ if (df && dbeFile->compare (df))
+ ret |= CMP_CHKSUM;
+ return ret;
+}
+
+void
+LoadObject::set_platform (Platform_t pltf, int wsz)
+{
+ switch (pltf)
+ {
+ case Sparc:
+ case Sparcv9:
+ case Sparcv8plus:
+ platform = (wsz == W64) ? Sparcv9 : Sparc;
+ break;
+ case Intel:
+ case Amd64:
+ platform = (wsz == W64) ? Amd64 : Intel;
+ break;
+ default:
+ platform = pltf;
+ break;
+ }
+};
+
+void
+LoadObject::set_name (char *string)
+{
+ char *p;
+ pathname = dbe_strdup (string);
+
+ p = get_basename (pathname);
+ if (p[0] == '<')
+ name = dbe_strdup (p);
+ else // set a short name to "<basename>"
+ name = dbe_sprintf (NTXT ("<%s>"), p);
+}
+
+void
+LoadObject::dump_functions (FILE *out)
+{
+ int index;
+ Function *fitem;
+ char *sname, *mname;
+ if (platform == Java)
+ {
+ JMethod *jmthd;
+ Vector<JMethod*> *jmethods = (Vector<JMethod*>*)functions;
+ Vec_loop (JMethod*, jmethods, index, jmthd)
+ {
+ fprintf (out, "id %6llu, @0x%llx sz-%lld %s (module = %s)\n",
+ (unsigned long long) jmthd->id, (long long) jmthd->get_mid (),
+ (long long) jmthd->size, jmthd->get_name (),
+ jmthd->module ? jmthd->module->file_name : noname->file_name);
+ }
+ }
+ else
+ {
+ Vec_loop (Function*, functions, index, fitem)
+ {
+ if (fitem->alias && fitem->alias != fitem)
+ fprintf (out, "id %6llu, @0x%llx - %s == alias of '%s'\n",
+ (ull_t) fitem->id, (ull_t) fitem->img_offset,
+ fitem->get_name (), fitem->alias->get_name ());
+ else
+ {
+ mname = fitem->module ? fitem->module->file_name : noname->file_name;
+ sname = fitem->getDefSrcName ();
+ fprintf (out,
+ "id %6llu, @0x%llx - 0x%llx [save 0x%llx] o-%lld sz-%lld %s (module = %s)",
+ (ull_t) fitem->id, (ull_t) fitem->img_offset,
+ (ull_t) (fitem->img_offset + fitem->size),
+ (ull_t) fitem->save_addr, (ull_t) fitem->img_offset,
+ (ll_t) fitem->size, fitem->get_name (), mname);
+ if (sname && !streq (sname, mname))
+ fprintf (out, " (Source = %s)", sname);
+ fprintf (out, "\n");
+ }
+ }
+ }
+}
+
+int
+LoadObject::get_index (Function *func)
+{
+ Function *fp;
+ uint64_t offset;
+ int x;
+ int left = 0;
+ int right = functions->size () - 1;
+ offset = func->img_offset;
+ while (left <= right)
+ {
+ x = (left + right) / 2;
+ fp = functions->fetch (x);
+
+ if (left == right)
+ {
+ if (offset >= fp->img_offset + fp->size)
+ return -1;
+ if (offset >= fp->img_offset)
+ return x;
+ return -1;
+ }
+ if (offset < fp->img_offset)
+ right = x - 1;
+ else if (offset >= fp->img_offset + fp->size)
+ left = x + 1;
+ else
+ return x;
+ }
+ return -1;
+}
+
+char *
+LoadObject::get_alias (Function *func)
+{
+ Function *fp, *alias;
+ int index, nsize;
+ static char buf[1024];
+ if (func->img_offset == 0 || func->alias == NULL)
+ return NULL;
+ int fid = get_index (func);
+ if (fid == -1)
+ return NULL;
+
+ nsize = functions->size ();
+ alias = func->alias;
+ for (index = fid; index < nsize; index++)
+ {
+ fp = functions->fetch (index);
+ if (fp->alias != alias)
+ {
+ fid = index;
+ break;
+ }
+ }
+
+ *buf = '\0';
+ for (index--; index >= 0; index--)
+ {
+ fp = functions->fetch (index);
+ if (fp->alias != alias)
+ break;
+ if (fp != alias)
+ {
+ size_t len = strlen (buf);
+ if (*buf != '\0')
+ {
+ snprintf (buf + len, sizeof (buf) - len, NTXT (", "));
+ len = strlen (buf);
+ }
+ snprintf (buf + len, sizeof (buf) - len, "%s", fp->get_name ());
+ }
+ }
+ return buf;
+}
+
+DbeInstr*
+LoadObject::find_dbeinstr (uint64_t file_off)
+{
+ int hash = (((int) file_off) >> 2) & (LO_InstHTableSize - 1);
+ DbeInstr *instr = instHTable[hash];
+ if (instr && instr->img_offset == file_off)
+ return instr;
+ Function *fp = find_function (file_off);
+ if (fp == NULL)
+ fp = dbeSession->get_Unknown_Function ();
+ uint64_t func_off = file_off - fp->img_offset;
+ instr = fp->find_dbeinstr (0, func_off);
+ instHTable[hash] = instr;
+ return instr;
+}
+
+Function *
+LoadObject::find_function (uint64_t foff)
+{
+ // Look up in the hash table
+ int hash = (((int) foff) >> 6) & (HTableSize - 1);
+ Function *func = funcHTable[hash];
+ if (func && foff >= func->img_offset && foff < func->img_offset + func->size)
+ return func->alias ? func->alias : func;
+
+ // Use binary search
+ func = NULL;
+ int left = 0;
+ int right = functions->size () - 1;
+ while (left <= right)
+ {
+ int x = (left + right) / 2;
+ Function *fp = functions->fetch (x);
+ assert (fp != NULL);
+
+ if (foff < fp->img_offset)
+ right = x - 1;
+ else if (foff >= fp->img_offset + fp->size)
+ left = x + 1;
+ else
+ {
+ func = fp;
+ break;
+ }
+ }
+
+ // Plug the hole with a static function
+ char *func_name = NULL;
+ Size low_bound = 0, high_bound = 0;
+ if (func == NULL)
+ {
+ int last = functions->size () - 1;
+ uint64_t usize = (uint64_t) size;
+ if (foff >= usize)
+ {
+ // Cannot map to this LoadObject. Probably LoadObject was changed.
+ if (last >= 0 && functions->fetch (last)->img_offset == usize)
+ {
+ // Function is already created
+ func = functions->fetch (last);
+ if (func->size < 0 || (uint64_t) func->size < foff - usize)
+ func->size = foff - usize;
+ }
+ else
+ {
+ low_bound = size;
+ high_bound = foff;
+ func_name = dbe_sprintf (GTXT ("<static>@0x%llx (%s) -- no functions found"),
+ low_bound, name);
+ }
+ }
+ else if (last < 0)
+ {
+ low_bound = 0;
+ high_bound = size;
+ func_name = dbe_sprintf (GTXT ("<static>@0x%llx (%s) -- no functions found"),
+ low_bound, name);
+ }
+ else if (foff < functions->fetch (0)->img_offset)
+ {
+ low_bound = 0;
+ high_bound = functions->fetch (0)->img_offset;
+ }
+ else
+ {
+ Function *fp = functions->fetch (last);
+ if (foff >= fp->img_offset + fp->size)
+ {
+ low_bound = fp->img_offset + fp->size;
+ high_bound = size;
+ }
+ else
+ {
+ fp = functions->fetch (left);
+ if (foff >= fp->img_offset + fp->size)
+ {
+ low_bound = fp->img_offset + fp->size;
+ high_bound = functions->fetch (left + 1)->img_offset;
+ }
+ else
+ {
+ Function *fp1 = functions->fetch (left - 1);
+ low_bound = fp1->img_offset + fp1->size;
+ high_bound = fp->img_offset;
+ }
+ }
+ }
+ }
+
+ if (func == NULL)
+ {
+ func = dbeSession->createFunction ();
+ func->size = (unsigned) (high_bound - low_bound);
+ func->module = noname;
+ func->img_fname = get_pathname ();
+ func->img_offset = (off_t) low_bound;
+ noname->functions->append (func); // unordered
+ if (func_name == NULL)
+ func_name = dbe_sprintf (GTXT ("<static>@0x%llx (%s)"), low_bound,
+ name);
+ func->set_name (func_name);
+ free (func_name);
+
+ // now insert the function
+ functions->insert (left, func);
+ }
+
+ // Update the hash table
+ funcHTable[hash] = func;
+ return func->alias ? func->alias : func;
+}
+
+static void
+fixFuncAlias (Vector<Function*> *SymLst)
+{
+ int ind, i, k;
+ int64_t len, bestLen, maxSize;
+ Function *sym, *bestAlias;
+
+ // XXXX it is a clone of Stabs::fixSymtabAlias()
+ ind = SymLst->size () - 1;
+ for (i = 0; i < ind; i++)
+ {
+ bestAlias = SymLst->fetch (i);
+ if (bestAlias->img_offset == 0) // Ignore this bad symbol
+ continue;
+ sym = SymLst->fetch (i + 1);
+ if (bestAlias->img_offset != sym->img_offset)
+ {
+ if (bestAlias->size == 0
+ || sym->img_offset < bestAlias->img_offset + bestAlias->size)
+ bestAlias->size = (int) (sym->img_offset - bestAlias->img_offset);
+ continue;
+ }
+
+ // Find a "best" alias
+ bestLen = strlen (bestAlias->get_name ());
+ maxSize = bestAlias->size;
+ for (k = i + 1; k <= ind; k++)
+ {
+ sym = SymLst->fetch (k);
+ if (bestAlias->img_offset != sym->img_offset)
+ { // no more aliases
+ if ((maxSize == 0) ||
+ (sym->img_offset < bestAlias->img_offset + maxSize))
+ maxSize = sym->img_offset - bestAlias->img_offset;
+ break;
+ }
+ if (maxSize < sym->size)
+ maxSize = sym->size;
+ len = strlen (sym->get_name ());
+ if (len < bestLen)
+ {
+ bestAlias = sym;
+ bestLen = len;
+ }
+ }
+ for (; i < k; i++)
+ {
+ sym = SymLst->fetch (i);
+ sym->alias = bestAlias;
+ sym->size = maxSize;
+ }
+ i--;
+ }
+}
+
+void
+LoadObject::post_process_functions ()
+{
+ if (flags & SEG_FLAG_DYNAMIC || platform == Java)
+ return;
+
+ char *msg = GTXT ("Processing Load Object Data");
+ if (dbeSession->is_interactive ())
+ theApplication->set_progress (1, msg);
+
+ // First sort the functions
+ functions->sort (func_compare);
+ fixFuncAlias (functions);
+
+ Module *mitem;
+ int index;
+ Vec_loop (Module*, seg_modules, index, mitem)
+ {
+ mitem->functions->sort (func_compare);
+ }
+
+ // Find any derived functions, and set their derivedNode
+ Function *fitem;
+ Vec_loop (Function*, functions, index, fitem)
+ {
+ if (dbeSession->is_interactive () && index % 5000 == 0)
+ {
+ int percent = (int) (100.0 * index / functions->size ());
+ theApplication->set_progress (percent, (percent != 0) ? NULL : msg);
+ }
+ fitem->findDerivedFunctions ();
+ }
+
+ // 4987698: get the alias name for MAIN_
+ fitem = find_function (NTXT ("MAIN_"));
+ if (fitem)
+ fitem->module->read_stabs ();
+ fitem = find_function (NTXT ("@plt"));
+ if (fitem)
+ fitem->flags |= FUNC_FLAG_PLT;
+ if (dbeSession->is_interactive ())
+ theApplication->set_progress (0, NTXT (""));
+}
+
+int
+LoadObject::func_compare (const void *p1, const void *p2)
+{
+ Function *f1 = *(Function **) p1;
+ Function *f2 = *(Function **) p2;
+ if (f1->img_offset != f2->img_offset)
+ return f1->img_offset > f2->img_offset ? 1 : -1;
+
+ // annotated source not available for weak symbols.
+ if ((f1->module->flags & MOD_FLAG_UNKNOWN) != 0)
+ {
+ if ((f2->module->flags & MOD_FLAG_UNKNOWN) == 0)
+ return -1;
+ }
+ else if ((f2->module->flags & MOD_FLAG_UNKNOWN) != 0)
+ return 1;
+ return strcoll (f1->get_name (), f2->get_name ());
+}
+
+Function *
+LoadObject::find_function (char *fname)
+{
+ Function *fitem;
+ int index;
+ Vec_loop (Function*, functions, index, fitem)
+ {
+ if (strcmp (fitem->get_name (), fname) == 0)
+ return fitem;
+ }
+ return (Function *) NULL;
+}
+
+Function *
+LoadObject::find_function (char *fname, unsigned int chksum)
+{
+ Function *fitem;
+ int index;
+ Vec_loop (Function*, functions, index, fitem)
+ {
+ if (fitem->chksum == chksum && strcmp (fitem->get_name (), fname) == 0)
+ return fitem;
+ }
+ return (Function *) NULL;
+}
+
+Module *
+LoadObject::find_module (char *mname)
+{
+ for (int i = 0, sz = seg_modules ? seg_modules->size () : 0; i < sz; i++)
+ {
+ Module *module = seg_modules->fetch (i);
+ if (strcmp (module->get_name (), mname) == 0)
+ return module;
+ }
+ return (Module *) NULL;
+}
+
+LoadObject::Arch_status
+LoadObject::sync_read_stabs ()
+{
+ Arch_status st = ARCHIVE_SUCCESS;
+ if (!isReadStabs)
+ {
+ aquireLock ();
+ if (!isReadStabs)
+ {
+ st = read_stabs ();
+ post_process_functions ();
+ isReadStabs = true;
+ }
+ releaseLock ();
+ }
+ return st;
+}
+
+LoadObject::Arch_status
+LoadObject::read_stabs ()
+{
+ if ((dbeFile->filetype & DbeFile::F_FICTION) != 0)
+ return ARCHIVE_SUCCESS;
+ Arch_status stabs_status = ARCHIVE_ERR_OPEN;
+ if (platform == Java)
+ {
+ Module *cf = NULL;
+ for (int i = 0, sz = seg_modules ? seg_modules->size () : 0; i < sz; i++)
+ {
+ Module *mod = seg_modules->fetch (i);
+ if (mod->dbeFile
+ && (mod->dbeFile->filetype & DbeFile::F_JAVACLASS) != 0)
+ {
+ cf = mod;
+ break;
+ }
+ }
+ if (cf)
+ {
+ int status = cf->readFile ();
+ switch (status)
+ {
+ case Module::AE_OK:
+ stabs_status = ARCHIVE_SUCCESS;
+ break;
+ case Module::AE_NOSTABS:
+ stabs_status = ARCHIVE_NO_STABS;
+ break;
+ case Module::AE_NOTREAD:
+ default:
+ stabs_status = ARCHIVE_ERR_OPEN;
+ break;
+ }
+ }
+ }
+ else if (strchr (pathname, '`'))
+ return ARCHIVE_SUCCESS;
+ else
+ {
+ Arch_status st = ARCHIVE_WRONG_ARCH;
+ Elf *elf = get_elf ();
+ if (elf == NULL)
+ {
+ if (read_archive () == 0)
+ st = ARCHIVE_SUCCESS;
+ else
+ {
+ char *msg = dbe_sprintf (GTXT ("*** Warning: Can't open file: %s"),
+ dbeFile->get_name ());
+ warnq->append (new Emsg (CMSG_ERROR, msg));
+ delete msg;
+ }
+ }
+ else if (checksum != 0 && checksum != elf->elf_checksum ())
+ {
+ if (read_archive () == 0)
+ st = ARCHIVE_SUCCESS;
+ else
+ {
+ char *msg = dbe_sprintf (
+ GTXT ("*** Note: '%s' has an unexpected checksum value; perhaps it was rebuilt. File ignored"),
+ dbeFile->get_location ());
+ commentq->append (new Emsg (CMSG_ERROR, msg));
+ delete msg;
+ }
+ }
+ if (st == ARCHIVE_SUCCESS) // An old archive is used
+ return st;
+
+ Stabs::Stab_status status = Stabs::DBGD_ERR_CANT_OPEN_FILE;
+ char *location = dbeFile->get_location (true);
+ if (location == NULL)
+ return ARCHIVE_ERR_OPEN;
+
+ if (openDebugInfo (location, &status))
+ {
+ status = objStabs->read_archive (this);
+ isRelocatable = objStabs->is_relocatable ();
+ size = objStabs->get_textsz ();
+ platform = objStabs->get_platform ();
+ wsize = objStabs->get_class ();
+ }
+
+ switch (status)
+ {
+ case Stabs::DBGD_ERR_NONE:
+ stabs_status = ARCHIVE_SUCCESS;
+ break;
+ case Stabs::DBGD_ERR_CANT_OPEN_FILE:
+ stabs_status = ARCHIVE_ERR_OPEN;
+ break;
+ case Stabs::DBGD_ERR_BAD_ELF_LIB:
+ case Stabs::DBGD_ERR_BAD_ELF_FORMAT:
+ stabs_status = ARCHIVE_BAD_STABS;
+ break;
+ case Stabs::DBGD_ERR_NO_STABS:
+ stabs_status = ARCHIVE_NO_STABS;
+ break;
+ case Stabs::DBGD_ERR_NO_DWARF:
+ stabs_status = ARCHIVE_NO_DWARF;
+ break;
+ default:
+ stabs_status = ARCHIVE_BAD_STABS;
+ break;
+ }
+ }
+ return stabs_status;
+}
+
+#define ARCH_STRLEN(s) ((strlen(s) + 4) & ~0x3 )
+
+static int
+offsetCmp (const void *a, const void *b)
+{
+ uint32_t o1 = ((inst_info_t *) a)->offset;
+ uint32_t o2 = ((inst_info_t *) b)->offset;
+ return o1 == o2 ? 0 : (o1 < o2 ? -1 : 1);
+}
+
+int
+LoadObject::read_archive ()
+{
+ if (arch_name == NULL)
+ return 1;
+ Module *mod = NULL;
+ Function *func = NULL;
+ char *buf;
+ Data_window *dwin = new Data_window (arch_name);
+ if (dwin->not_opened ())
+ {
+ delete dwin;
+ buf = dbe_sprintf (GTXT ("*** Warning: Error opening file for reading: %s: %s"),
+ arch_name, strerror (errno));
+ warnq->append (new Emsg (CMSG_ERROR, buf));
+ delete buf;
+ return 1;
+ }
+ dwin->need_swap_endian = need_swap_endian;
+
+ // Prevent reading earlier archive files, which didn't support versioning.
+ int64_t offset = 0;
+ ARCH_common *cpkt = (ARCH_common*) dwin->bind (offset, sizeof (ARCH_common));
+ uint16_t v16;
+ if (cpkt)
+ {
+ v16 = (uint16_t) cpkt->type;
+ if (dwin->decode (v16) != ARCH_SEGMENT)
+ cpkt = NULL;
+ }
+ if (cpkt == NULL)
+ {
+ buf = dbe_sprintf (GTXT ("archive file malformed %s"), arch_name);
+ warnq->append (new Emsg (CMSG_WARN, buf));
+ delete buf;
+ return 1;
+ }
+
+ char *msg = NULL;
+ unsigned long long pointer_invalid = 0;
+ for (int64_t last_offset = -5000;;)
+ {
+ cpkt = (ARCH_common*) dwin->bind (offset, sizeof (ARCH_common));
+ if (cpkt == NULL)
+ break;
+ v16 = (uint16_t) cpkt->size;
+ uint32_t cpktsize = dwin->decode (v16);
+ cpkt = (ARCH_common*) dwin->bind (offset, cpktsize);
+ if ((cpkt == NULL) || (cpktsize == 0))
+ {
+ buf = dbe_sprintf (GTXT ("archive file malformed %s"), arch_name);
+ warnq->append (new Emsg (CMSG_WARN, buf));
+ delete buf;
+ break;
+ }
+
+ // Update the progress bar
+ if (dbeSession->is_interactive () && ((offset - last_offset) >= 5000))
+ {
+ last_offset = offset;
+ int percent = (int) (100.0 * offset / dwin->get_fsize ());
+ if (msg == NULL)
+ msg = dbe_sprintf (GTXT ("Reading Load Object Data: %s"), name);
+ theApplication->set_progress (percent, (percent != 0) ? NULL : msg);
+ }
+ char *ptr = (char *) cpkt;
+ v16 = (uint16_t) cpkt->type;
+ switch (dwin->decode (v16))
+ {
+ case ARCH_SEGMENT:
+ {
+ ARCH_segment *aseg = (ARCH_segment*) cpkt;
+ if (dwin->decode (aseg->version) != ARCH_VERSION)
+ {
+ buf = dbe_sprintf (GTXT ("Archive file version mismatch for %s"), arch_name);
+ warnq->append (new Emsg (CMSG_ERROR, buf));
+ delete buf;
+ if (dbeSession->is_interactive ())
+ theApplication->set_progress (0, "");
+ return 1;
+ }
+ if (size == 0)
+ size = dwin->decode (aseg->textsz);
+ Platform_t pltf = (Platform_t) dwin->decode (aseg->platform);
+ if (pltf != Unknown)
+ {
+ platform = pltf; // override if known
+ wsize = (platform == Sparcv9 || platform == Amd64) ? W64 : W32;
+ }
+ break;
+ }
+ case ARCH_MSG:
+ {
+ ARCH_message *amsg = (ARCH_message*) cpkt;
+ buf = status_str ((Arch_status) dwin->decode (amsg->errcode));
+ commentq->append (new Emsg (CMSG_ARCHIVE, buf));
+ free (buf);
+ break;
+ }
+ case ARCH_INF:
+ {
+ ARCH_info *ainf = (ARCH_info*) cpkt;
+ Emsg *m = new Emsg (CMSG_ARCHIVE, (char*) (ainf + 1));
+ commentq->append (m);
+ break;
+ }
+ case ARCH_MODULE:
+ {
+ ARCH_module *amod = (ARCH_module*) cpkt;
+ char *str = ((char*) amod) + sizeof (ARCH_module);
+ if (streq (str, SP_UNKNOWN_NAME) &&
+ streq (str + ARCH_STRLEN (str), SP_UNKNOWN_NAME))
+ {
+ mod = noname;
+ break;
+ }
+ mod = dbeSession->createModule (this, str);
+ mod->lang_code = (Sp_lang_code) dwin->decode (amod->lang_code);
+ mod->fragmented = dwin->decode (amod->fragmented);
+ str += ARCH_STRLEN (str);
+ mod->set_file_name (dbe_strdup (str));
+ modules->put (get_basename (str), mod);
+ break;
+ }
+ case ARCH_FUNCTION:
+ {
+ if (mod == NULL)
+ break;
+ ARCH_function *afnc = (ARCH_function*) cpkt;
+ func = dbeSession->createFunction ();
+ func->img_offset = dwin->decode (afnc->offset);
+ func->size = dwin->decode (afnc->size);
+ func->save_addr = dwin->decode (afnc->save_addr)
+ - dwin->decode (afnc->offset);
+ func->module = mod;
+ func->set_name (((char*) afnc) + sizeof (ARCH_function));
+ mod->functions->append (func);
+ functions->append (func);
+ break;
+ }
+ case ARCH_LDINSTR:
+ if (mod == NULL)
+ break;
+ Dprintf (DEBUG_LOADOBJ, "LDINSTR list for %s\n", mod->get_name ());
+ if (mod->infoList == NULL)
+ mod->infoList = new Vector<inst_info_t*>;
+ for (memop_info_t *mp = (memop_info_t*) (ptr + sizeof (ARCH_aninfo));
+ (char*) mp < ptr + cpktsize; mp++)
+ {
+ memop_info_t *memop = new memop_info_t;
+ memop->offset = dwin->decode (mp->offset);
+ memop->id = dwin->decode (mp->id);
+ memop->signature = dwin->decode (mp->signature);
+ memop->datatype_id = dwin->decode (mp->datatype_id);
+ mod->ldMemops.append (memop);
+
+ inst_info_t *instop = new inst_info_t;
+ instop->type = CPF_INSTR_TYPE_LD;
+ instop->offset = memop->offset;
+ instop->memop = memop;
+ mod->infoList->incorporate (instop, offsetCmp);
+ Dprintf (DEBUG_LOADOBJ,
+ "ld: offset=0x%04x id=0x%08x sig=0x%08x dtid=0x%08x\n",
+ memop->offset, memop->id, memop->signature,
+ memop->datatype_id);
+ }
+ Dprintf (DEBUG_LOADOBJ, "LDINSTR list of %lld for %s\n",
+ (long long) mod->ldMemops.size (), mod->get_name ());
+ break;
+ case ARCH_STINSTR:
+ if (mod == NULL)
+ break;
+ Dprintf (DEBUG_LOADOBJ, NTXT ("STINSTR list for %s\n"), mod->get_name ());
+ if (mod->infoList == NULL)
+ mod->infoList = new Vector<inst_info_t*>;
+ for (memop_info_t *mp = (memop_info_t*) (ptr + sizeof (ARCH_aninfo));
+ ((char *) mp) < ptr + cpktsize; mp++)
+ {
+ memop_info_t *memop = new memop_info_t;
+ memop->offset = dwin->decode (mp->offset);
+ memop->id = dwin->decode (mp->id);
+ memop->signature = dwin->decode (mp->signature);
+ memop->datatype_id = dwin->decode (mp->datatype_id);
+ mod->stMemops.append (memop);
+
+ inst_info_t *instop = new inst_info_t;
+ instop->type = CPF_INSTR_TYPE_ST;
+ instop->offset = memop->offset;
+ instop->memop = memop;
+ mod->infoList->incorporate (instop, offsetCmp);
+ Dprintf (DEBUG_LOADOBJ,
+ "st: offset=0x%04x id=0x%08x sig=0x%08x dtid=0x%08x\n",
+ memop->offset, memop->id, memop->signature,
+ memop->datatype_id);
+ }
+ Dprintf (DEBUG_LOADOBJ, "STINSTR list of %lld for %s\n",
+ (long long) mod->stMemops.size (), mod->get_name ());
+ break;
+ case ARCH_PREFETCH:
+ if (mod == NULL)
+ break;
+ Dprintf (DEBUG_LOADOBJ, "PFINSTR list for %s\n", mod->get_name ());
+ if (mod->infoList == NULL)
+ mod->infoList = new Vector<inst_info_t*>;
+ for (memop_info_t *mp = (memop_info_t*) (ptr + sizeof (ARCH_aninfo));
+ ((char*) mp) < ptr + cpkt->size; mp++)
+ {
+ memop_info_t *memop = new memop_info_t;
+ memop->offset = dwin->decode (mp->offset);
+ memop->id = dwin->decode (mp->id);
+ memop->signature = dwin->decode (mp->signature);
+ memop->datatype_id = dwin->decode (mp->datatype_id);
+ mod->pfMemops.append (memop);
+
+ inst_info_t *instop = new inst_info_t;
+ instop->type = CPF_INSTR_TYPE_PREFETCH;
+ instop->offset = memop->offset;
+ instop->memop = memop;
+ mod->infoList->incorporate (instop, offsetCmp);
+ Dprintf (DEBUG_LOADOBJ,
+ "pf: offset=0x%04x id=0x%08x sig=0x%08x dtid=0x%08x\n",
+ memop->offset, memop->id, memop->signature,
+ memop->datatype_id);
+ }
+ Dprintf (DEBUG_LOADOBJ, "PFINSTR list of %lld for %s\n",
+ (long long) mod->pfMemops.size (), mod->get_name ());
+ break;
+ case ARCH_BRTARGET:
+ if (mod == NULL)
+ break;
+ for (target_info_t *tp = (target_info_t*) (ptr + sizeof (ARCH_aninfo));
+ ((char*) tp) < ptr + cpkt->size; tp++)
+ {
+ target_info_t *bTarget = new target_info_t;
+ bTarget->offset = dwin->decode (tp->offset);
+ mod->bTargets.append (bTarget);
+ }
+ Dprintf (DEBUG_LOADOBJ, "BRTARGET list of %lld for %s\n",
+ (long long) mod->infoList->size (), mod->get_name ());
+ break;
+ default:
+ /* Check if the prointer is valid - should be even. */
+ pointer_invalid = (unsigned long long) (offset + cpktsize) & 1;
+ break; // ignore unknown packets
+ }
+ if (pointer_invalid)
+ break;
+ offset += cpktsize;
+ }
+ delete msg;
+ delete dwin;
+
+ if (dbeSession->is_interactive ())
+ theApplication->set_progress (0, NTXT (""));
+ return 0;
+}
+
+char *
+LoadObject::status_str (Arch_status rv, char */*arg*/)
+{
+ switch (rv)
+ {
+ case ARCHIVE_SUCCESS:
+ case ARCHIVE_EXIST:
+ return NULL;
+ case ARCHIVE_BAD_STABS:
+ return dbe_sprintf (GTXT ("Error: unable to read symbol table of %s"),
+ name);
+ case ARCHIVE_ERR_SEG:
+ return dbe_sprintf (GTXT ("Error: unable to read load object file %s"),
+ pathname);
+ case ARCHIVE_ERR_OPEN:
+ return dbe_sprintf (GTXT ("Error: unable to open file %s"),
+ pathname);
+ case ARCHIVE_ERR_MAP:
+ return dbe_sprintf (GTXT ("Error: unable to map file %s"),
+ pathname);
+ case ARCHIVE_WARN_CHECKSUM:
+ return dbe_sprintf (GTXT ("Note: checksum differs from that recorded in experiment for %s"),
+ name);
+ case ARCHIVE_WARN_MTIME:
+ return dbe_sprintf (GTXT ("Warning: last-modified time differs from that recorded in experiment for %s"),
+ name);
+ case ARCHIVE_WARN_HOST:
+ return dbe_sprintf (GTXT ("Try running er_archive -F on the experiment, on the host where it was recorded"));
+ case ARCHIVE_ERR_VERSION:
+ return dbe_sprintf (GTXT ("Error: Wrong version of archive for %s"),
+ pathname);
+ case ARCHIVE_NO_STABS:
+ return dbe_sprintf (GTXT ("Note: no stabs or dwarf information in %s"),
+ name);
+ case ARCHIVE_WRONG_ARCH:
+#if ARCH(SPARC)
+ return dbe_sprintf (GTXT ("Error: file %s is built for Intel, and can't be read on SPARC"),
+ name);
+#else
+ return dbe_sprintf (GTXT ("Error: file %s is built for SPARC, and can't be read on Intel"),
+ name);
+#endif
+ case ARCHIVE_NO_LIBDWARF:
+ return dbe_strdup (GTXT ("Warning: no libdwarf found to read DWARF symbol tables"));
+ case ARCHIVE_NO_DWARF:
+ return dbe_sprintf (GTXT ("Note: no DWARF symbol table in %s"), name);
+ default:
+ return dbe_sprintf (GTXT ("Warning: unexpected archive error %d"),
+ (int) rv);
+ }
+}
+
+uint32_t
+LoadObject::get_checksum ()
+{
+ char *errmsg = NULL;
+ uint32_t crcval = get_cksum (pathname, &errmsg);
+ if (0 == crcval && errmsg)
+ {
+ warnq->append (new Emsg (CMSG_ERROR, errmsg));
+ free (errmsg);
+ }
+ return crcval;
+}
+
+static char*
+get_module_map_key (Module *mod)
+{
+ return mod->lang_code == Sp_lang_java ? mod->get_name () : mod->file_name;
+}
+
+Module *
+LoadObject::get_comparable_Module (Module *mod)
+{
+ if (mod->loadobject == this)
+ return mod;
+ if (get_module_map_key (mod) == NULL)
+ return NULL;
+ if (seg_modules_map == NULL)
+ {
+ seg_modules_map = new HashMap<char*, Module*>;
+ for (int i = 0; i < seg_modules->size (); i++)
+ {
+ Module *m = seg_modules->fetch (i);
+ char *key = get_module_map_key (m);
+ if (key)
+ {
+ seg_modules_map->put (m->file_name, m);
+ char *bname = get_basename (key);
+ if (bname != key)
+ seg_modules_map->put (bname, m);
+ }
+ }
+ }
+
+ char *key = get_module_map_key (mod);
+ Module *cmpMod = seg_modules_map->get (key);
+ if (cmpMod && cmpMod->comparable_objs == NULL)
+ return cmpMod;
+ char *bname = get_basename (key);
+ if (bname != key)
+ {
+ cmpMod = seg_modules_map->get (bname);
+ if (cmpMod && cmpMod->comparable_objs == NULL)
+ return cmpMod;
+ }
+ return NULL;
+}
+
+Vector<Histable*> *
+LoadObject::get_comparable_objs ()
+{
+ update_comparable_objs ();
+ if (comparable_objs || dbeSession->expGroups->size () <= 1)
+ return comparable_objs;
+ comparable_objs = new Vector<Histable*>(dbeSession->expGroups->size ());
+ for (int i = 0, sz = dbeSession->expGroups->size (); i < sz; i++)
+ {
+ ExpGroup *gr = dbeSession->expGroups->fetch (i);
+ Histable *h = gr->get_comparable_loadObject (this);
+ comparable_objs->append (h);
+ if (h)
+ h->comparable_objs = comparable_objs;
+ }
+ dump_comparable_objs ();
+ return comparable_objs;
+}
+
+void
+LoadObject::append_module (Module *mod)
+{
+ seg_modules->append (mod);
+ if (seg_modules_map == NULL)
+ seg_modules_map = new HashMap<char*, Module*>;
+ char *key = get_module_map_key (mod);
+ if (key)
+ {
+ seg_modules_map->put (key, mod);
+ char *bname = get_basename (key);
+ if (bname != key)
+ seg_modules_map->put (bname, mod);
+ }
+}
+
+// LIBRARY_VISIBILITY
+Function *
+LoadObject::get_hide_function ()
+{
+ if (h_function == NULL)
+ h_function = dbeSession->create_hide_function (this);
+ return h_function;
+}
+
+DbeInstr *
+LoadObject::get_hide_instr (DbeInstr *instr)
+{
+ if (h_instr == NULL)
+ {
+ Function *hf = get_hide_function ();
+ h_instr = hf->create_hide_instr (instr);
+ }
+ return h_instr;
+}