disassembler.cc revision f87a203d89e1bbb6708282e0b64dbd13d59b723d
1// Copyright 2006-2008 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from 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#include "v8.h" 29 30#include "code-stubs.h" 31#include "codegen-inl.h" 32#include "debug.h" 33#include "disasm.h" 34#include "disassembler.h" 35#include "macro-assembler.h" 36#include "serialize.h" 37#include "string-stream.h" 38 39namespace v8 { 40namespace internal { 41 42#ifdef ENABLE_DISASSEMBLER 43 44void Disassembler::Dump(FILE* f, byte* begin, byte* end) { 45 for (byte* pc = begin; pc < end; pc++) { 46 if (f == NULL) { 47 PrintF("%" V8PRIxPTR " %4" V8PRIdPTR " %02x\n", 48 reinterpret_cast<intptr_t>(pc), 49 pc - begin, 50 *pc); 51 } else { 52 fprintf(f, "%" V8PRIxPTR " %4" V8PRIdPTR " %02x\n", 53 reinterpret_cast<uintptr_t>(pc), pc - begin, *pc); 54 } 55 } 56} 57 58 59class V8NameConverter: public disasm::NameConverter { 60 public: 61 explicit V8NameConverter(Code* code) : code_(code) {} 62 virtual const char* NameOfAddress(byte* pc) const; 63 virtual const char* NameInCode(byte* addr) const; 64 Code* code() const { return code_; } 65 private: 66 Code* code_; 67}; 68 69 70const char* V8NameConverter::NameOfAddress(byte* pc) const { 71 static v8::internal::EmbeddedVector<char, 128> buffer; 72 73 const char* name = Builtins::Lookup(pc); 74 if (name != NULL) { 75 OS::SNPrintF(buffer, "%s (%p)", name, pc); 76 return buffer.start(); 77 } 78 79 if (code_ != NULL) { 80 int offs = static_cast<int>(pc - code_->instruction_start()); 81 // print as code offset, if it seems reasonable 82 if (0 <= offs && offs < code_->instruction_size()) { 83 OS::SNPrintF(buffer, "%d (%p)", offs, pc); 84 return buffer.start(); 85 } 86 } 87 88 return disasm::NameConverter::NameOfAddress(pc); 89} 90 91 92const char* V8NameConverter::NameInCode(byte* addr) const { 93 // The V8NameConverter is used for well known code, so we can "safely" 94 // dereference pointers in generated code. 95 return (code_ != NULL) ? reinterpret_cast<const char*>(addr) : ""; 96} 97 98 99static void DumpBuffer(FILE* f, char* buff) { 100 if (f == NULL) { 101 PrintF("%s", buff); 102 } else { 103 fprintf(f, "%s", buff); 104 } 105} 106 107static const int kOutBufferSize = 2048 + String::kMaxShortPrintLength; 108static const int kRelocInfoPosition = 57; 109 110static int DecodeIt(FILE* f, 111 const V8NameConverter& converter, 112 byte* begin, 113 byte* end) { 114 NoHandleAllocation ha; 115 AssertNoAllocation no_alloc; 116 ExternalReferenceEncoder ref_encoder; 117 118 v8::internal::EmbeddedVector<char, 128> decode_buffer; 119 v8::internal::EmbeddedVector<char, kOutBufferSize> out_buffer; 120 byte* pc = begin; 121 disasm::Disassembler d(converter); 122 RelocIterator* it = NULL; 123 if (converter.code() != NULL) { 124 it = new RelocIterator(converter.code()); 125 } else { 126 // No relocation information when printing code stubs. 127 } 128 int constants = -1; // no constants being decoded at the start 129 130 while (pc < end) { 131 // First decode instruction so that we know its length. 132 byte* prev_pc = pc; 133 if (constants > 0) { 134 OS::SNPrintF(decode_buffer, 135 "%08x constant", 136 *reinterpret_cast<int32_t*>(pc)); 137 constants--; 138 pc += 4; 139 } else { 140 int num_const = d.ConstantPoolSizeAt(pc); 141 if (num_const >= 0) { 142 OS::SNPrintF(decode_buffer, 143 "%08x constant pool begin", 144 *reinterpret_cast<int32_t*>(pc)); 145 constants = num_const; 146 pc += 4; 147 } else if (it != NULL && !it->done() && it->rinfo()->pc() == pc && 148 it->rinfo()->rmode() == RelocInfo::INTERNAL_REFERENCE) { 149 // raw pointer embedded in code stream, e.g., jump table 150 byte* ptr = *reinterpret_cast<byte**>(pc); 151 OS::SNPrintF(decode_buffer, 152 "%08" V8PRIxPTR " jump table entry %4" V8PRIdPTR, 153 ptr, 154 ptr - begin); 155 pc += 4; 156 } else { 157 decode_buffer[0] = '\0'; 158 pc += d.InstructionDecode(decode_buffer, pc); 159 } 160 } 161 162 // Collect RelocInfo for this instruction (prev_pc .. pc-1) 163 List<const char*> comments(4); 164 List<byte*> pcs(1); 165 List<RelocInfo::Mode> rmodes(1); 166 List<intptr_t> datas(1); 167 if (it != NULL) { 168 while (!it->done() && it->rinfo()->pc() < pc) { 169 if (RelocInfo::IsComment(it->rinfo()->rmode())) { 170 // For comments just collect the text. 171 comments.Add(reinterpret_cast<const char*>(it->rinfo()->data())); 172 } else { 173 // For other reloc info collect all data. 174 pcs.Add(it->rinfo()->pc()); 175 rmodes.Add(it->rinfo()->rmode()); 176 datas.Add(it->rinfo()->data()); 177 } 178 it->next(); 179 } 180 } 181 182 StringBuilder out(out_buffer.start(), out_buffer.length()); 183 184 // Comments. 185 for (int i = 0; i < comments.length(); i++) { 186 out.AddFormatted(" %s\n", comments[i]); 187 } 188 189 // Write out comments, resets outp so that we can format the next line. 190 DumpBuffer(f, out.Finalize()); 191 out.Reset(); 192 193 // Instruction address and instruction offset. 194 out.AddFormatted("%p %4d ", prev_pc, prev_pc - begin); 195 196 // Instruction. 197 out.AddFormatted("%s", decode_buffer.start()); 198 199 // Print all the reloc info for this instruction which are not comments. 200 for (int i = 0; i < pcs.length(); i++) { 201 // Put together the reloc info 202 RelocInfo relocinfo(pcs[i], rmodes[i], datas[i]); 203 204 // Indent the printing of the reloc info. 205 if (i == 0) { 206 // The first reloc info is printed after the disassembled instruction. 207 out.AddPadding(' ', kRelocInfoPosition - out.position()); 208 } else { 209 // Additional reloc infos are printed on separate lines. 210 out.AddFormatted("\n"); 211 out.AddPadding(' ', kRelocInfoPosition); 212 } 213 214 RelocInfo::Mode rmode = relocinfo.rmode(); 215 if (RelocInfo::IsPosition(rmode)) { 216 if (RelocInfo::IsStatementPosition(rmode)) { 217 out.AddFormatted(" ;; debug: statement %d", relocinfo.data()); 218 } else { 219 out.AddFormatted(" ;; debug: position %d", relocinfo.data()); 220 } 221 } else if (rmode == RelocInfo::EMBEDDED_OBJECT) { 222 HeapStringAllocator allocator; 223 StringStream accumulator(&allocator); 224 relocinfo.target_object()->ShortPrint(&accumulator); 225 SmartPointer<const char> obj_name = accumulator.ToCString(); 226 out.AddFormatted(" ;; object: %s", *obj_name); 227 } else if (rmode == RelocInfo::EXTERNAL_REFERENCE) { 228 const char* reference_name = 229 ref_encoder.NameOfAddress(*relocinfo.target_reference_address()); 230 out.AddFormatted(" ;; external reference (%s)", reference_name); 231 } else if (RelocInfo::IsCodeTarget(rmode)) { 232 out.AddFormatted(" ;; code:"); 233 if (rmode == RelocInfo::CONSTRUCT_CALL) { 234 out.AddFormatted(" constructor,"); 235 } 236 Code* code = Code::GetCodeFromTargetAddress(relocinfo.target_address()); 237 Code::Kind kind = code->kind(); 238 if (code->is_inline_cache_stub()) { 239 if (rmode == RelocInfo::CODE_TARGET_CONTEXT) { 240 out.AddFormatted(" contextual,"); 241 } 242 InlineCacheState ic_state = code->ic_state(); 243 out.AddFormatted(" %s, %s", Code::Kind2String(kind), 244 Code::ICState2String(ic_state)); 245 if (ic_state == MONOMORPHIC) { 246 PropertyType type = code->type(); 247 out.AddFormatted(", %s", Code::PropertyType2String(type)); 248 } 249 if (code->ic_in_loop() == IN_LOOP) { 250 out.AddFormatted(", in_loop"); 251 } 252 if (kind == Code::CALL_IC || kind == Code::KEYED_CALL_IC) { 253 out.AddFormatted(", argc = %d", code->arguments_count()); 254 } 255 } else if (kind == Code::STUB) { 256 // Reverse lookup required as the minor key cannot be retrieved 257 // from the code object. 258 Object* obj = Heap::code_stubs()->SlowReverseLookup(code); 259 if (obj != Heap::undefined_value()) { 260 ASSERT(obj->IsSmi()); 261 // Get the STUB key and extract major and minor key. 262 uint32_t key = Smi::cast(obj)->value(); 263 uint32_t minor_key = CodeStub::MinorKeyFromKey(key); 264 CodeStub::Major major_key = CodeStub::GetMajorKey(code); 265 ASSERT(major_key == CodeStub::MajorKeyFromKey(key)); 266 out.AddFormatted(" %s, %s, ", 267 Code::Kind2String(kind), 268 CodeStub::MajorName(major_key, false)); 269 switch (major_key) { 270 case CodeStub::CallFunction: 271 out.AddFormatted("argc = %d", minor_key); 272 break; 273 default: 274 out.AddFormatted("minor: %d", minor_key); 275 } 276 } 277 } else { 278 out.AddFormatted(" %s", Code::Kind2String(kind)); 279 } 280 } else { 281 out.AddFormatted(" ;; %s", RelocInfo::RelocModeName(rmode)); 282 } 283 } 284 out.AddString("\n"); 285 DumpBuffer(f, out.Finalize()); 286 out.Reset(); 287 } 288 289 delete it; 290 return static_cast<int>(pc - begin); 291} 292 293 294int Disassembler::Decode(FILE* f, byte* begin, byte* end) { 295 V8NameConverter defaultConverter(NULL); 296 return DecodeIt(f, defaultConverter, begin, end); 297} 298 299 300// Called by Code::CodePrint. 301void Disassembler::Decode(FILE* f, Code* code) { 302 byte* begin = Code::cast(code)->instruction_start(); 303 byte* end = begin + Code::cast(code)->instruction_size(); 304 V8NameConverter v8NameConverter(code); 305 DecodeIt(f, v8NameConverter, begin, end); 306} 307 308#else // ENABLE_DISASSEMBLER 309 310void Disassembler::Dump(FILE* f, byte* begin, byte* end) {} 311int Disassembler::Decode(FILE* f, byte* begin, byte* end) { return 0; } 312void Disassembler::Decode(FILE* f, Code* code) {} 313 314#endif // ENABLE_DISASSEMBLER 315 316} } // namespace v8::internal 317