Merge zizzer:/bk/m5 into isabel.reinhardt.house:/z/stever/bk/m5
--HG-- extra : convert_revision : a0f7a0793b4c413b8c004633707b1a992f79e8d1
This commit is contained in:
commit
bd360b6b97
17 changed files with 1747 additions and 159 deletions
41
arch/alpha/aout_machdep.h
Normal file
41
arch/alpha/aout_machdep.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/* $Id$ */
|
||||
|
||||
#ifndef __AOUT_MACHDEP_H__
|
||||
#define __AOUT_MACHDEP_H__
|
||||
|
||||
///
|
||||
/// Funky Alpha 64-bit a.out header used for PAL code.
|
||||
///
|
||||
struct aout_exechdr {
|
||||
uint16_t magic;
|
||||
uint16_t vstamp;
|
||||
uint16_t bldrev;
|
||||
uint16_t padcell;
|
||||
uint64_t tsize; // text segment size
|
||||
uint64_t dsize; // data segment size
|
||||
uint64_t bsize; // bss segment size
|
||||
uint64_t entry; // entry point
|
||||
uint64_t text_start; // text base address
|
||||
uint64_t data_start; // data base address
|
||||
uint64_t bss_start; // bss base address
|
||||
uint32_t gprmask;
|
||||
uint32_t fprmask;
|
||||
uint64_t gp_value;
|
||||
};
|
||||
|
||||
#define AOUT_LDPGSZ 8192
|
||||
|
||||
#define N_GETMAGIC(ex) ((ex).magic)
|
||||
|
||||
#define N_BADMAX
|
||||
|
||||
#define N_TXTADDR(ex) ((ex).text_start)
|
||||
#define N_DATADDR(ex) ((ex).data_start)
|
||||
#define N_BSSADDR(ex) ((ex).bss_start)
|
||||
|
||||
#define N_TXTOFF(ex) \
|
||||
(N_GETMAGIC(ex) == ZMAGIC ? 0 : sizeof(struct aout_exechdr))
|
||||
|
||||
#define N_DATOFF(ex) N_ALIGN(ex, N_TXTOFF(ex) + (ex).tsize)
|
||||
|
||||
#endif /* !__AOUT_MACHDEP_H__*/
|
75
arch/alpha/ecoff_machdep.h
Normal file
75
arch/alpha/ecoff_machdep.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* Taken from NetBSD arch/alpha/ecoff_machdep.h
|
||||
*/
|
||||
|
||||
/* $NetBSD: ecoff_machdep.h,v 1.5 1999/04/27 02:32:33 cgd Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1994 Adam Glass
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Adam Glass.
|
||||
* 4. The name of the Author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Adam Glass ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL Adam Glass BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
//
|
||||
// Define COFF/ECOFF integer type sizes
|
||||
//
|
||||
typedef int16_t coff_short;
|
||||
typedef uint16_t coff_ushort;
|
||||
typedef int32_t coff_int;
|
||||
typedef uint32_t coff_uint;
|
||||
typedef int64_t coff_long;
|
||||
typedef uint64_t coff_ulong;
|
||||
typedef uint64_t coff_addr;
|
||||
|
||||
#define ECOFF_LDPGSZ 4096
|
||||
|
||||
#define ECOFF_PAD \
|
||||
coff_ushort bldrev; /* XXX */
|
||||
|
||||
#define ECOFF_MACHDEP \
|
||||
coff_uint gprmask; \
|
||||
coff_uint fprmask; \
|
||||
coff_ulong gp_value
|
||||
|
||||
#define ECOFF_MAGIC_ALPHA 0603
|
||||
#define ECOFF_MAGIC_NETBSD_ALPHA 0605
|
||||
#define ECOFF_BADMAG(ep) \
|
||||
((ep)->f.f_magic != ECOFF_MAGIC_ALPHA && \
|
||||
(ep)->f.f_magic != ECOFF_MAGIC_NETBSD_ALPHA)
|
||||
|
||||
#define ECOFF_FLAG_EXEC 0002
|
||||
#define ECOFF_SEGMENT_ALIGNMENT(ep) \
|
||||
(((ep)->f.f_flags & ECOFF_FLAG_EXEC) == 0 ? 8 : 16)
|
||||
|
||||
#define ECOFF_FLAG_OBJECT_TYPE_MASK 0x3000
|
||||
#define ECOFF_OBJECT_TYPE_NO_SHARED 0x1000
|
||||
#define ECOFF_OBJECT_TYPE_SHARABLE 0x2000
|
||||
#define ECOFF_OBJECT_TYPE_CALL_SHARED 0x3000
|
||||
|
111
base/aout_object.cc
Normal file
111
base/aout_object.cc
Normal file
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Copyright (c) 2003 The Regents of The University of Michigan
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer;
|
||||
* redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution;
|
||||
* neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "aout_object.hh"
|
||||
|
||||
#include "functional_memory.hh"
|
||||
#include "symtab.hh"
|
||||
|
||||
#include "trace.hh" // for DPRINTF
|
||||
|
||||
#include "exec_aout.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
ObjectFile *
|
||||
AoutObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data)
|
||||
{
|
||||
if (!N_BADMAG(*(aout_exechdr *)data)) {
|
||||
return new AoutObject(fname, fd, len, data);
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AoutObject::AoutObject(const string &_filename, int _fd,
|
||||
size_t _len, uint8_t *_data)
|
||||
: ObjectFile(_filename, _fd, _len, _data)
|
||||
{
|
||||
execHdr = (aout_exechdr *)fileData;
|
||||
|
||||
entry = execHdr->entry;
|
||||
|
||||
text.baseAddr = N_TXTADDR(*execHdr);
|
||||
text.size = execHdr->tsize;
|
||||
|
||||
data.baseAddr = N_DATADDR(*execHdr);
|
||||
data.size = execHdr->dsize;
|
||||
|
||||
bss.baseAddr = N_BSSADDR(*execHdr);
|
||||
bss.size = execHdr->bsize;
|
||||
|
||||
DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n",
|
||||
text.baseAddr, text.size, data.baseAddr, data.size,
|
||||
bss.baseAddr, bss.size);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
AoutObject::loadSections(FunctionalMemory *mem, bool loadPhys)
|
||||
{
|
||||
Addr textAddr = text.baseAddr;
|
||||
Addr dataAddr = data.baseAddr;
|
||||
|
||||
if (loadPhys) {
|
||||
textAddr &= (ULL(1) << 40) - 1;
|
||||
dataAddr &= (ULL(1) << 40) - 1;
|
||||
}
|
||||
|
||||
// Since we don't really have an MMU and all memory is
|
||||
// zero-filled, there's no need to set up the BSS segment.
|
||||
if (text.size != 0)
|
||||
mem->prot_write(textAddr, fileData + N_TXTOFF(*execHdr), text.size);
|
||||
if (data.size != 0)
|
||||
mem->prot_write(dataAddr, fileData + N_DATOFF(*execHdr), data.size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
AoutObject::loadGlobalSymbols(SymbolTable *symtab)
|
||||
{
|
||||
// a.out symbols not supported yet
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
AoutObject::loadLocalSymbols(SymbolTable *symtab)
|
||||
{
|
||||
// a.out symbols not supported yet
|
||||
return false;
|
||||
}
|
57
base/aout_object.hh
Normal file
57
base/aout_object.hh
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (c) 2003 The Regents of The University of Michigan
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer;
|
||||
* redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution;
|
||||
* neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __AOUT_OBJECT_HH__
|
||||
#define __AOUT_OBJECT_HH__
|
||||
|
||||
#include "object_file.hh"
|
||||
|
||||
// forward decls: avoid including exec_aout.h here
|
||||
struct aout_exechdr;
|
||||
|
||||
class AoutObject : public ObjectFile
|
||||
{
|
||||
protected:
|
||||
aout_exechdr *execHdr;
|
||||
|
||||
AoutObject(const std::string &_filename, int _fd,
|
||||
size_t _len, uint8_t *_data);
|
||||
|
||||
public:
|
||||
virtual ~AoutObject() {}
|
||||
|
||||
virtual bool loadSections(FunctionalMemory *mem,
|
||||
bool loadPhys = false);
|
||||
virtual bool loadGlobalSymbols(SymbolTable *symtab);
|
||||
virtual bool loadLocalSymbols(SymbolTable *symtab);
|
||||
|
||||
static ObjectFile *tryFile(const std::string &fname, int fd,
|
||||
size_t len, uint8_t *data);
|
||||
};
|
||||
|
||||
#endif // __AOUT_OBJECT_HH__
|
491
base/coff_sym.h
Normal file
491
base/coff_sym.h
Normal file
|
@ -0,0 +1,491 @@
|
|||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* Taken from binutils-2.14.90.0.5 include/coff/sym.h
|
||||
*/
|
||||
|
||||
/* Declarations of internal format of MIPS ECOFF symbols.
|
||||
Originally contributed by MIPS Computer Systems and Third Eye Software.
|
||||
Changes contributed by Cygnus Support are in the public domain.
|
||||
|
||||
This file is just aggregated with the files that make up the GNU
|
||||
release; it is not considered part of GAS, GDB, or other GNU
|
||||
programs. */
|
||||
|
||||
/*
|
||||
* |-----------------------------------------------------------|
|
||||
* | Copyright (c) 1992, 1991, 1990 MIPS Computer Systems, Inc.|
|
||||
* | MIPS Computer Systems, Inc. grants reproduction and use |
|
||||
* | rights to all parties, PROVIDED that this comment is |
|
||||
* | maintained in the copy. |
|
||||
* |-----------------------------------------------------------|
|
||||
*/
|
||||
#ifndef _SYM_H
|
||||
#define _SYM_H
|
||||
|
||||
/* (C) Copyright 1984 by Third Eye Software, Inc.
|
||||
*
|
||||
* Third Eye Software, Inc. grants reproduction and use rights to
|
||||
* all parties, PROVIDED that this comment is maintained in the copy.
|
||||
*
|
||||
* Third Eye makes no claims about the applicability of this
|
||||
* symbol table to a particular use.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains the definition of the Third Eye Symbol Table.
|
||||
*
|
||||
* Symbols are assumed to be in 'encounter order' - i.e. the order that
|
||||
* the things they represent were encountered by the compiler/assembler/loader.
|
||||
* EXCEPT for globals! These are assumed to be bunched together,
|
||||
* probably right after the last 'normal' symbol. Globals ARE sorted
|
||||
* in ascending order.
|
||||
*
|
||||
* -----------------------------------------------------------------------
|
||||
* A brief word about Third Eye naming/use conventions:
|
||||
*
|
||||
* All arrays and index's are 0 based.
|
||||
* All "ifooMax" values are the highest legal value PLUS ONE. This makes
|
||||
* them good for allocating arrays, etc. All checks are "ifoo < ifooMax".
|
||||
*
|
||||
* "isym" Index into the SYMbol table.
|
||||
* "ipd" Index into the Procedure Descriptor array.
|
||||
* "ifd" Index into the File Descriptor array.
|
||||
* "iss" Index into String Space.
|
||||
* "cb" Count of Bytes.
|
||||
* "rgPd" array whose domain is "0..ipdMax-1" and RanGe is PDR.
|
||||
* "rgFd" array whose domain is "0..ifdMax-1" and RanGe is FDR.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Symbolic Header (HDR) structure.
|
||||
* As long as all the pointers are set correctly,
|
||||
* we don't care WHAT order the various sections come out in!
|
||||
*
|
||||
* A file produced solely for the use of CDB will probably NOT have
|
||||
* any instructions or data areas in it, as these are available
|
||||
* in the original.
|
||||
*/
|
||||
|
||||
typedef struct ecoff_symhdr {
|
||||
coff_short magic; /* to verify validity of the table */
|
||||
coff_short vstamp; /* version stamp */
|
||||
coff_int ilineMax; /* number of line number entries */
|
||||
coff_int idnMax; /* max index into dense number table */
|
||||
coff_int ipdMax; /* number of procedures */
|
||||
coff_int isymMax; /* number of local symbols */
|
||||
coff_int ioptMax; /* max index into optimization symbol entries */
|
||||
coff_int iauxMax; /* number of auxillary symbol entries */
|
||||
coff_int issMax; /* max index into local strings */
|
||||
coff_int issExtMax; /* max index into external strings */
|
||||
coff_int ifdMax; /* number of file descriptor entries */
|
||||
coff_int crfd; /* number of relative file descriptor entries */
|
||||
coff_int iextMax; /* max index into external symbols */
|
||||
coff_addr cbLine; /* number of bytes for line number entries */
|
||||
coff_addr cbLineOffset; /* offset to start of line number entries*/
|
||||
coff_addr cbDnOffset; /* offset to start dense number table */
|
||||
coff_addr cbPdOffset; /* offset to procedure descriptor table */
|
||||
coff_addr cbSymOffset; /* offset to start of local symbols*/
|
||||
coff_addr cbOptOffset; /* offset to optimization symbol entries */
|
||||
coff_addr cbAuxOffset; /* offset to start of auxillary symbol entries*/
|
||||
coff_addr cbSsOffset; /* offset to start of local strings */
|
||||
coff_addr cbSsExtOffset; /* offset to start of external strings */
|
||||
coff_addr cbFdOffset; /* offset to file descriptor table */
|
||||
coff_addr cbRfdOffset; /* offset to relative file descriptor table */
|
||||
coff_addr cbExtOffset; /* offset to start of external symbol entries*/
|
||||
/* If you add machine dependent fields, add them here */
|
||||
} HDRR, *pHDRR;
|
||||
#define cbHDRR sizeof(HDRR)
|
||||
#define hdrNil ((pHDRR)0)
|
||||
|
||||
/*
|
||||
* The FDR and PDR structures speed mapping of address <-> name.
|
||||
* They are sorted in ascending memory order and are kept in
|
||||
* memory by CDB at runtime.
|
||||
*/
|
||||
|
||||
/*
|
||||
* File Descriptor
|
||||
*
|
||||
* There is one of these for EVERY FILE, whether compiled with
|
||||
* full debugging symbols or not. The name of a file should be
|
||||
* the path name given to the compiler. This allows the user
|
||||
* to simply specify the names of the directories where the COMPILES
|
||||
* were done, and we will be able to find their files.
|
||||
* A field whose comment starts with "R - " indicates that it will be
|
||||
* setup at runtime.
|
||||
*/
|
||||
typedef struct ecoff_fdr {
|
||||
coff_addr adr; /* memory address of beginning of file */
|
||||
coff_addr cbLineOffset; /* byte offset from header for this file ln's */
|
||||
coff_addr cbLine; /* size of lines for this file */
|
||||
coff_addr cbSs; /* number of bytes in the ss */
|
||||
coff_int rss; /* file name (of source, if known) */
|
||||
coff_int issBase; /* file's string space */
|
||||
coff_int isymBase; /* beginning of symbols */
|
||||
coff_int csym; /* count file's of symbols */
|
||||
coff_int ilineBase; /* file's line symbols */
|
||||
coff_int cline; /* count of file's line symbols */
|
||||
coff_int ioptBase; /* file's optimization entries */
|
||||
coff_int copt; /* count of file's optimization entries */
|
||||
coff_int ipdFirst; /* start of procedures for this file */
|
||||
coff_int cpd; /* count of procedures for this file */
|
||||
coff_int iauxBase; /* file's auxiliary entries */
|
||||
coff_int caux; /* count of file's auxiliary entries */
|
||||
coff_int rfdBase; /* index into the file indirect table */
|
||||
coff_int crfd; /* count file indirect entries */
|
||||
unsigned lang: 5; /* language for this file */
|
||||
unsigned fMerge : 1; /* whether this file can be merged */
|
||||
unsigned fReadin : 1; /* true if it was read in (not just created) */
|
||||
unsigned fBigendian : 1;/* if set, was compiled on big endian machine */
|
||||
/* aux's will be in compile host's sex */
|
||||
unsigned glevel : 2; /* level this file was compiled with */
|
||||
unsigned reserved : 22; /* reserved for future use */
|
||||
coff_uint reserved2;
|
||||
} FDR, *pFDR;
|
||||
#define cbFDR sizeof(FDR)
|
||||
#define fdNil ((pFDR)0)
|
||||
#define ifdNil -1
|
||||
#define ifdTemp 0
|
||||
#define ilnNil -1
|
||||
|
||||
|
||||
/*
|
||||
* Procedure Descriptor
|
||||
*
|
||||
* There is one of these for EVERY TEXT LABEL.
|
||||
* If a procedure is in a file with full symbols, then isym
|
||||
* will point to the PROC symbols, else it will point to the
|
||||
* global symbol for the label.
|
||||
*/
|
||||
|
||||
typedef struct pdr {
|
||||
coff_addr adr; /* memory address of start of procedure */
|
||||
coff_addr cbLineOffset; /* byte offset for this procedure from the fd base */
|
||||
coff_int isym; /* start of local symbol entries */
|
||||
coff_int iline; /* start of line number entries*/
|
||||
coff_uint regmask; /* save register mask */
|
||||
coff_int regoffset; /* save register offset */
|
||||
coff_int iopt; /* start of optimization symbol entries*/
|
||||
coff_uint fregmask; /* save floating point register mask */
|
||||
coff_int fregoffset; /* save floating point register offset */
|
||||
coff_int frameoffset; /* frame size */
|
||||
coff_int lnLow; /* lowest line in the procedure */
|
||||
coff_int lnHigh; /* highest line in the procedure */
|
||||
/* These fields are new for 64 bit ECOFF. */
|
||||
unsigned gp_prologue : 8; /* byte size of GP prologue */
|
||||
unsigned gp_used : 1; /* true if the procedure uses GP */
|
||||
unsigned reg_frame : 1; /* true if register frame procedure */
|
||||
unsigned prof : 1; /* true if compiled with -pg */
|
||||
unsigned reserved : 13; /* reserved: must be zero */
|
||||
unsigned localoff : 8; /* offset of local variables from vfp */
|
||||
coff_short framereg; /* frame pointer register */
|
||||
coff_short pcreg; /* offset or reg of return pc */
|
||||
} PDR, *pPDR;
|
||||
#define cbPDR sizeof(PDR)
|
||||
#define pdNil ((pPDR) 0)
|
||||
#define ipdNil -1
|
||||
|
||||
/*
|
||||
* The structure of the runtime procedure descriptor created by the loader
|
||||
* for use by the static exception system.
|
||||
*/
|
||||
/*
|
||||
* If 0'd out because exception_info chokes Visual C++ and because there
|
||||
* don't seem to be any references to this structure elsewhere in gdb.
|
||||
*/
|
||||
#if 0
|
||||
typedef struct runtime_pdr {
|
||||
coff_addr adr; /* memory address of start of procedure */
|
||||
coff_uint regmask; /* save register mask */
|
||||
coff_int regoffset; /* save register offset */
|
||||
coff_uint fregmask; /* save floating point register mask */
|
||||
coff_int fregoffset; /* save floating point register offset */
|
||||
coff_int frameoffset; /* frame size */
|
||||
coff_ushort framereg; /* frame pointer register */
|
||||
coff_ushort pcreg; /* offset or reg of return pc */
|
||||
coff_int irpss; /* index into the runtime string table */
|
||||
coff_uint reserved;
|
||||
struct exception_info *exception_info;/* pointer to exception array */
|
||||
} RPDR, *pRPDR;
|
||||
#define cbRPDR sizeof(RPDR)
|
||||
#define rpdNil ((pRPDR) 0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Line Numbers
|
||||
*
|
||||
* Line Numbers are segregated from the normal symbols because they
|
||||
* are [1] smaller , [2] are of no interest to your
|
||||
* average loader, and [3] are never needed in the middle of normal
|
||||
* scanning and therefore slow things down.
|
||||
*
|
||||
* By definition, the first LINER for any given procedure will have
|
||||
* the first line of a procedure and represent the first address.
|
||||
*/
|
||||
|
||||
typedef coff_int LINER, *pLINER;
|
||||
#define lineNil ((pLINER)0)
|
||||
#define cbLINER sizeof(LINER)
|
||||
#define ilineNil -1
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* The Symbol Structure (GFW, to those who Know!)
|
||||
*/
|
||||
|
||||
typedef struct ecoff_sym {
|
||||
coff_long value; /* value of symbol */
|
||||
coff_int iss; /* index into String Space of name */
|
||||
unsigned st : 6; /* symbol type */
|
||||
unsigned sc : 5; /* storage class - text, data, etc */
|
||||
unsigned reserved : 1; /* reserved */
|
||||
unsigned index : 20; /* index into sym/aux table */
|
||||
} SYMR, *pSYMR;
|
||||
#define symNil ((pSYMR)0)
|
||||
#define cbSYMR sizeof(SYMR)
|
||||
#define isymNil -1
|
||||
#define indexNil 0xfffff
|
||||
#define issNil -1
|
||||
#define issNull 0
|
||||
|
||||
|
||||
/* The following converts a memory resident string to an iss.
|
||||
* This hack is recognized in SbFIss, in sym.c of the debugger.
|
||||
*/
|
||||
#define IssFSb(sb) (0x80000000 | ((coff_ulong)(sb)))
|
||||
|
||||
/* E X T E R N A L S Y M B O L R E C O R D
|
||||
*
|
||||
* Same as the SYMR except it contains file context to determine where
|
||||
* the index is.
|
||||
*/
|
||||
typedef struct ecoff_extsym {
|
||||
SYMR asym; /* symbol for the external */
|
||||
unsigned jmptbl:1; /* symbol is a jump table entry for shlibs */
|
||||
unsigned cobol_main:1; /* symbol is a cobol main procedure */
|
||||
unsigned weakext:1; /* symbol is weak external */
|
||||
unsigned reserved:29; /* reserved for future use */
|
||||
coff_int ifd; /* where the iss and index fields point into */
|
||||
} EXTR, *pEXTR;
|
||||
#define extNil ((pEXTR)0)
|
||||
#define cbEXTR sizeof(EXTR)
|
||||
|
||||
|
||||
/* A U X I L L A R Y T Y P E I N F O R M A T I O N */
|
||||
|
||||
/*
|
||||
* Type Information Record
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned fBitfield : 1; /* set if bit width is specified */
|
||||
unsigned continued : 1; /* indicates additional TQ info in next AUX */
|
||||
unsigned bt : 6; /* basic type */
|
||||
unsigned tq4 : 4;
|
||||
unsigned tq5 : 4;
|
||||
/* ---- 16 bit boundary ---- */
|
||||
unsigned tq0 : 4;
|
||||
unsigned tq1 : 4; /* 6 type qualifiers - tqPtr, etc. */
|
||||
unsigned tq2 : 4;
|
||||
unsigned tq3 : 4;
|
||||
} TIR, *pTIR;
|
||||
#define cbTIR sizeof(TIR)
|
||||
#define tiNil ((pTIR)0)
|
||||
#define itqMax 6
|
||||
|
||||
/*
|
||||
* Relative symbol record
|
||||
*
|
||||
* If the rfd field is 4095, the index field indexes into the global symbol
|
||||
* table.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
unsigned rfd : 12; /* index into the file indirect table */
|
||||
unsigned index : 20; /* index int sym/aux/iss tables */
|
||||
} RNDXR, *pRNDXR;
|
||||
#define cbRNDXR sizeof(RNDXR)
|
||||
#define rndxNil ((pRNDXR)0)
|
||||
|
||||
/* dense numbers or sometimes called block numbers are stored in this type,
|
||||
* a rfd of 0xffffffff is an index into the global table.
|
||||
*/
|
||||
typedef struct {
|
||||
coff_uint rfd; /* index into the file table */
|
||||
coff_uint index; /* index int sym/aux/iss tables */
|
||||
} DNR, *pDNR;
|
||||
#define cbDNR sizeof(DNR)
|
||||
#define dnNil ((pDNR)0)
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Auxillary information occurs only if needed.
|
||||
* It ALWAYS occurs in this order when present.
|
||||
|
||||
isymMac used by stProc only
|
||||
TIR type info
|
||||
TIR additional TQ info (if first TIR was not enough)
|
||||
rndx if (bt == btStruct,btUnion,btEnum,btSet,btRange,
|
||||
btTypedef):
|
||||
rsym.index == iaux for btSet or btRange
|
||||
else rsym.index == isym
|
||||
dimLow btRange, btSet
|
||||
dimMac btRange, btSet
|
||||
rndx0 As many as there are tq arrays
|
||||
dimLow0
|
||||
dimHigh0
|
||||
...
|
||||
rndxMax-1
|
||||
dimLowMax-1
|
||||
dimHighMax-1
|
||||
width in bits if (bit field), width in bits.
|
||||
*/
|
||||
#define cAuxMax (6 + (idimMax*3))
|
||||
|
||||
/* a union of all possible info in the AUX universe */
|
||||
typedef union {
|
||||
TIR ti; /* type information record */
|
||||
RNDXR rndx; /* relative index into symbol table */
|
||||
coff_int dnLow; /* low dimension */
|
||||
coff_int dnHigh; /* high dimension */
|
||||
coff_int isym; /* symbol table index (end of proc) */
|
||||
coff_int iss; /* index into string space (not used) */
|
||||
coff_int width; /* width for non-default sized struc fields */
|
||||
coff_int count; /* count of ranges for variant arm */
|
||||
} AUXU, *pAUXU;
|
||||
#define cbAUXU sizeof(AUXU)
|
||||
#define auxNil ((pAUXU)0)
|
||||
#define iauxNil -1
|
||||
|
||||
|
||||
/*
|
||||
* Optimization symbols
|
||||
*
|
||||
* Optimization symbols contain some overlap information with the normal
|
||||
* symbol table. In particular, the proc information
|
||||
* is somewhat redundant but necessary to easily find the other information
|
||||
* present.
|
||||
*
|
||||
* All of the offsets are relative to the beginning of the last otProc
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
unsigned ot: 8; /* optimization type */
|
||||
unsigned value: 24; /* address where we are moving it to */
|
||||
RNDXR rndx; /* points to a symbol or opt entry */
|
||||
coff_ulong offset; /* relative offset this occured */
|
||||
} OPTR, *pOPTR;
|
||||
#define optNil ((pOPTR) 0)
|
||||
#define cbOPTR sizeof(OPTR)
|
||||
#define ioptNil -1
|
||||
|
||||
/*
|
||||
* File Indirect
|
||||
*
|
||||
* When a symbol is referenced across files the following procedure is used:
|
||||
* 1) use the file index to get the File indirect entry.
|
||||
* 2) use the file indirect entry to get the File descriptor.
|
||||
* 3) add the sym index to the base of that file's sym table
|
||||
*
|
||||
*/
|
||||
|
||||
typedef coff_long RFDT, *pRFDT;
|
||||
#define cbRFDT sizeof(RFDT)
|
||||
#define rfdNil -1
|
||||
|
||||
/*
|
||||
* The file indirect table in the mips loader is known as an array of FITs.
|
||||
* This is done to keep the code in the loader readable in the area where
|
||||
* these tables are merged. Note this is only a name change.
|
||||
*/
|
||||
typedef coff_int FIT, *pFIT;
|
||||
#define cbFIT sizeof(FIT)
|
||||
#define ifiNil -1
|
||||
#define fiNil ((pFIT) 0)
|
||||
|
||||
#ifdef _LANGUAGE_PASCAL
|
||||
#define ifdNil -1
|
||||
#define ilnNil -1
|
||||
#define ipdNil -1
|
||||
#define ilineNil -1
|
||||
#define isymNil -1
|
||||
#define indexNil 16#fffff
|
||||
#define issNil -1
|
||||
#define issNull 0
|
||||
#define itqMax 6
|
||||
#define iauxNil -1
|
||||
#define ioptNil -1
|
||||
#define rfdNil -1
|
||||
#define ifiNil -1
|
||||
#endif /* _LANGUAGE_PASCAL */
|
||||
|
||||
|
||||
/* Dense numbers
|
||||
*
|
||||
* Rather than use file index, symbol index pairs to represent symbols
|
||||
* and globals, we use dense number so that they can be easily embeded
|
||||
* in intermediate code and the programs that process them can
|
||||
* use direct access tabls instead of hash table (which would be
|
||||
* necesary otherwise because of the sparse name space caused by
|
||||
* file index, symbol index pairs. Dense number are represented
|
||||
* by RNDXRs.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following table defines the meaning of each SYM field as
|
||||
* a function of the "st". (scD/B == scData OR scBss)
|
||||
*
|
||||
* Note: the value "isymMac" is used by symbols that have the concept
|
||||
* of enclosing a block of related information. This value is the
|
||||
* isym of the first symbol AFTER the end associated with the primary
|
||||
* symbol. For example if a procedure was at isym==90 and had an
|
||||
* isymMac==155, the associated end would be at isym==154, and the
|
||||
* symbol at 155 would probably (although not necessarily) be the
|
||||
* symbol for the next procedure. This allows rapid skipping over
|
||||
* internal information of various sorts. "stEnd"s ALWAYS have the
|
||||
* isym of the primary symbol that started the block.
|
||||
*
|
||||
|
||||
ST SC VALUE INDEX
|
||||
-------- ------ -------- ------
|
||||
stFile scText address isymMac
|
||||
stLabel scText address ---
|
||||
stGlobal scD/B address iaux
|
||||
stStatic scD/B address iaux
|
||||
stParam scAbs offset iaux
|
||||
stLocal scAbs offset iaux
|
||||
stProc scText address iaux (isymMac is first AUX)
|
||||
stStaticProc scText address iaux (isymMac is first AUX)
|
||||
|
||||
stMember scNil ordinal --- (if member of enum)
|
||||
(mipsread thinks the case below has a bit, not byte, offset.)
|
||||
stMember scNil byte offset iaux (if member of struct/union)
|
||||
stMember scBits bit offset iaux (bit field spec)
|
||||
|
||||
stBlock scText address isymMac (text block)
|
||||
(the code seems to think that rather than scNil, we see scInfo for
|
||||
the two cases below.)
|
||||
stBlock scNil cb isymMac (struct/union member define)
|
||||
stBlock scNil cMembers isymMac (enum member define)
|
||||
|
||||
(New types added by SGI to simplify things:)
|
||||
stStruct scInfo cb isymMac (struct type define)
|
||||
stUnion scInfo cb isymMac (union type define)
|
||||
stEnum scInfo cMembers isymMac (enum type define)
|
||||
|
||||
stEnd scText address isymStart
|
||||
stEnd scNil ------- isymStart (struct/union/enum)
|
||||
|
||||
stTypedef scNil ------- iaux
|
||||
stRegReloc sc??? value old register number
|
||||
stForward sc??? new address isym to original symbol
|
||||
|
||||
stConstant scInfo value --- (scalar)
|
||||
stConstant scInfo iss --- (complex, e.g. string)
|
||||
|
||||
*
|
||||
*/
|
||||
#endif
|
172
base/coff_symconst.h
Normal file
172
base/coff_symconst.h
Normal file
|
@ -0,0 +1,172 @@
|
|||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* Taken from binutils-2.14.90.0.5 include/coff/symconst.h
|
||||
*/
|
||||
|
||||
/* Declarations of constants for internal format of MIPS ECOFF symbols.
|
||||
Originally contributed by MIPS Computer Systems and Third Eye Software.
|
||||
Changes contributed by Cygnus Support are in the public domain.
|
||||
|
||||
This file is just aggregated with the files that make up the GNU
|
||||
release; it is not considered part of GAS, GDB, or other GNU
|
||||
programs. */
|
||||
|
||||
/*
|
||||
* |-----------------------------------------------------------|
|
||||
* | Copyright (c) 1992, 1991, 1990 MIPS Computer Systems, Inc.|
|
||||
* | MIPS Computer Systems, Inc. grants reproduction and use |
|
||||
* | rights to all parties, PROVIDED that this comment is |
|
||||
* | maintained in the copy. |
|
||||
* |-----------------------------------------------------------|
|
||||
*/
|
||||
|
||||
/* (C) Copyright 1984 by Third Eye Software, Inc.
|
||||
*
|
||||
* Third Eye Software, Inc. grants reproduction and use rights to
|
||||
* all parties, PROVIDED that this comment is maintained in the copy.
|
||||
*
|
||||
* Third Eye makes no claims about the applicability of this
|
||||
* symbol table to a particular use.
|
||||
*/
|
||||
|
||||
/* glevels for field in FDR */
|
||||
#define GLEVEL_0 2
|
||||
#define GLEVEL_1 1
|
||||
#define GLEVEL_2 0 /* for upward compat reasons. */
|
||||
#define GLEVEL_3 3
|
||||
|
||||
/* magic number fo symheader */
|
||||
#define magicSym 0x7009
|
||||
/* The Alpha uses this value instead, for some reason. */
|
||||
#define magicSym2 0x1992
|
||||
|
||||
/* Language codes */
|
||||
#define langC 0
|
||||
#define langPascal 1
|
||||
#define langFortran 2
|
||||
#define langAssembler 3 /* one Assembley inst might map to many mach */
|
||||
#define langMachine 4
|
||||
#define langNil 5
|
||||
#define langAda 6
|
||||
#define langPl1 7
|
||||
#define langCobol 8
|
||||
#define langStdc 9 /* FIXME: Collides with SGI langCplusplus */
|
||||
#define langCplusplus 9 /* FIXME: Collides with langStdc */
|
||||
#define langCplusplusV2 10 /* SGI addition */
|
||||
#define langMax 11 /* maximun allowed 32 -- 5 bits */
|
||||
|
||||
/* The following are value definitions for the fields in the SYMR */
|
||||
|
||||
/*
|
||||
* Storage Classes
|
||||
*/
|
||||
|
||||
#define scNil 0
|
||||
#define scText 1 /* text symbol */
|
||||
#define scData 2 /* initialized data symbol */
|
||||
#define scBss 3 /* un-initialized data symbol */
|
||||
#define scRegister 4 /* value of symbol is register number */
|
||||
#define scAbs 5 /* value of symbol is absolute */
|
||||
#define scUndefined 6 /* who knows? */
|
||||
#define scCdbLocal 7 /* variable's value is IN se->va.?? */
|
||||
#define scBits 8 /* this is a bit field */
|
||||
#define scCdbSystem 9 /* variable's value is IN CDB's address space */
|
||||
#define scDbx 9 /* overlap dbx internal use */
|
||||
#define scRegImage 10 /* register value saved on stack */
|
||||
#define scInfo 11 /* symbol contains debugger information */
|
||||
#define scUserStruct 12 /* address in struct user for current process */
|
||||
#define scSData 13 /* load time only small data */
|
||||
#define scSBss 14 /* load time only small common */
|
||||
#define scRData 15 /* load time only read only data */
|
||||
#define scVar 16 /* Var parameter (fortran,pascal) */
|
||||
#define scCommon 17 /* common variable */
|
||||
#define scSCommon 18 /* small common */
|
||||
#define scVarRegister 19 /* Var parameter in a register */
|
||||
#define scVariant 20 /* Variant record */
|
||||
#define scSUndefined 21 /* small undefined(external) data */
|
||||
#define scInit 22 /* .init section symbol */
|
||||
#define scBasedVar 23 /* Fortran or PL/1 ptr based var */
|
||||
#define scXData 24 /* exception handling data */
|
||||
#define scPData 25 /* Procedure section */
|
||||
#define scFini 26 /* .fini section */
|
||||
#define scRConst 27 /* .rconst section */
|
||||
#define scMax 32
|
||||
|
||||
|
||||
/*
|
||||
* Symbol Types
|
||||
*/
|
||||
|
||||
#define stNil 0 /* Nuthin' special */
|
||||
#define stGlobal 1 /* external symbol */
|
||||
#define stStatic 2 /* static */
|
||||
#define stParam 3 /* procedure argument */
|
||||
#define stLocal 4 /* local variable */
|
||||
#define stLabel 5 /* label */
|
||||
#define stProc 6 /* " " Procedure */
|
||||
#define stBlock 7 /* beginnning of block */
|
||||
#define stEnd 8 /* end (of anything) */
|
||||
#define stMember 9 /* member (of anything - struct/union/enum */
|
||||
#define stTypedef 10 /* type definition */
|
||||
#define stFile 11 /* file name */
|
||||
#define stRegReloc 12 /* register relocation */
|
||||
#define stForward 13 /* forwarding address */
|
||||
#define stStaticProc 14 /* load time only static procs */
|
||||
#define stConstant 15 /* const */
|
||||
#define stStaParam 16 /* Fortran static parameters */
|
||||
/* These new symbol types have been recently added to SGI machines. */
|
||||
#define stStruct 26 /* Beginning of block defining a struct type */
|
||||
#define stUnion 27 /* Beginning of block defining a union type */
|
||||
#define stEnum 28 /* Beginning of block defining an enum type */
|
||||
#define stIndirect 34 /* Indirect type specification */
|
||||
/* Pseudo-symbols - internal to debugger */
|
||||
#define stStr 60 /* string */
|
||||
#define stNumber 61 /* pure number (ie. 4 NOR 2+2) */
|
||||
#define stExpr 62 /* 2+2 vs. 4 */
|
||||
#define stType 63 /* post-coersion SER */
|
||||
#define stMax 64
|
||||
|
||||
/* definitions for fields in TIR */
|
||||
|
||||
/* type qualifiers for ti.tq0 -> ti.(itqMax-1) */
|
||||
#define tqNil 0 /* bt is what you see */
|
||||
#define tqPtr 1 /* pointer */
|
||||
#define tqProc 2 /* procedure */
|
||||
#define tqArray 3 /* duh */
|
||||
#define tqFar 4 /* longer addressing - 8086/8 land */
|
||||
#define tqVol 5 /* volatile */
|
||||
#define tqConst 6 /* const */
|
||||
#define tqMax 8
|
||||
|
||||
/* basic types as seen in ti.bt */
|
||||
#define btNil 0 /* undefined (also, enum members) */
|
||||
#define btAdr 1 /* address - integer same size as pointer */
|
||||
#define btChar 2 /* character */
|
||||
#define btUChar 3 /* unsigned character */
|
||||
#define btShort 4 /* short */
|
||||
#define btUShort 5 /* unsigned short */
|
||||
#define btInt 6 /* int */
|
||||
#define btUInt 7 /* unsigned int */
|
||||
#define btLong 8 /* long */
|
||||
#define btULong 9 /* unsigned long */
|
||||
#define btFloat 10 /* float (real) */
|
||||
#define btDouble 11 /* Double (real) */
|
||||
#define btStruct 12 /* Structure (Record) */
|
||||
#define btUnion 13 /* Union (variant) */
|
||||
#define btEnum 14 /* Enumerated */
|
||||
#define btTypedef 15 /* defined via a typedef, isymRef points */
|
||||
#define btRange 16 /* subrange of int */
|
||||
#define btSet 17 /* pascal sets */
|
||||
#define btComplex 18 /* fortran complex */
|
||||
#define btDComplex 19 /* fortran double complex */
|
||||
#define btIndirect 20 /* forward or unnamed typedef */
|
||||
#define btFixedDec 21 /* Fixed Decimal */
|
||||
#define btFloatDec 22 /* Float Decimal */
|
||||
#define btString 23 /* Varying Length Character String */
|
||||
#define btBit 24 /* Aligned Bit String */
|
||||
#define btPicture 25 /* Picture */
|
||||
#define btVoid 26 /* void */
|
||||
#define btLongLong 27 /* long long */
|
||||
#define btULongLong 28 /* unsigned long long */
|
||||
#define btMax 64
|
169
base/ecoff_object.cc
Normal file
169
base/ecoff_object.cc
Normal file
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* Copyright (c) 2003 The Regents of The University of Michigan
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer;
|
||||
* redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution;
|
||||
* neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ecoff_object.hh"
|
||||
|
||||
#include "functional_memory.hh"
|
||||
#include "symtab.hh"
|
||||
|
||||
#include "trace.hh" // for DPRINTF
|
||||
|
||||
#include "exec_ecoff.h"
|
||||
#include "coff_sym.h"
|
||||
#include "coff_symconst.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
ObjectFile *
|
||||
EcoffObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data)
|
||||
{
|
||||
if (((ecoff_filehdr *)data)->f_magic == ECOFF_MAGIC_ALPHA) {
|
||||
// it's Alpha ECOFF
|
||||
return new EcoffObject(fname, fd, len, data);
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
EcoffObject::EcoffObject(const string &_filename, int _fd,
|
||||
size_t _len, uint8_t *_data)
|
||||
: ObjectFile(_filename, _fd, _len, _data)
|
||||
{
|
||||
execHdr = (ecoff_exechdr *)fileData;
|
||||
fileHdr = &(execHdr->f);
|
||||
aoutHdr = &(execHdr->a);
|
||||
|
||||
entry = aoutHdr->entry;
|
||||
|
||||
text.baseAddr = aoutHdr->text_start;
|
||||
text.size = aoutHdr->tsize;
|
||||
|
||||
data.baseAddr = aoutHdr->data_start;
|
||||
data.size = aoutHdr->dsize;
|
||||
|
||||
bss.baseAddr = aoutHdr->bss_start;
|
||||
bss.size = aoutHdr->bsize;
|
||||
|
||||
DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n",
|
||||
text.baseAddr, text.size, data.baseAddr, data.size,
|
||||
bss.baseAddr, bss.size);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
EcoffObject::loadSections(FunctionalMemory *mem, bool loadPhys)
|
||||
{
|
||||
Addr textAddr = text.baseAddr;
|
||||
Addr dataAddr = data.baseAddr;
|
||||
|
||||
if (loadPhys) {
|
||||
textAddr &= (ULL(1) << 40) - 1;
|
||||
dataAddr &= (ULL(1) << 40) - 1;
|
||||
}
|
||||
|
||||
// Since we don't really have an MMU and all memory is
|
||||
// zero-filled, there's no need to set up the BSS segment.
|
||||
mem->prot_write(textAddr, fileData + ECOFF_TXTOFF(execHdr), text.size);
|
||||
mem->prot_write(dataAddr, fileData + ECOFF_DATOFF(execHdr), data.size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
EcoffObject::loadGlobalSymbols(SymbolTable *symtab)
|
||||
{
|
||||
if (!symtab)
|
||||
return false;
|
||||
|
||||
if (fileHdr->f_magic != ECOFF_MAGIC_ALPHA) {
|
||||
cprintf("wrong magic\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
ecoff_symhdr *syms = (ecoff_symhdr *)(fileData + fileHdr->f_symptr);
|
||||
if (syms->magic != magicSym2) {
|
||||
cprintf("bad symbol header magic\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ecoff_extsym *ext_syms = (ecoff_extsym *)(fileData + syms->cbExtOffset);
|
||||
|
||||
char *ext_strings = (char *)(fileData + syms->cbSsExtOffset);
|
||||
for (int i = 0; i < syms->iextMax; i++) {
|
||||
ecoff_sym *entry = &(ext_syms[i].asym);
|
||||
if (entry->iss != -1)
|
||||
symtab->insert(entry->value, ext_strings + entry->iss);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
EcoffObject::loadLocalSymbols(SymbolTable *symtab)
|
||||
{
|
||||
if (!symtab)
|
||||
return false;
|
||||
|
||||
if (fileHdr->f_magic != ECOFF_MAGIC_ALPHA) {
|
||||
cprintf("wrong magic\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
ecoff_symhdr *syms = (ecoff_symhdr *)(fileData + fileHdr->f_symptr);
|
||||
if (syms->magic != magicSym2) {
|
||||
cprintf("bad symbol header magic\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ecoff_sym *local_syms = (ecoff_sym *)(fileData + syms->cbSymOffset);
|
||||
char *local_strings = (char *)(fileData + syms->cbSsOffset);
|
||||
ecoff_fdr *fdesc = (ecoff_fdr *)(fileData + syms->cbFdOffset);
|
||||
|
||||
for (int i = 0; i < syms->ifdMax; i++) {
|
||||
ecoff_sym *entry = (ecoff_sym *)(local_syms + fdesc[i].isymBase);
|
||||
char *strings = (char *)(local_strings + fdesc[i].issBase);
|
||||
for (int j = 0; j < fdesc[i].csym; j++) {
|
||||
if (entry[j].st == stGlobal || entry[j].st == stProc)
|
||||
if (entry[j].iss != -1)
|
||||
symtab->insert(entry[j].value, strings + entry[j].iss);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < syms->isymMax; i++) {
|
||||
ecoff_sym *entry = &(local_syms[i]);
|
||||
if (entry->st == stProc)
|
||||
symtab->insert(entry->value, local_strings + entry->iss);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
61
base/ecoff_object.hh
Normal file
61
base/ecoff_object.hh
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2003 The Regents of The University of Michigan
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer;
|
||||
* redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution;
|
||||
* neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __ECOFF_OBJECT_HH__
|
||||
#define __ECOFF_OBJECT_HH__
|
||||
|
||||
#include "object_file.hh"
|
||||
|
||||
// forward decls: avoid including exec_ecoff.h here
|
||||
struct ecoff_exechdr;
|
||||
struct ecoff_filehdr;
|
||||
struct ecoff_aouthdr;
|
||||
|
||||
class EcoffObject : public ObjectFile
|
||||
{
|
||||
protected:
|
||||
ecoff_exechdr *execHdr;
|
||||
ecoff_filehdr *fileHdr;
|
||||
ecoff_aouthdr *aoutHdr;
|
||||
|
||||
EcoffObject(const std::string &_filename, int _fd,
|
||||
size_t _len, uint8_t *_data);
|
||||
|
||||
public:
|
||||
virtual ~EcoffObject() {}
|
||||
|
||||
virtual bool loadSections(FunctionalMemory *mem,
|
||||
bool loadPhys = false);
|
||||
virtual bool loadGlobalSymbols(SymbolTable *symtab);
|
||||
virtual bool loadLocalSymbols(SymbolTable *symtab);
|
||||
|
||||
static ObjectFile *tryFile(const std::string &fname, int fd,
|
||||
size_t len, uint8_t *data);
|
||||
};
|
||||
|
||||
#endif // __ECOFF_OBJECT_HH__
|
140
base/elf_object.cc
Normal file
140
base/elf_object.cc
Normal file
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Copyright (c) 2003 The Regents of The University of Michigan
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer;
|
||||
* redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution;
|
||||
* neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "elf_object.hh"
|
||||
|
||||
#include "functional_memory.hh"
|
||||
#include "symtab.hh"
|
||||
|
||||
#include "trace.hh" // for DPRINTF
|
||||
|
||||
#include "exec_elf.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
ObjectFile *
|
||||
ElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data)
|
||||
{
|
||||
if (memcmp(((Elf64_Ehdr *)data)->e_ident, ELFMAG, SELFMAG) == 0) {
|
||||
// for now we'll assume it's a 64-bit Alpha binary
|
||||
return new ElfObject(fname, fd, len, data);
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ElfObject::ElfObject(const string &_filename, int _fd,
|
||||
size_t _len, uint8_t *_data)
|
||||
: ObjectFile(_filename, _fd, _len, _data)
|
||||
{
|
||||
ehdr = (Elf64_Ehdr *)fileData;
|
||||
|
||||
entry = ehdr->e_entry;
|
||||
|
||||
phdr = (Elf64_Phdr *)(fileData + ehdr->e_phoff);
|
||||
assert(sizeof(Elf64_Phdr) == ehdr->e_phentsize);
|
||||
|
||||
bool foundText = false;
|
||||
bool foundData = false;
|
||||
for (int i = 0; i < ehdr->e_phnum; ++i) {
|
||||
Elf64_Phdr *p = &phdr[i];
|
||||
|
||||
// for now we don't care about non-loadable segments
|
||||
if (!(p->p_type & PT_LOAD))
|
||||
continue;
|
||||
|
||||
if (p->p_flags & PF_X) {
|
||||
// executable: must be text
|
||||
assert(!foundText);
|
||||
foundText = true;
|
||||
textPhdrIdx = i;
|
||||
text.baseAddr = p->p_vaddr;
|
||||
text.size = p->p_filesz;
|
||||
assert(p->p_filesz == p->p_memsz);
|
||||
}
|
||||
else {
|
||||
assert(p->p_flags & PF_R);
|
||||
assert(!foundData);
|
||||
foundData = true;
|
||||
dataPhdrIdx = i;
|
||||
data.baseAddr = p->p_vaddr;
|
||||
data.size = p->p_filesz;
|
||||
bss.baseAddr = data.baseAddr + data.size;
|
||||
bss.size = p->p_memsz - p->p_filesz;
|
||||
}
|
||||
}
|
||||
|
||||
assert(foundText && foundData);
|
||||
|
||||
DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n",
|
||||
text.baseAddr, text.size, data.baseAddr, data.size,
|
||||
bss.baseAddr, bss.size);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ElfObject::loadSections(FunctionalMemory *mem, bool loadPhys)
|
||||
{
|
||||
Addr textAddr = text.baseAddr;
|
||||
Addr dataAddr = data.baseAddr;
|
||||
|
||||
if (loadPhys) {
|
||||
textAddr &= (ULL(1) << 40) - 1;
|
||||
dataAddr &= (ULL(1) << 40) - 1;
|
||||
}
|
||||
|
||||
// Since we don't really have an MMU and all memory is
|
||||
// zero-filled, there's no need to set up the BSS segment.
|
||||
if (text.size != 0)
|
||||
mem->prot_write(textAddr, fileData + phdr[textPhdrIdx].p_offset,
|
||||
text.size);
|
||||
if (data.size != 0)
|
||||
mem->prot_write(dataAddr, fileData + phdr[dataPhdrIdx].p_offset,
|
||||
data.size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ElfObject::loadGlobalSymbols(SymbolTable *symtab)
|
||||
{
|
||||
// symbols not supported yet
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ElfObject::loadLocalSymbols(SymbolTable *symtab)
|
||||
{
|
||||
// symbols not supported yet
|
||||
return false;
|
||||
}
|
62
base/elf_object.hh
Normal file
62
base/elf_object.hh
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2003 The Regents of The University of Michigan
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer;
|
||||
* redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution;
|
||||
* neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __ELF_OBJECT_HH__
|
||||
#define __ELF_OBJECT_HH__
|
||||
|
||||
#include "object_file.hh"
|
||||
|
||||
// forward decls: avoid including exec_elf.hh here
|
||||
struct Elf64_Ehdr;
|
||||
struct Elf64_Phdr;
|
||||
|
||||
class ElfObject : public ObjectFile
|
||||
{
|
||||
protected:
|
||||
Elf64_Ehdr *ehdr;
|
||||
Elf64_Phdr *phdr;
|
||||
|
||||
int textPhdrIdx;
|
||||
int dataPhdrIdx;
|
||||
|
||||
ElfObject(const std::string &_filename, int _fd,
|
||||
size_t _len, uint8_t *_data);
|
||||
|
||||
public:
|
||||
virtual ~ElfObject() {}
|
||||
|
||||
virtual bool loadSections(FunctionalMemory *mem,
|
||||
bool loadPhys = false);
|
||||
virtual bool loadGlobalSymbols(SymbolTable *symtab);
|
||||
virtual bool loadLocalSymbols(SymbolTable *symtab);
|
||||
|
||||
static ObjectFile *tryFile(const std::string &fname, int fd,
|
||||
size_t len, uint8_t *data);
|
||||
};
|
||||
|
||||
#endif // __ELF_OBJECT_HH__
|
62
base/exec_aout.h
Normal file
62
base/exec_aout.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* Taken from NetBSD sys/exec_aout.h
|
||||
*/
|
||||
|
||||
/* $NetBSD: exec_aout.h,v 1.29 2002/12/10 17:14:31 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1993, 1994 Christopher G. Demetriou
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Christopher G. Demetriou.
|
||||
* 4. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_EXEC_AOUT_H_
|
||||
#define _SYS_EXEC_AOUT_H_
|
||||
|
||||
#ifndef N_PAGSIZ
|
||||
#define N_PAGSIZ(ex) (AOUT_LDPGSZ)
|
||||
#endif
|
||||
|
||||
/* a_magic */
|
||||
#define OMAGIC 0407 /* old impure format */
|
||||
#define NMAGIC 0410 /* read-only text */
|
||||
#define ZMAGIC 0413 /* demand load format */
|
||||
|
||||
#define N_ALIGN(ex,x) \
|
||||
(N_GETMAGIC(ex) == ZMAGIC ? \
|
||||
((x) + AOUT_LDPGSZ - 1) & ~(AOUT_LDPGSZ - 1) : (x))
|
||||
|
||||
/* Valid magic number check. */
|
||||
#define N_BADMAG(ex) \
|
||||
(N_GETMAGIC(ex) != NMAGIC && N_GETMAGIC(ex) != OMAGIC && \
|
||||
N_GETMAGIC(ex) != ZMAGIC)
|
||||
|
||||
#include "aout_machdep.h"
|
||||
|
||||
#endif /* !_SYS_EXEC_AOUT_H_ */
|
111
base/exec_ecoff.h
Normal file
111
base/exec_ecoff.h
Normal file
|
@ -0,0 +1,111 @@
|
|||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* Taken from NetBSD sys/exec_ecoff.h
|
||||
*/
|
||||
|
||||
/* $NetBSD: exec_ecoff.h,v 1.13 2003/01/18 09:53:18 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1994 Adam Glass
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Adam Glass.
|
||||
* 4. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_EXEC_ECOFF_H_
|
||||
#define _SYS_EXEC_ECOFF_H_
|
||||
|
||||
#include "ecoff_machdep.h"
|
||||
|
||||
struct ecoff_filehdr {
|
||||
coff_ushort f_magic; /* magic number */
|
||||
coff_ushort f_nscns; /* # of sections */
|
||||
coff_uint f_timdat; /* time and date stamp */
|
||||
coff_ulong f_symptr; /* file offset of symbol table */
|
||||
coff_uint f_nsyms; /* # of symbol table entries */
|
||||
coff_ushort f_opthdr; /* sizeof the optional header */
|
||||
coff_ushort f_flags; /* flags??? */
|
||||
};
|
||||
|
||||
struct ecoff_aouthdr {
|
||||
coff_ushort magic;
|
||||
coff_ushort vstamp;
|
||||
ECOFF_PAD
|
||||
coff_ulong tsize;
|
||||
coff_ulong dsize;
|
||||
coff_ulong bsize;
|
||||
coff_ulong entry;
|
||||
coff_ulong text_start;
|
||||
coff_ulong data_start;
|
||||
coff_ulong bss_start;
|
||||
ECOFF_MACHDEP;
|
||||
};
|
||||
|
||||
struct ecoff_scnhdr { /* needed for size info */
|
||||
char s_name[8]; /* name */
|
||||
coff_ulong s_paddr; /* physical addr? for ROMing?*/
|
||||
coff_ulong s_vaddr; /* virtual addr? */
|
||||
coff_ulong s_size; /* size */
|
||||
coff_ulong s_scnptr; /* file offset of raw data */
|
||||
coff_ulong s_relptr; /* file offset of reloc data */
|
||||
coff_ulong s_lnnoptr; /* file offset of line data */
|
||||
coff_ushort s_nreloc; /* # of relocation entries */
|
||||
coff_ushort s_nlnno; /* # of line entries */
|
||||
coff_uint s_flags; /* flags */
|
||||
};
|
||||
|
||||
struct ecoff_exechdr {
|
||||
struct ecoff_filehdr f;
|
||||
struct ecoff_aouthdr a;
|
||||
};
|
||||
|
||||
#define ECOFF_HDR_SIZE (sizeof(struct ecoff_exechdr))
|
||||
|
||||
#define ECOFF_OMAGIC 0407
|
||||
#define ECOFF_NMAGIC 0410
|
||||
#define ECOFF_ZMAGIC 0413
|
||||
|
||||
#define ECOFF_ROUND(value, by) \
|
||||
(((value) + (by) - 1) & ~((by) - 1))
|
||||
|
||||
#define ECOFF_BLOCK_ALIGN(ep, value) \
|
||||
((ep)->a.magic == ECOFF_ZMAGIC ? ECOFF_ROUND((value), ECOFF_LDPGSZ) : \
|
||||
(value))
|
||||
|
||||
#define ECOFF_TXTOFF(ep) \
|
||||
((ep)->a.magic == ECOFF_ZMAGIC ? 0 : \
|
||||
ECOFF_ROUND(ECOFF_HDR_SIZE + (ep)->f.f_nscns * \
|
||||
sizeof(struct ecoff_scnhdr), ECOFF_SEGMENT_ALIGNMENT(ep)))
|
||||
|
||||
#define ECOFF_DATOFF(ep) \
|
||||
(ECOFF_BLOCK_ALIGN((ep), ECOFF_TXTOFF(ep) + (ep)->a.tsize))
|
||||
|
||||
#define ECOFF_SEGMENT_ALIGN(ep, value) \
|
||||
(ECOFF_ROUND((value), ((ep)->a.magic == ECOFF_ZMAGIC ? ECOFF_LDPGSZ : \
|
||||
ECOFF_SEGMENT_ALIGNMENT(ep))))
|
||||
|
||||
#endif /* !_SYS_EXEC_ECOFF_H_ */
|
|
@ -36,138 +36,80 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include "cprintf.hh"
|
||||
#include "ecoff.hh"
|
||||
#include "object_file.hh"
|
||||
#include "symtab.hh"
|
||||
|
||||
#include "ecoff_object.hh"
|
||||
#include "aout_object.hh"
|
||||
#include "elf_object.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
ObjectFile::ObjectFile()
|
||||
: descriptor(-1), data(NULL)
|
||||
{}
|
||||
ObjectFile::ObjectFile(const string &_filename, int _fd,
|
||||
size_t _len, uint8_t *_data)
|
||||
: filename(_filename), descriptor(_fd), fileData(_data), len(_len)
|
||||
{
|
||||
}
|
||||
|
||||
ObjectFile::ObjectFile(string file)
|
||||
: descriptor(-1), data(NULL)
|
||||
{ open(file); }
|
||||
|
||||
ObjectFile::~ObjectFile()
|
||||
{ close(); }
|
||||
|
||||
bool
|
||||
ObjectFile::open(string file_name)
|
||||
{
|
||||
close();
|
||||
|
||||
name = file_name;
|
||||
|
||||
descriptor = ::open(name.c_str(), O_RDONLY);
|
||||
if (descriptor < 0)
|
||||
return false;
|
||||
|
||||
len = (size_t)::lseek(descriptor, 0, SEEK_END);
|
||||
|
||||
data = (uint8_t *)::mmap(NULL, len, PROT_READ, MAP_SHARED, descriptor, 0);
|
||||
if (data == MAP_FAILED)
|
||||
return false;
|
||||
|
||||
postOpen();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ObjectFile::close()
|
||||
{
|
||||
if (descriptor >= 0)
|
||||
if (descriptor >= 0) {
|
||||
::close(descriptor);
|
||||
|
||||
if (data)
|
||||
::munmap(data, len);
|
||||
descriptor = -1;
|
||||
}
|
||||
|
||||
void
|
||||
EcoffObject::postOpen()
|
||||
if (fileData) {
|
||||
::munmap(fileData, len);
|
||||
fileData = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ObjectFile *
|
||||
createObjectFile(const string &fname)
|
||||
{
|
||||
exec = &(((EcoffExecHeader *)data)->f);
|
||||
aout = &(((EcoffExecHeader *)data)->a);
|
||||
|
||||
text_off = aout->text_start;
|
||||
data_off = aout->data_start;
|
||||
bss_off = aout->bss_start;
|
||||
|
||||
text_size = aout->tsize;
|
||||
data_size = aout->dsize;
|
||||
bss_size = aout->bsize;
|
||||
// open the file
|
||||
int fd = open(fname.c_str(), O_RDONLY);
|
||||
if (fd < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
EcoffObject::loadGlobals(SymbolTable *symtab)
|
||||
{
|
||||
if (!symtab)
|
||||
return false;
|
||||
// find the length of the file by seeking to the end
|
||||
size_t len = (size_t)lseek(fd, 0, SEEK_END);
|
||||
|
||||
if (exec->f_magic != ALPHAMAGIC) {
|
||||
cprintf("wrong magic\n");
|
||||
return false;
|
||||
// mmap the whole shebang
|
||||
uint8_t *fileData =
|
||||
(uint8_t *)mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (fileData == MAP_FAILED) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EcoffSymHeader *syms = (EcoffSymHeader *)(data + exec->f_symptr);
|
||||
if (syms->magic != ECOFF_SYM_MAGIC) {
|
||||
cprintf("bad symbol header magic\n");
|
||||
exit(1);
|
||||
ObjectFile *fileObj = NULL;
|
||||
|
||||
// figure out what we have here
|
||||
if ((fileObj = EcoffObject::tryFile(fname, fd, len, fileData)) != NULL) {
|
||||
return fileObj;
|
||||
}
|
||||
|
||||
EcoffExtSymEntry *ext_syms =
|
||||
(EcoffExtSymEntry *)(data + syms->cbExtOffset);
|
||||
|
||||
char *ext_strings = (char *)(data + syms->cbSsExtOffset);
|
||||
for (int i = 0; i < syms->iextMax; i++) {
|
||||
EcoffSymEntry *entry = &(ext_syms[i].asym);
|
||||
if (entry->iss != -1)
|
||||
symtab->insert(entry->value, ext_strings + entry->iss);
|
||||
if ((fileObj = AoutObject::tryFile(fname, fd, len, fileData)) != NULL) {
|
||||
return fileObj;
|
||||
}
|
||||
|
||||
return true;
|
||||
if ((fileObj = ElfObject::tryFile(fname, fd, len, fileData)) != NULL) {
|
||||
return fileObj;
|
||||
}
|
||||
|
||||
bool
|
||||
EcoffObject::loadLocals(SymbolTable *symtab)
|
||||
{
|
||||
if (!symtab)
|
||||
return false;
|
||||
|
||||
if (exec->f_magic != ALPHAMAGIC) {
|
||||
cprintf("wrong magic\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
EcoffSymHeader *syms = (EcoffSymHeader *)(data + exec->f_symptr);
|
||||
if (syms->magic != ECOFF_SYM_MAGIC) {
|
||||
cprintf("bad symbol header magic\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
EcoffSymEntry *local_syms = (EcoffSymEntry *)(data + syms->cbSymOffset);
|
||||
char *local_strings = (char *)(data + syms->cbSsOffset);
|
||||
EcoffFileDesc *fdesc = (EcoffFileDesc *)(data + syms->cbFdOffset);
|
||||
|
||||
for (int i = 0; i < syms->ifdMax; i++) {
|
||||
EcoffSymEntry *entry =
|
||||
(EcoffSymEntry *)(local_syms + fdesc[i].isymBase);
|
||||
char *strings = (char *)(local_strings + fdesc[i].issBase);
|
||||
for (int j = 0; j < fdesc[i].csym; j++) {
|
||||
if (entry[j].st == 1 || entry[j].st == 6)
|
||||
if (entry[j].iss != -1)
|
||||
symtab->insert(entry[j].value, strings + entry[j].iss);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < syms->isymMax; i++) {
|
||||
EcoffSymEntry *entry = &(local_syms[i]);
|
||||
if (entry->st == 6)
|
||||
if (entry->st == 1 || entry->st == 6)
|
||||
symtab->insert(entry->value, local_strings + entry->iss);
|
||||
}
|
||||
|
||||
return true;
|
||||
// don't know what it is
|
||||
close(fd);
|
||||
munmap(fileData, len);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -29,64 +29,60 @@
|
|||
#ifndef __OBJECT_FILE_HH__
|
||||
#define __OBJECT_FILE_HH__
|
||||
|
||||
#include "ecoff.hh"
|
||||
#include "isa_traits.hh" // for Addr
|
||||
|
||||
class FunctionalMemory;
|
||||
class SymbolTable;
|
||||
|
||||
class ObjectFile
|
||||
{
|
||||
protected:
|
||||
std::string name;
|
||||
const std::string filename;
|
||||
int descriptor;
|
||||
uint8_t *data;
|
||||
uint8_t *fileData;
|
||||
size_t len;
|
||||
|
||||
ObjectFile(const std::string &_filename, int _fd,
|
||||
size_t _len, uint8_t *_data);
|
||||
|
||||
public:
|
||||
ObjectFile();
|
||||
explicit ObjectFile(std::string file);
|
||||
virtual ~ObjectFile();
|
||||
|
||||
bool open(std::string file);
|
||||
void close();
|
||||
|
||||
virtual bool loadGlobals(SymbolTable *symtab) = 0;
|
||||
virtual bool loadLocals(SymbolTable *symtab) = 0;
|
||||
virtual void postOpen() = 0;
|
||||
virtual bool loadSections(FunctionalMemory *mem,
|
||||
bool loadPhys = false) = 0;
|
||||
virtual bool loadGlobalSymbols(SymbolTable *symtab) = 0;
|
||||
virtual bool loadLocalSymbols(SymbolTable *symtab) = 0;
|
||||
|
||||
protected:
|
||||
Addr text_off;
|
||||
Addr data_off;
|
||||
Addr bss_off;
|
||||
|
||||
size_t text_size;
|
||||
size_t data_size;
|
||||
size_t bss_size;
|
||||
|
||||
public:
|
||||
Addr textOffset() const { return text_off; }
|
||||
Addr dataOffset() const { return data_off; }
|
||||
Addr bssOffset() const { return bss_off; }
|
||||
|
||||
size_t textSize() const { return text_size; }
|
||||
size_t dataSize() const { return data_size; }
|
||||
size_t bssSize() const { return bss_size; }
|
||||
struct Section {
|
||||
Addr baseAddr;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
class EcoffObject : public ObjectFile
|
||||
{
|
||||
protected:
|
||||
EcoffFileHeader *exec;
|
||||
EcoffAOutHeader *aout;
|
||||
Addr entry;
|
||||
Addr globalPtr;
|
||||
|
||||
Section text;
|
||||
Section data;
|
||||
Section bss;
|
||||
|
||||
public:
|
||||
EcoffObject() {}
|
||||
explicit EcoffObject(std::string file) { open(file); }
|
||||
virtual ~EcoffObject() {}
|
||||
Addr entryPoint() const { return entry; }
|
||||
Addr globalPointer() const { return globalPtr; }
|
||||
|
||||
virtual bool loadGlobals(SymbolTable *symtab);
|
||||
virtual bool loadLocals(SymbolTable *symtab);
|
||||
virtual void postOpen();
|
||||
Addr textBase() const { return text.baseAddr; }
|
||||
Addr dataBase() const { return data.baseAddr; }
|
||||
Addr bssBase() const { return bss.baseAddr; }
|
||||
|
||||
size_t textSize() const { return text.size; }
|
||||
size_t dataSize() const { return data.size; }
|
||||
size_t bssSize() const { return bss.size; }
|
||||
};
|
||||
|
||||
ObjectFile *createObjectFile(const std::string &fname);
|
||||
|
||||
|
||||
#endif // __OBJECT_FILE_HH__
|
||||
|
|
85
sim/prog.cc
85
sim/prog.cc
|
@ -38,7 +38,7 @@
|
|||
#include "eio.hh"
|
||||
#include "thread.hh"
|
||||
#include "fake_syscall.hh"
|
||||
#include "loader.hh"
|
||||
#include "object_file.hh"
|
||||
#include "exec_context.hh"
|
||||
#include "smt.hh"
|
||||
|
||||
|
@ -219,12 +219,93 @@ DEFINE_SIM_OBJECT_CLASS_NAME("Process object", Process)
|
|||
//
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
static void
|
||||
copyStringArray(vector<string> &strings, Addr array_ptr, Addr data_ptr,
|
||||
FunctionalMemory *memory)
|
||||
{
|
||||
for (int i = 0; i < strings.size(); ++i) {
|
||||
memory->access(Write, array_ptr, &data_ptr, sizeof(Addr));
|
||||
memory->writeString(data_ptr, strings[i].c_str());
|
||||
array_ptr += sizeof(Addr);
|
||||
data_ptr += strings[i].size() + 1;
|
||||
}
|
||||
// add NULL terminator
|
||||
data_ptr = 0;
|
||||
memory->access(Write, array_ptr, &data_ptr, sizeof(Addr));
|
||||
}
|
||||
|
||||
LiveProcess::LiveProcess(const string &name,
|
||||
int stdin_fd, int stdout_fd, int stderr_fd,
|
||||
vector<string> &argv, vector<string> &envp)
|
||||
: Process(name, stdin_fd, stdout_fd, stderr_fd)
|
||||
{
|
||||
smt_load_prog(argv, envp, init_regs, this);
|
||||
prog_fname = argv[0];
|
||||
ObjectFile *objFile = createObjectFile(prog_fname);
|
||||
if (objFile == NULL) {
|
||||
fatal("Can't load object file %s", prog_fname);
|
||||
}
|
||||
|
||||
prog_entry = objFile->entryPoint();
|
||||
text_base = objFile->textBase();
|
||||
text_size = objFile->textSize();
|
||||
data_base = objFile->dataBase();
|
||||
data_size = objFile->dataSize() + objFile->bssSize();
|
||||
brk_point = ROUND_UP(data_base + data_size, VMPageSize);
|
||||
|
||||
// load object file into target memory
|
||||
objFile->loadSections(memory);
|
||||
|
||||
// Set up stack. On Alpha, stack goes below text section. This
|
||||
// code should get moved to some architecture-specific spot.
|
||||
stack_base = text_base - (409600+4096);
|
||||
|
||||
// Set pointer for next thread stack. Reserve 8M for main stack.
|
||||
next_thread_stack_base = stack_base - (8 * 1024 * 1024);
|
||||
|
||||
// Calculate how much space we need for arg & env arrays.
|
||||
int argv_array_size = sizeof(Addr) * (argv.size() + 1);
|
||||
int envp_array_size = sizeof(Addr) * (envp.size() + 1);
|
||||
int arg_data_size = 0;
|
||||
for (int i = 0; i < argv.size(); ++i) {
|
||||
arg_data_size += argv[i].size() + 1;
|
||||
}
|
||||
int env_data_size = 0;
|
||||
for (int i = 0; i < envp.size(); ++i) {
|
||||
env_data_size += envp[i].size() + 1;
|
||||
}
|
||||
|
||||
int space_needed =
|
||||
argv_array_size + envp_array_size + arg_data_size + env_data_size;
|
||||
// for SimpleScalar compatibility
|
||||
if (space_needed < 16384)
|
||||
space_needed = 16384;
|
||||
|
||||
// set bottom of stack
|
||||
stack_min = stack_base - space_needed;
|
||||
// align it
|
||||
stack_min &= ~7;
|
||||
stack_size = stack_base - stack_min;
|
||||
|
||||
// map out initial stack contents
|
||||
Addr argv_array_base = stack_min + sizeof(uint64_t); // room for argc
|
||||
Addr envp_array_base = argv_array_base + argv_array_size;
|
||||
Addr arg_data_base = envp_array_base + envp_array_size;
|
||||
Addr env_data_base = arg_data_base + arg_data_size;
|
||||
|
||||
// write contents to stack
|
||||
uint64_t argc = argv.size();
|
||||
memory->access(Write, stack_min, &argc, sizeof(uint64_t));
|
||||
|
||||
copyStringArray(argv, argv_array_base, arg_data_base, memory);
|
||||
copyStringArray(envp, envp_array_base, env_data_base, memory);
|
||||
|
||||
init_regs->intRegFile[ArgumentReg0] = argc;
|
||||
init_regs->intRegFile[ArgumentReg1] = argv_array_base;
|
||||
init_regs->intRegFile[StackPointerReg] = stack_min;
|
||||
init_regs->intRegFile[GlobalPointerReg] = objFile->globalPointer();
|
||||
init_regs->pc = prog_entry;
|
||||
init_regs->npc = prog_entry + sizeof(MachInst);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -86,7 +86,6 @@ class Process : public SimObject
|
|||
|
||||
Addr brk_point; // top of the data segment
|
||||
|
||||
Addr environ_base; // environment base address
|
||||
Addr stack_base; // stack segment base (highest address)
|
||||
unsigned stack_size; // initial stack size
|
||||
Addr stack_min; // lowest address accessed on the stack
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "kernel_loader.hh"
|
||||
#include "exec_context.hh"
|
||||
#include "object_file.hh"
|
||||
#include "memory_control.hh"
|
||||
|
@ -68,28 +67,47 @@ System::System(const std::string _name,
|
|||
kernelSymtab = new SymbolTable;
|
||||
consoleSymtab = new SymbolTable;
|
||||
|
||||
EcoffObject kernel(kernel_path);
|
||||
EcoffObject console(console_path);
|
||||
ObjectFile *kernel = createObjectFile(kernel_path);
|
||||
if (kernel == NULL)
|
||||
fatal("Could not load kernel file %s", kernel_path);
|
||||
|
||||
if (!kernel.loadGlobals(kernelSymtab))
|
||||
ObjectFile *console = createObjectFile(console_path);
|
||||
if (console == NULL)
|
||||
fatal("Could not load console file %s", console_path);
|
||||
|
||||
if (!kernel->loadGlobalSymbols(kernelSymtab))
|
||||
panic("could not load kernel symbols\n");
|
||||
|
||||
if (!console.loadGlobals(consoleSymtab))
|
||||
if (!console->loadGlobalSymbols(consoleSymtab))
|
||||
panic("could not load console symbols\n");
|
||||
|
||||
// Load pal file
|
||||
loadPal(palcode, physmem, PAL_BASE);
|
||||
ObjectFile *pal = createObjectFile(palcode);
|
||||
if (pal == NULL)
|
||||
fatal("Could not load PALcode file %s", palcode);
|
||||
pal->loadSections(physmem, true);
|
||||
|
||||
// copy of initial reg file contents
|
||||
initRegs = new RegFile;
|
||||
memset(initRegs, 0, sizeof(RegFile));
|
||||
|
||||
// Load console file
|
||||
loadKernel(console_path, physmem);
|
||||
console->loadSections(physmem, true);
|
||||
|
||||
// Load kernel file
|
||||
loadKernel(kernel_path, physmem, initRegs,
|
||||
&kernelStart, &kernelEnd, &kernelEntry);
|
||||
kernel->loadSections(physmem, true);
|
||||
kernelStart = kernel->textBase();
|
||||
kernelEnd = kernel->bssBase() + kernel->bssSize();
|
||||
kernelEntry = kernel->entryPoint();
|
||||
|
||||
DPRINTF(Loader, "Kernel start = %#x\n"
|
||||
"Kernel end = %#x\n"
|
||||
"Kernel entry = %#x\n",
|
||||
kernelStart, kernelEnd, kernelEntry);
|
||||
|
||||
// Setup kernel boot parameters
|
||||
initRegs->pc = 0x4001;
|
||||
initRegs->npc = initRegs->pc + sizeof(MachInst);
|
||||
|
||||
DPRINTF(Loader, "Kernel loaded...\n");
|
||||
|
||||
|
|
Loading…
Reference in a new issue