stacktrace.cc revision 5222:bb733a878f85
1/* 2 * Copyright .AN) 2007 MIPS Technologies, Inc. All Rights Reserved 3 * 4 * This software is part of the M5 simulator. 5 * 6 * THIS IS A LEGAL AGREEMENT. BY DOWNLOADING, USING, COPYING, CREATING 7 * DERIVATIVE WORKS, AND/OR DISTRIBUTING THIS SOFTWARE YOU ARE AGREEING 8 * TO THESE TERMS AND CONDITIONS. 9 * 10 * Permission is granted to use, copy, create derivative works and 11 * distribute this software and such derivative works for any purpose, 12 * so long as (1) the copyright notice above, this grant of permission, 13 * and the disclaimer below appear in all copies and derivative works 14 * made, (2) the copyright notice above is augmented as appropriate to 15 * reflect the addition of any new copyrightable work in a derivative 16 * work (e.g., Copyright .AN) <Publication Year> Copyright Owner), and (3) 17 * the name of MIPS Technologies, Inc. ($B!H(BMIPS$B!I(B) is not used in any 18 * advertising or publicity pertaining to the use or distribution of 19 * this software without specific, written prior authorization. 20 * 21 * THIS SOFTWARE IS PROVIDED $B!H(BAS IS.$B!I(B MIPS MAKES NO WARRANTIES AND 22 * DISCLAIMS ALL WARRANTIES, WHETHER EXPRESS, STATUTORY, IMPLIED OR 23 * OTHERWISE, INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND 25 * NON-INFRINGEMENT OF THIRD PARTY RIGHTS, REGARDING THIS SOFTWARE. 26 * IN NO EVENT SHALL MIPS BE LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, 27 * INDIRECT, INCIDENTAL, CONSEQUENTIAL, SPECIAL, OR PUNITIVE DAMAGES OF 28 * ANY KIND OR NATURE, ARISING OUT OF OR IN CONNECTION WITH THIS AGREEMENT, 29 * THIS SOFTWARE AND/OR THE USE OF THIS SOFTWARE, WHETHER SUCH LIABILITY 30 * IS ASSERTED ON THE BASIS OF CONTRACT, TORT (INCLUDING NEGLIGENCE OR 31 * STRICT LIABILITY), OR OTHERWISE, EVEN IF MIPS HAS BEEN WARNED OF THE 32 * POSSIBILITY OF ANY SUCH LOSS OR DAMAGE IN ADVANCE. 33 * 34 * Authors: Nathan L. Binkert 35 */ 36 37#include <string> 38 39#include "arch/mips/isa_traits.hh" 40#include "arch/mips/stacktrace.hh" 41#include "arch/mips/vtophys.hh" 42#include "base/bitfield.hh" 43#include "base/trace.hh" 44#include "cpu/base.hh" 45#include "cpu/thread_context.hh" 46#include "sim/system.hh" 47 48using namespace std; 49using namespace MipsISA; 50 51ProcessInfo::ProcessInfo(ThreadContext *_tc) 52 : tc(_tc) 53{ 54// Addr addr = 0; 55 56 VirtualPort *vp; 57 58 vp = tc->getVirtPort(); 59 60// if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_size", addr)) 61// panic("thread info not compiled into kernel\n"); 62// thread_info_size = vp->readGtoH<int32_t>(addr); 63 64// if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_size", addr)) 65// panic("thread info not compiled into kernel\n"); 66// task_struct_size = vp->readGtoH<int32_t>(addr); 67 68// if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_task", addr)) 69// panic("thread info not compiled into kernel\n"); 70// task_off = vp->readGtoH<int32_t>(addr); 71 72// if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_pid", addr)) 73// panic("thread info not compiled into kernel\n"); 74// pid_off = vp->readGtoH<int32_t>(addr); 75 76// if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr)) 77// panic("thread info not compiled into kernel\n"); 78// name_off = vp->readGtoH<int32_t>(addr); 79 80 tc->delVirtPort(vp); 81} 82 83Addr 84ProcessInfo::task(Addr ksp) const 85{ 86 Addr base = ksp & ~0x3fff; 87 if (base == ULL(0xfffffc0000000000)) 88 return 0; 89 90 Addr tsk; 91 92 VirtualPort *vp; 93 94 vp = tc->getVirtPort(); 95 tsk = vp->readGtoH<Addr>(base + task_off); 96 tc->delVirtPort(vp); 97 98 return tsk; 99} 100 101int 102ProcessInfo::pid(Addr ksp) const 103{ 104 Addr task = this->task(ksp); 105 if (!task) 106 return -1; 107 108 uint16_t pd; 109 110 VirtualPort *vp; 111 112 vp = tc->getVirtPort(); 113 pd = vp->readGtoH<uint16_t>(task + pid_off); 114 tc->delVirtPort(vp); 115 116 return pd; 117} 118 119string 120ProcessInfo::name(Addr ksp) const 121{ 122 Addr task = this->task(ksp); 123 if (!task) 124 return "console"; 125 126 char comm[256]; 127 CopyStringOut(tc, comm, task + name_off, sizeof(comm)); 128 if (!comm[0]) 129 return "startup"; 130 131 return comm; 132} 133 134StackTrace::StackTrace() 135 : tc(0), stack(64) 136{ 137} 138 139StackTrace::StackTrace(ThreadContext *_tc, StaticInstPtr inst) 140 : tc(0), stack(64) 141{ 142 trace(_tc, inst); 143} 144 145StackTrace::~StackTrace() 146{ 147} 148 149void 150StackTrace::trace(ThreadContext *_tc, bool is_call) 151{ 152 tc = _tc; 153 /* FIXME - Jaidev - What is IPR_DTB_CM in Alpha? */ 154 bool usermode = 0; 155 //(tc->readMiscReg(MipsISA::IPR_DTB_CM) & 0x18) != 0; 156 157// Addr pc = tc->readNextPC(); 158// bool kernel = tc->getSystemPtr()->kernelStart <= pc && 159// pc <= tc->getSystemPtr()->kernelEnd; 160 161 if (usermode) { 162 stack.push_back(user); 163 return; 164 } 165 166// if (!kernel) { 167// stack.push_back(console); 168// return; 169// } 170 171// SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab; 172// Addr ksp = tc->readIntReg(TheISA::StackPointerReg); 173// Addr bottom = ksp & ~0x3fff; 174// Addr addr; 175 176// if (is_call) { 177// if (!symtab->findNearestAddr(pc, addr)) 178// panic("could not find address %#x", pc); 179 180// stack.push_back(addr); 181// pc = tc->readPC(); 182// } 183 184// Addr ra; 185// int size; 186 187// while (ksp > bottom) { 188// if (!symtab->findNearestAddr(pc, addr)) 189// panic("could not find symbol for pc=%#x", pc); 190// assert(pc >= addr && "symbol botch: callpc < func"); 191 192// stack.push_back(addr); 193 194// if (isEntry(addr)) 195// return; 196 197// if (decodePrologue(ksp, pc, addr, size, ra)) { 198// if (!ra) 199// return; 200 201// if (size <= 0) { 202// stack.push_back(unknown); 203// return; 204// } 205 206// pc = ra; 207// ksp += size; 208// } else { 209// stack.push_back(unknown); 210// return; 211// } 212 213// bool kernel = tc->getSystemPtr()->kernelStart <= pc && 214// pc <= tc->getSystemPtr()->kernelEnd; 215// if (!kernel) 216// return; 217 218// if (stack.size() >= 1000) 219// panic("unwinding too far"); 220// } 221 222// panic("unwinding too far"); 223} 224 225bool 226StackTrace::isEntry(Addr addr) 227{ 228 /* if (addr == tc->readMiscReg(MipsISA::IPR_PALtemp2)) 229 return true;*/ 230 231 return false; 232} 233 234bool 235StackTrace::decodeStack(MachInst inst, int &disp) 236{ 237 // lda $sp, -disp($sp) 238 // 239 // Opcode<31:26> == 0x08 240 // RA<25:21> == 30 241 // RB<20:16> == 30 242 // Disp<15:0> 243 const MachInst mem_mask = 0xffff0000; 244 const MachInst lda_pattern = 0x23de0000; 245 const MachInst lda_disp_mask = 0x0000ffff; 246 247 // subq $sp, disp, $sp 248 // addq $sp, disp, $sp 249 // 250 // Opcode<31:26> == 0x10 251 // RA<25:21> == 30 252 // Lit<20:13> 253 // One<12> = 1 254 // Func<11:5> == 0x20 (addq) 255 // Func<11:5> == 0x29 (subq) 256 // RC<4:0> == 30 257 const MachInst intop_mask = 0xffe01fff; 258 const MachInst addq_pattern = 0x43c0141e; 259 const MachInst subq_pattern = 0x43c0153e; 260 const MachInst intop_disp_mask = 0x001fe000; 261 const int intop_disp_shift = 13; 262 263 if ((inst & mem_mask) == lda_pattern) 264 disp = -sext<16>(inst & lda_disp_mask); 265 else if ((inst & intop_mask) == addq_pattern) 266 disp = -int((inst & intop_disp_mask) >> intop_disp_shift); 267 else if ((inst & intop_mask) == subq_pattern) 268 disp = int((inst & intop_disp_mask) >> intop_disp_shift); 269 else 270 return false; 271 272 return true; 273} 274 275bool 276StackTrace::decodeSave(MachInst inst, int ®, int &disp) 277{ 278 // lda $stq, disp($sp) 279 // 280 // Opcode<31:26> == 0x08 281 // RA<25:21> == ? 282 // RB<20:16> == 30 283 // Disp<15:0> 284 const MachInst stq_mask = 0xfc1f0000; 285 const MachInst stq_pattern = 0xb41e0000; 286 const MachInst stq_disp_mask = 0x0000ffff; 287 const MachInst reg_mask = 0x03e00000; 288 const int reg_shift = 21; 289 290 if ((inst & stq_mask) == stq_pattern) { 291 reg = (inst & reg_mask) >> reg_shift; 292 disp = sext<16>(inst & stq_disp_mask); 293 } else { 294 return false; 295 } 296 297 return true; 298} 299 300/* 301 * Decode the function prologue for the function we're in, and note 302 * which registers are stored where, and how large the stack frame is. 303 */ 304bool 305StackTrace::decodePrologue(Addr sp, Addr callpc, Addr func, 306 int &size, Addr &ra) 307{ 308 size = 0; 309 ra = 0; 310 311 for (Addr pc = func; pc < callpc; pc += sizeof(MachInst)) { 312 MachInst inst; 313 CopyOut(tc, (uint8_t *)&inst, pc, sizeof(MachInst)); 314 315 int reg, disp; 316 if (decodeStack(inst, disp)) { 317 if (size) { 318 // panic("decoding frame size again"); 319 return true; 320 } 321 size += disp; 322 } else if (decodeSave(inst, reg, disp)) { 323 if (!ra && reg == ReturnAddressReg) { 324 CopyOut(tc, (uint8_t *)&ra, sp + disp, sizeof(Addr)); 325 if (!ra) { 326 // panic("no return address value pc=%#x\n", pc); 327 return false; 328 } 329 } 330 } 331 } 332 333 return true; 334} 335 336#if TRACING_ON 337void 338StackTrace::dump() 339{ 340 StringWrap name(tc->getCpuPtr()->name()); 341// SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab; 342 343 DPRINTFN("------ Stack ------\n"); 344 345// string symbol; 346// for (int i = 0, size = stack.size(); i < size; ++i) { 347// Addr addr = stack[size - i - 1]; 348// if (addr == user) 349// symbol = "user"; 350// else if (addr == console) 351// symbol = "console"; 352// else if (addr == unknown) 353// symbol = "unknown"; 354// else 355// symtab->findSymbol(addr, symbol); 356 357// DPRINTFN("%#x: %s\n", addr, symbol); 358// } 359} 360#endif 361