1/* 2 * Copyright (c) 2001-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Nathan Binkert 29 * Steve Reinhardt 30 * Ali Saidi 31 */ 32 33#include <unistd.h> 34#include <fcntl.h> 35 36#include <string> 37 38#include "base/intmath.hh" 39#include "base/loader/object_file.hh" 40#include "base/loader/symtab.hh" 41#include "base/statistics.hh" 42#include "config/full_system.hh"
| 1/* 2 * Copyright (c) 2001-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Nathan Binkert 29 * Steve Reinhardt 30 * Ali Saidi 31 */ 32 33#include <unistd.h> 34#include <fcntl.h> 35 36#include <string> 37 38#include "base/intmath.hh" 39#include "base/loader/object_file.hh" 40#include "base/loader/symtab.hh" 41#include "base/statistics.hh" 42#include "config/full_system.hh"
|
43#include "cpu/exec_context.hh"
| 43#include "cpu/thread_context.hh"
|
44#include "mem/page_table.hh" 45#include "mem/physical.hh" 46#include "mem/translating_port.hh" 47#include "sim/builder.hh" 48#include "sim/process.hh" 49#include "sim/stats.hh" 50#include "sim/syscall_emul.hh" 51#include "sim/system.hh" 52 53using namespace std; 54using namespace TheISA; 55 56// 57// The purpose of this code is to fake the loader & syscall mechanism 58// when there's no OS: thus there's no resone to use it in FULL_SYSTEM 59// mode when we do have an OS 60// 61#if FULL_SYSTEM 62#error "process.cc not compatible with FULL_SYSTEM" 63#endif 64 65// current number of allocated processes 66int num_processes = 0; 67 68Process::Process(const string &nm, 69 System *_system, 70 int stdin_fd, // initial I/O descriptors 71 int stdout_fd, 72 int stderr_fd) 73 : SimObject(nm), system(_system) 74{ 75 // initialize first 3 fds (stdin, stdout, stderr) 76 fd_map[STDIN_FILENO] = stdin_fd; 77 fd_map[STDOUT_FILENO] = stdout_fd; 78 fd_map[STDERR_FILENO] = stderr_fd; 79 80 // mark remaining fds as free 81 for (int i = 3; i <= MAX_FD; ++i) { 82 fd_map[i] = -1; 83 } 84 85 mmap_start = mmap_end = 0; 86 nxm_start = nxm_end = 0; 87 pTable = new PageTable(system); 88 // other parameters will be initialized when the program is loaded 89} 90 91 92void 93Process::regStats() 94{ 95 using namespace Stats; 96 97 num_syscalls 98 .name(name() + ".PROG:num_syscalls") 99 .desc("Number of system calls") 100 ; 101} 102 103// 104// static helper functions 105// 106int 107Process::openInputFile(const string &filename) 108{ 109 int fd = open(filename.c_str(), O_RDONLY); 110 111 if (fd == -1) { 112 perror(NULL); 113 cerr << "unable to open \"" << filename << "\" for reading\n"; 114 fatal("can't open input file"); 115 } 116 117 return fd; 118} 119 120 121int 122Process::openOutputFile(const string &filename) 123{ 124 int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0774); 125 126 if (fd == -1) { 127 perror(NULL); 128 cerr << "unable to open \"" << filename << "\" for writing\n"; 129 fatal("can't open output file"); 130 } 131 132 return fd; 133} 134 135 136int
| 44#include "mem/page_table.hh" 45#include "mem/physical.hh" 46#include "mem/translating_port.hh" 47#include "sim/builder.hh" 48#include "sim/process.hh" 49#include "sim/stats.hh" 50#include "sim/syscall_emul.hh" 51#include "sim/system.hh" 52 53using namespace std; 54using namespace TheISA; 55 56// 57// The purpose of this code is to fake the loader & syscall mechanism 58// when there's no OS: thus there's no resone to use it in FULL_SYSTEM 59// mode when we do have an OS 60// 61#if FULL_SYSTEM 62#error "process.cc not compatible with FULL_SYSTEM" 63#endif 64 65// current number of allocated processes 66int num_processes = 0; 67 68Process::Process(const string &nm, 69 System *_system, 70 int stdin_fd, // initial I/O descriptors 71 int stdout_fd, 72 int stderr_fd) 73 : SimObject(nm), system(_system) 74{ 75 // initialize first 3 fds (stdin, stdout, stderr) 76 fd_map[STDIN_FILENO] = stdin_fd; 77 fd_map[STDOUT_FILENO] = stdout_fd; 78 fd_map[STDERR_FILENO] = stderr_fd; 79 80 // mark remaining fds as free 81 for (int i = 3; i <= MAX_FD; ++i) { 82 fd_map[i] = -1; 83 } 84 85 mmap_start = mmap_end = 0; 86 nxm_start = nxm_end = 0; 87 pTable = new PageTable(system); 88 // other parameters will be initialized when the program is loaded 89} 90 91 92void 93Process::regStats() 94{ 95 using namespace Stats; 96 97 num_syscalls 98 .name(name() + ".PROG:num_syscalls") 99 .desc("Number of system calls") 100 ; 101} 102 103// 104// static helper functions 105// 106int 107Process::openInputFile(const string &filename) 108{ 109 int fd = open(filename.c_str(), O_RDONLY); 110 111 if (fd == -1) { 112 perror(NULL); 113 cerr << "unable to open \"" << filename << "\" for reading\n"; 114 fatal("can't open input file"); 115 } 116 117 return fd; 118} 119 120 121int 122Process::openOutputFile(const string &filename) 123{ 124 int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0774); 125 126 if (fd == -1) { 127 perror(NULL); 128 cerr << "unable to open \"" << filename << "\" for writing\n"; 129 fatal("can't open output file"); 130 } 131 132 return fd; 133} 134 135 136int
|
137Process::registerExecContext(ExecContext *xc)
| 137Process::registerThreadContext(ThreadContext *tc)
|
138{ 139 // add to list
| 138{ 139 // add to list
|
140 int myIndex = execContexts.size(); 141 execContexts.push_back(xc);
| 140 int myIndex = threadContexts.size(); 141 threadContexts.push_back(tc);
|
142 143 // return CPU number to caller 144 return myIndex; 145} 146 147void 148Process::startup() 149{
| 142 143 // return CPU number to caller 144 return myIndex; 145} 146 147void 148Process::startup() 149{
|
150 if (execContexts.empty())
| 150 if (threadContexts.empty())
|
151 fatal("Process %s is not associated with any CPUs!\n", name()); 152
| 151 fatal("Process %s is not associated with any CPUs!\n", name()); 152
|
153 // first exec context for this process... initialize & enable 154 ExecContext *xc = execContexts[0];
| 153 // first thread context for this process... initialize & enable 154 ThreadContext *tc = threadContexts[0];
|
155 156 // mark this context as active so it will start ticking.
| 155 156 // mark this context as active so it will start ticking.
|
157 xc->activate(0);
| 157 tc->activate(0);
|
158 159 Port *mem_port; 160 mem_port = system->physmem->getPort("functional"); 161 initVirtMem = new TranslatingPort("process init port", pTable, true); 162 mem_port->setPeer(initVirtMem); 163 initVirtMem->setPeer(mem_port); 164} 165 166void
| 158 159 Port *mem_port; 160 mem_port = system->physmem->getPort("functional"); 161 initVirtMem = new TranslatingPort("process init port", pTable, true); 162 mem_port->setPeer(initVirtMem); 163 initVirtMem->setPeer(mem_port); 164} 165 166void
|
167Process::replaceExecContext(ExecContext *xc, int xcIndex)
| 167Process::replaceThreadContext(ThreadContext *tc, int tcIndex)
|
168{
| 168{
|
169 if (xcIndex >= execContexts.size()) { 170 panic("replaceExecContext: bad xcIndex, %d >= %d\n", 171 xcIndex, execContexts.size());
| 169 if (tcIndex >= threadContexts.size()) { 170 panic("replaceThreadContext: bad tcIndex, %d >= %d\n", 171 tcIndex, threadContexts.size());
|
172 } 173
| 172 } 173
|
174 execContexts[xcIndex] = xc;
| 174 threadContexts[tcIndex] = tc;
|
175} 176 177// map simulator fd sim_fd to target fd tgt_fd 178void 179Process::dup_fd(int sim_fd, int tgt_fd) 180{ 181 if (tgt_fd < 0 || tgt_fd > MAX_FD) 182 panic("Process::dup_fd tried to dup past MAX_FD (%d)", tgt_fd); 183 184 fd_map[tgt_fd] = sim_fd; 185} 186 187 188// generate new target fd for sim_fd 189int 190Process::alloc_fd(int sim_fd) 191{ 192 // in case open() returns an error, don't allocate a new fd 193 if (sim_fd == -1) 194 return -1; 195 196 // find first free target fd 197 for (int free_fd = 0; free_fd < MAX_FD; ++free_fd) { 198 if (fd_map[free_fd] == -1) { 199 fd_map[free_fd] = sim_fd; 200 return free_fd; 201 } 202 } 203 204 panic("Process::alloc_fd: out of file descriptors!"); 205} 206 207 208// free target fd (e.g., after close) 209void 210Process::free_fd(int tgt_fd) 211{ 212 if (fd_map[tgt_fd] == -1) 213 warn("Process::free_fd: request to free unused fd %d", tgt_fd); 214 215 fd_map[tgt_fd] = -1; 216} 217 218 219// look up simulator fd for given target fd 220int 221Process::sim_fd(int tgt_fd) 222{ 223 if (tgt_fd > MAX_FD) 224 return -1; 225 226 return fd_map[tgt_fd]; 227} 228 229 230 231// 232// need to declare these here since there is no concrete Process type 233// that can be constructed (i.e., no REGISTER_SIM_OBJECT() macro call, 234// which is where these get declared for concrete types). 235// 236DEFINE_SIM_OBJECT_CLASS_NAME("Process", Process) 237 238 239//////////////////////////////////////////////////////////////////////// 240// 241// LiveProcess member definitions 242// 243//////////////////////////////////////////////////////////////////////// 244 245 246void 247copyStringArray(vector<string> &strings, Addr array_ptr, Addr data_ptr, 248 TranslatingPort* memPort) 249{ 250 Addr data_ptr_swap; 251 for (int i = 0; i < strings.size(); ++i) { 252 data_ptr_swap = htog(data_ptr); 253 memPort->writeBlob(array_ptr, (uint8_t*)&data_ptr_swap, sizeof(Addr)); 254 memPort->writeString(data_ptr, strings[i].c_str()); 255 array_ptr += sizeof(Addr); 256 data_ptr += strings[i].size() + 1; 257 } 258 // add NULL terminator 259 data_ptr = 0; 260 261 memPort->writeBlob(array_ptr, (uint8_t*)&data_ptr, sizeof(Addr)); 262} 263 264LiveProcess::LiveProcess(const string &nm, ObjectFile *_objFile, 265 System *_system, 266 int stdin_fd, int stdout_fd, int stderr_fd, 267 vector<string> &_argv, vector<string> &_envp) 268 : Process(nm, _system, stdin_fd, stdout_fd, stderr_fd), 269 objFile(_objFile), argv(_argv), envp(_envp) 270{ 271 prog_fname = argv[0]; 272 273 // load up symbols, if any... these may be used for debugging or 274 // profiling. 275 if (!debugSymbolTable) { 276 debugSymbolTable = new SymbolTable(); 277 if (!objFile->loadGlobalSymbols(debugSymbolTable) || 278 !objFile->loadLocalSymbols(debugSymbolTable)) { 279 // didn't load any symbols 280 delete debugSymbolTable; 281 debugSymbolTable = NULL; 282 } 283 } 284} 285 286void 287LiveProcess::argsInit(int intSize, int pageSize) 288{ 289 Process::startup(); 290 291 // load object file into target memory 292 objFile->loadSections(initVirtMem); 293 294 // Calculate how much space we need for arg & env arrays. 295 int argv_array_size = intSize * (argv.size() + 1); 296 int envp_array_size = intSize * (envp.size() + 1); 297 int arg_data_size = 0; 298 for (int i = 0; i < argv.size(); ++i) { 299 arg_data_size += argv[i].size() + 1; 300 } 301 int env_data_size = 0; 302 for (int i = 0; i < envp.size(); ++i) { 303 env_data_size += envp[i].size() + 1; 304 } 305 306 int space_needed = 307 argv_array_size + envp_array_size + arg_data_size + env_data_size; 308 // for SimpleScalar compatibility 309 if (space_needed < 16384) 310 space_needed = 16384; 311 312 // set bottom of stack 313 stack_min = stack_base - space_needed; 314 // align it 315 stack_min &= ~(intSize-1); 316 stack_size = stack_base - stack_min; 317 // map memory 318 pTable->allocate(roundDown(stack_min, pageSize), 319 roundUp(stack_size, pageSize)); 320 321 // map out initial stack contents 322 Addr argv_array_base = stack_min + intSize; // room for argc 323 Addr envp_array_base = argv_array_base + argv_array_size; 324 Addr arg_data_base = envp_array_base + envp_array_size; 325 Addr env_data_base = arg_data_base + arg_data_size; 326 327 // write contents to stack 328 uint64_t argc = argv.size(); 329 if (intSize == 8) 330 argc = htog((uint64_t)argc); 331 else if (intSize == 4) 332 argc = htog((uint32_t)argc); 333 else 334 panic("Unknown int size"); 335 336 initVirtMem->writeBlob(stack_min, (uint8_t*)&argc, intSize); 337 338 copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem); 339 copyStringArray(envp, envp_array_base, env_data_base, initVirtMem); 340
| 175} 176 177// map simulator fd sim_fd to target fd tgt_fd 178void 179Process::dup_fd(int sim_fd, int tgt_fd) 180{ 181 if (tgt_fd < 0 || tgt_fd > MAX_FD) 182 panic("Process::dup_fd tried to dup past MAX_FD (%d)", tgt_fd); 183 184 fd_map[tgt_fd] = sim_fd; 185} 186 187 188// generate new target fd for sim_fd 189int 190Process::alloc_fd(int sim_fd) 191{ 192 // in case open() returns an error, don't allocate a new fd 193 if (sim_fd == -1) 194 return -1; 195 196 // find first free target fd 197 for (int free_fd = 0; free_fd < MAX_FD; ++free_fd) { 198 if (fd_map[free_fd] == -1) { 199 fd_map[free_fd] = sim_fd; 200 return free_fd; 201 } 202 } 203 204 panic("Process::alloc_fd: out of file descriptors!"); 205} 206 207 208// free target fd (e.g., after close) 209void 210Process::free_fd(int tgt_fd) 211{ 212 if (fd_map[tgt_fd] == -1) 213 warn("Process::free_fd: request to free unused fd %d", tgt_fd); 214 215 fd_map[tgt_fd] = -1; 216} 217 218 219// look up simulator fd for given target fd 220int 221Process::sim_fd(int tgt_fd) 222{ 223 if (tgt_fd > MAX_FD) 224 return -1; 225 226 return fd_map[tgt_fd]; 227} 228 229 230 231// 232// need to declare these here since there is no concrete Process type 233// that can be constructed (i.e., no REGISTER_SIM_OBJECT() macro call, 234// which is where these get declared for concrete types). 235// 236DEFINE_SIM_OBJECT_CLASS_NAME("Process", Process) 237 238 239//////////////////////////////////////////////////////////////////////// 240// 241// LiveProcess member definitions 242// 243//////////////////////////////////////////////////////////////////////// 244 245 246void 247copyStringArray(vector<string> &strings, Addr array_ptr, Addr data_ptr, 248 TranslatingPort* memPort) 249{ 250 Addr data_ptr_swap; 251 for (int i = 0; i < strings.size(); ++i) { 252 data_ptr_swap = htog(data_ptr); 253 memPort->writeBlob(array_ptr, (uint8_t*)&data_ptr_swap, sizeof(Addr)); 254 memPort->writeString(data_ptr, strings[i].c_str()); 255 array_ptr += sizeof(Addr); 256 data_ptr += strings[i].size() + 1; 257 } 258 // add NULL terminator 259 data_ptr = 0; 260 261 memPort->writeBlob(array_ptr, (uint8_t*)&data_ptr, sizeof(Addr)); 262} 263 264LiveProcess::LiveProcess(const string &nm, ObjectFile *_objFile, 265 System *_system, 266 int stdin_fd, int stdout_fd, int stderr_fd, 267 vector<string> &_argv, vector<string> &_envp) 268 : Process(nm, _system, stdin_fd, stdout_fd, stderr_fd), 269 objFile(_objFile), argv(_argv), envp(_envp) 270{ 271 prog_fname = argv[0]; 272 273 // load up symbols, if any... these may be used for debugging or 274 // profiling. 275 if (!debugSymbolTable) { 276 debugSymbolTable = new SymbolTable(); 277 if (!objFile->loadGlobalSymbols(debugSymbolTable) || 278 !objFile->loadLocalSymbols(debugSymbolTable)) { 279 // didn't load any symbols 280 delete debugSymbolTable; 281 debugSymbolTable = NULL; 282 } 283 } 284} 285 286void 287LiveProcess::argsInit(int intSize, int pageSize) 288{ 289 Process::startup(); 290 291 // load object file into target memory 292 objFile->loadSections(initVirtMem); 293 294 // Calculate how much space we need for arg & env arrays. 295 int argv_array_size = intSize * (argv.size() + 1); 296 int envp_array_size = intSize * (envp.size() + 1); 297 int arg_data_size = 0; 298 for (int i = 0; i < argv.size(); ++i) { 299 arg_data_size += argv[i].size() + 1; 300 } 301 int env_data_size = 0; 302 for (int i = 0; i < envp.size(); ++i) { 303 env_data_size += envp[i].size() + 1; 304 } 305 306 int space_needed = 307 argv_array_size + envp_array_size + arg_data_size + env_data_size; 308 // for SimpleScalar compatibility 309 if (space_needed < 16384) 310 space_needed = 16384; 311 312 // set bottom of stack 313 stack_min = stack_base - space_needed; 314 // align it 315 stack_min &= ~(intSize-1); 316 stack_size = stack_base - stack_min; 317 // map memory 318 pTable->allocate(roundDown(stack_min, pageSize), 319 roundUp(stack_size, pageSize)); 320 321 // map out initial stack contents 322 Addr argv_array_base = stack_min + intSize; // room for argc 323 Addr envp_array_base = argv_array_base + argv_array_size; 324 Addr arg_data_base = envp_array_base + envp_array_size; 325 Addr env_data_base = arg_data_base + arg_data_size; 326 327 // write contents to stack 328 uint64_t argc = argv.size(); 329 if (intSize == 8) 330 argc = htog((uint64_t)argc); 331 else if (intSize == 4) 332 argc = htog((uint32_t)argc); 333 else 334 panic("Unknown int size"); 335 336 initVirtMem->writeBlob(stack_min, (uint8_t*)&argc, intSize); 337 338 copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem); 339 copyStringArray(envp, envp_array_base, env_data_base, initVirtMem); 340
|
341 execContexts[0]->setIntReg(ArgumentReg0, argc); 342 execContexts[0]->setIntReg(ArgumentReg1, argv_array_base); 343 execContexts[0]->setIntReg(StackPointerReg, stack_min);
| 341 threadContexts[0]->setIntReg(ArgumentReg0, argc); 342 threadContexts[0]->setIntReg(ArgumentReg1, argv_array_base); 343 threadContexts[0]->setIntReg(StackPointerReg, stack_min);
|
344 345 Addr prog_entry = objFile->entryPoint();
| 344 345 Addr prog_entry = objFile->entryPoint();
|
346 execContexts[0]->setPC(prog_entry); 347 execContexts[0]->setNextPC(prog_entry + sizeof(MachInst)); 348 execContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst)));
| 346 threadContexts[0]->setPC(prog_entry); 347 threadContexts[0]->setNextPC(prog_entry + sizeof(MachInst)); 348 threadContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst)));
|
349 350 num_processes++; 351} 352 353void
| 349 350 num_processes++; 351} 352 353void
|
354LiveProcess::syscall(int64_t callnum, ExecContext *xc)
| 354LiveProcess::syscall(int64_t callnum, ThreadContext *tc)
|
355{ 356 num_syscalls++; 357 358 SyscallDesc *desc = getDesc(callnum); 359 if (desc == NULL) 360 fatal("Syscall %d out of range", callnum); 361
| 355{ 356 num_syscalls++; 357 358 SyscallDesc *desc = getDesc(callnum); 359 if (desc == NULL) 360 fatal("Syscall %d out of range", callnum); 361
|
362 desc->doSyscall(callnum, this, xc);
| 362 desc->doSyscall(callnum, this, tc);
|
363} 364 365DEFINE_SIM_OBJECT_CLASS_NAME("LiveProcess", LiveProcess);
| 363} 364 365DEFINE_SIM_OBJECT_CLASS_NAME("LiveProcess", LiveProcess);
|