Retro68/binutils/gprofng/src/LoadObject.cc
Wolfgang Thaller f485e125c4 binutils 2.39
2022-10-27 20:45:45 +02:00

1243 lines
32 KiB
C++

/* 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;
}