mirror of
https://github.com/autc04/Retro68.git
synced 2024-06-07 13:33:06 +00:00
1243 lines
32 KiB
C++
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;
|
|
}
|