1 // [AsmJit]
2 // Machine Code Generation for C++.
3 //
4 // [License]
5 // Zlib - See LICENSE.md file in the package.
6 
7 #define ASMJIT_EXPORTS
8 
9 #include "../core/build.h"
10 #ifndef ASMJIT_NO_LOGGING
11 
12 #include "../core/builder.h"
13 #include "../core/codeholder.h"
14 #include "../core/compiler.h"
15 #include "../core/emitter.h"
16 #include "../core/logging.h"
17 #include "../core/string.h"
18 #include "../core/support.h"
19 #include "../core/type.h"
20 
21 #ifdef ASMJIT_BUILD_X86
22   #include "../x86/x86logging_p.h"
23 #endif
24 
25 #ifdef ASMJIT_BUILD_ARM
26   #include "../arm/armlogging_p.h"
27 #endif
28 
29 ASMJIT_BEGIN_NAMESPACE
30 
31 #if defined(ASMJIT_NO_COMPILER)
32 class VirtReg;
33 #endif
34 
35 // ============================================================================
36 // [asmjit::Logger - Construction / Destruction]
37 // ============================================================================
38 
Logger()39 Logger::Logger() noexcept
40   : _options() {}
~Logger()41 Logger::~Logger() noexcept {}
42 
43 // ============================================================================
44 // [asmjit::Logger - Logging]
45 // ============================================================================
46 
logf(const char * fmt,...)47 Error Logger::logf(const char* fmt, ...) noexcept {
48   Error err;
49   va_list ap;
50 
51   va_start(ap, fmt);
52   err = logv(fmt, ap);
53   va_end(ap);
54 
55   return err;
56 }
57 
logv(const char * fmt,va_list ap)58 Error Logger::logv(const char* fmt, va_list ap) noexcept {
59   StringTmp<2048> sb;
60   ASMJIT_PROPAGATE(sb.appendVFormat(fmt, ap));
61   return log(sb);
62 }
63 
logBinary(const void * data,size_t size)64 Error Logger::logBinary(const void* data, size_t size) noexcept {
65   static const char prefix[] = "db ";
66 
67   StringTmp<256> sb;
68   sb.appendString(prefix, ASMJIT_ARRAY_SIZE(prefix) - 1);
69 
70   size_t i = size;
71   const uint8_t* s = static_cast<const uint8_t*>(data);
72 
73   while (i) {
74     uint32_t n = uint32_t(Support::min<size_t>(i, 16));
75     sb.truncate(ASMJIT_ARRAY_SIZE(prefix) - 1);
76     sb.appendHex(s, n);
77     sb.appendChar('\n');
78     ASMJIT_PROPAGATE(log(sb));
79     s += n;
80     i -= n;
81   }
82 
83   return kErrorOk;
84 }
85 
86 // ============================================================================
87 // [asmjit::FileLogger - Construction / Destruction]
88 // ============================================================================
89 
FileLogger(FILE * file)90 FileLogger::FileLogger(FILE* file) noexcept
91   : _file(nullptr) { setFile(file); }
~FileLogger()92 FileLogger::~FileLogger() noexcept {}
93 
94 // ============================================================================
95 // [asmjit::FileLogger - Logging]
96 // ============================================================================
97 
_log(const char * data,size_t size)98 Error FileLogger::_log(const char* data, size_t size) noexcept {
99   if (!_file)
100     return kErrorOk;
101 
102   if (size == SIZE_MAX)
103     size = strlen(data);
104 
105   fwrite(data, 1, size, _file);
106   return kErrorOk;
107 }
108 
109 // ============================================================================
110 // [asmjit::StringLogger - Construction / Destruction]
111 // ============================================================================
112 
StringLogger()113 StringLogger::StringLogger() noexcept {}
~StringLogger()114 StringLogger::~StringLogger() noexcept {}
115 
116 // ============================================================================
117 // [asmjit::StringLogger - Logging]
118 // ============================================================================
119 
_log(const char * data,size_t size)120 Error StringLogger::_log(const char* data, size_t size) noexcept {
121   return _content.appendString(data, size);
122 }
123 
124 // ============================================================================
125 // [asmjit::Logging]
126 // ============================================================================
127 
formatLabel(String & sb,uint32_t flags,const BaseEmitter * emitter,uint32_t labelId)128 Error Logging::formatLabel(
129   String& sb,
130   uint32_t flags,
131   const BaseEmitter* emitter,
132   uint32_t labelId) noexcept {
133 
134   ASMJIT_UNUSED(flags);
135 
136   const LabelEntry* le = emitter->code()->labelEntry(labelId);
137   if (ASMJIT_UNLIKELY(!le))
138     return sb.appendFormat("InvalidLabel[Id=%u]", labelId);
139 
140   if (le->hasName()) {
141     if (le->hasParent()) {
142       uint32_t parentId = le->parentId();
143       const LabelEntry* pe = emitter->code()->labelEntry(parentId);
144 
145       if (ASMJIT_UNLIKELY(!pe))
146         ASMJIT_PROPAGATE(sb.appendFormat("InvalidLabel[Id=%u]", labelId));
147       else if (ASMJIT_UNLIKELY(!pe->hasName()))
148         ASMJIT_PROPAGATE(sb.appendFormat("L%u", parentId));
149       else
150         ASMJIT_PROPAGATE(sb.appendString(pe->name()));
151 
152       ASMJIT_PROPAGATE(sb.appendChar('.'));
153     }
154     return sb.appendString(le->name());
155   }
156   else {
157     return sb.appendFormat("L%u", labelId);
158   }
159 }
160 
formatRegister(String & sb,uint32_t flags,const BaseEmitter * emitter,uint32_t archId,uint32_t regType,uint32_t regId)161 Error Logging::formatRegister(
162   String& sb,
163   uint32_t flags,
164   const BaseEmitter* emitter,
165   uint32_t archId,
166   uint32_t regType,
167   uint32_t regId) noexcept {
168 
169   #ifdef ASMJIT_BUILD_X86
170   if (ArchInfo::isX86Family(archId))
171     return x86::LoggingInternal::formatRegister(sb, flags, emitter, archId, regType, regId);
172   #endif
173 
174   #ifdef ASMJIT_BUILD_ARM
175   if (ArchInfo::isArmFamily(archId))
176     return arm::LoggingInternal::formatRegister(sb, flags, emitter, archId, regType, regId);
177   #endif
178 
179   return kErrorInvalidArch;
180 }
181 
formatOperand(String & sb,uint32_t flags,const BaseEmitter * emitter,uint32_t archId,const Operand_ & op)182 Error Logging::formatOperand(
183   String& sb,
184   uint32_t flags,
185   const BaseEmitter* emitter,
186   uint32_t archId,
187   const Operand_& op) noexcept {
188 
189   #ifdef ASMJIT_BUILD_X86
190   if (ArchInfo::isX86Family(archId))
191     return x86::LoggingInternal::formatOperand(sb, flags, emitter, archId, op);
192   #endif
193 
194   #ifdef ASMJIT_BUILD_ARM
195   if (ArchInfo::isArmFamily(archId))
196     return arm::LoggingInternal::formatOperand(sb, flags, emitter, archId, op);
197   #endif
198 
199   return kErrorInvalidArch;
200 }
201 
formatInstruction(String & sb,uint32_t flags,const BaseEmitter * emitter,uint32_t archId,const BaseInst & inst,const Operand_ * operands,uint32_t opCount)202 Error Logging::formatInstruction(
203   String& sb,
204   uint32_t flags,
205   const BaseEmitter* emitter,
206   uint32_t archId,
207   const BaseInst& inst, const Operand_* operands, uint32_t opCount) noexcept {
208 
209   #ifdef ASMJIT_BUILD_X86
210   if (ArchInfo::isX86Family(archId))
211     return x86::LoggingInternal::formatInstruction(sb, flags, emitter, archId, inst, operands, opCount);
212   #endif
213 
214   #ifdef ASMJIT_BUILD_ARM
215   if (ArchInfo::isArmFamily(archId))
216     return arm::LoggingInternal::formatInstruction(sb, flags, emitter, archId, inst, operands, opCount);
217   #endif
218 
219   return kErrorInvalidArch;
220 }
221 
formatTypeId(String & sb,uint32_t typeId)222 Error Logging::formatTypeId(String& sb, uint32_t typeId) noexcept {
223   if (typeId == Type::kIdVoid)
224     return sb.appendString("void");
225 
226   if (!Type::isValid(typeId))
227     return sb.appendString("unknown");
228 
229   const char* typeName = "unknown";
230   uint32_t typeSize = Type::sizeOf(typeId);
231 
232   uint32_t baseId = Type::baseOf(typeId);
233   switch (baseId) {
234     case Type::kIdIntPtr : typeName = "iptr"  ; break;
235     case Type::kIdUIntPtr: typeName = "uptr"  ; break;
236     case Type::kIdI8     : typeName = "i8"    ; break;
237     case Type::kIdU8     : typeName = "u8"    ; break;
238     case Type::kIdI16    : typeName = "i16"   ; break;
239     case Type::kIdU16    : typeName = "u16"   ; break;
240     case Type::kIdI32    : typeName = "i32"   ; break;
241     case Type::kIdU32    : typeName = "u32"   ; break;
242     case Type::kIdI64    : typeName = "i64"   ; break;
243     case Type::kIdU64    : typeName = "u64"   ; break;
244     case Type::kIdF32    : typeName = "f32"   ; break;
245     case Type::kIdF64    : typeName = "f64"   ; break;
246     case Type::kIdF80    : typeName = "f80"   ; break;
247     case Type::kIdMask8  : typeName = "mask8" ; break;
248     case Type::kIdMask16 : typeName = "mask16"; break;
249     case Type::kIdMask32 : typeName = "mask32"; break;
250     case Type::kIdMask64 : typeName = "mask64"; break;
251     case Type::kIdMmx32  : typeName = "mmx32" ; break;
252     case Type::kIdMmx64  : typeName = "mmx64" ; break;
253   }
254 
255   uint32_t baseSize = Type::sizeOf(baseId);
256   if (typeSize > baseSize) {
257     uint32_t count = typeSize / baseSize;
258     return sb.appendFormat("%sx%u", typeName, unsigned(count));
259   }
260   else {
261     return sb.appendString(typeName);
262   }
263 
264 }
265 
266 #ifndef ASMJIT_NO_BUILDER
formatFuncValue(String & sb,uint32_t flags,const BaseEmitter * emitter,FuncValue value)267 static Error formatFuncValue(String& sb, uint32_t flags, const BaseEmitter* emitter, FuncValue value) noexcept {
268   uint32_t typeId = value.typeId();
269   ASMJIT_PROPAGATE(Logging::formatTypeId(sb, typeId));
270 
271   if (value.isReg()) {
272     ASMJIT_PROPAGATE(sb.appendChar('@'));
273     ASMJIT_PROPAGATE(Logging::formatRegister(sb, flags, emitter, emitter->archId(), value.regType(), value.regId()));
274   }
275 
276   if (value.isStack()) {
277     ASMJIT_PROPAGATE(sb.appendFormat("@[%d]", int(value.stackOffset())));
278   }
279 
280   return kErrorOk;
281 }
282 
formatFuncRets(String & sb,uint32_t flags,const BaseEmitter * emitter,const FuncDetail & fd,VirtReg * const * vRegs)283 static Error formatFuncRets(
284   String& sb,
285   uint32_t flags,
286   const BaseEmitter* emitter,
287   const FuncDetail& fd,
288   VirtReg* const* vRegs) noexcept {
289 
290   if (!fd.hasRet())
291     return sb.appendString("void");
292 
293   for (uint32_t i = 0; i < fd.retCount(); i++) {
294     if (i) ASMJIT_PROPAGATE(sb.appendString(", "));
295     ASMJIT_PROPAGATE(formatFuncValue(sb, flags, emitter, fd.ret(i)));
296 
297     #ifndef ASMJIT_NO_COMPILER
298     if (vRegs) {
299       static const char nullRet[] = "<none>";
300       ASMJIT_PROPAGATE(sb.appendFormat(" %s", vRegs[i] ? vRegs[i]->name() : nullRet));
301     }
302     #endif
303   }
304 
305   return kErrorOk;
306 }
307 
formatFuncArgs(String & sb,uint32_t flags,const BaseEmitter * emitter,const FuncDetail & fd,VirtReg * const * vRegs)308 static Error formatFuncArgs(
309   String& sb,
310   uint32_t flags,
311   const BaseEmitter* emitter,
312   const FuncDetail& fd,
313   VirtReg* const* vRegs) noexcept {
314 
315   uint32_t count = fd.argCount();
316   if (!count)
317     return sb.appendString("void");
318 
319   for (uint32_t i = 0; i < count; i++) {
320     if (i) ASMJIT_PROPAGATE(sb.appendString(", "));
321     ASMJIT_PROPAGATE(formatFuncValue(sb, flags, emitter, fd.arg(i)));
322 
323     #ifndef ASMJIT_NO_COMPILER
324     if (vRegs) {
325       static const char nullArg[] = "<none>";
326       ASMJIT_PROPAGATE(sb.appendFormat(" %s", vRegs[i] ? vRegs[i]->name() : nullArg));
327     }
328     #endif
329   }
330 
331   return kErrorOk;
332 }
333 
formatNode(String & sb,uint32_t flags,const BaseBuilder * cb,const BaseNode * node_)334 Error Logging::formatNode(
335   String& sb,
336   uint32_t flags,
337   const BaseBuilder* cb,
338   const BaseNode* node_) noexcept {
339 
340   if (node_->hasPosition() && (flags & FormatOptions::kFlagPositions) != 0)
341     ASMJIT_PROPAGATE(sb.appendFormat("<%05u> ", node_->position()));
342 
343   switch (node_->type()) {
344     case BaseNode::kNodeInst: {
345       const InstNode* node = node_->as<InstNode>();
346       ASMJIT_PROPAGATE(
347         Logging::formatInstruction(sb, flags, cb,
348           cb->archId(),
349           node->baseInst(), node->operands(), node->opCount()));
350       break;
351     }
352 
353     case BaseNode::kNodeSection: {
354       const SectionNode* node = node_->as<SectionNode>();
355       if (cb->_code->isSectionValid(node->id())) {
356         const Section* section = cb->_code->sectionById(node->id());
357         ASMJIT_PROPAGATE(sb.appendFormat(".section %s", section->name()));
358       }
359       break;
360     }
361 
362     case BaseNode::kNodeLabel: {
363       const LabelNode* node = node_->as<LabelNode>();
364       ASMJIT_PROPAGATE(formatLabel(sb, flags, cb, node->id()));
365       ASMJIT_PROPAGATE(sb.appendString(":"));
366       break;
367     }
368 
369     case BaseNode::kNodeAlign: {
370       const AlignNode* node = node_->as<AlignNode>();
371       ASMJIT_PROPAGATE(
372         sb.appendFormat(".align %u (%s)",
373           node->alignment(),
374           node->alignMode() == kAlignCode ? "code" : "data"));
375       break;
376     }
377 
378     case BaseNode::kNodeEmbedData: {
379       const EmbedDataNode* node = node_->as<EmbedDataNode>();
380       ASMJIT_PROPAGATE(sb.appendFormat(".embed (%u bytes)", node->size()));
381       break;
382     }
383 
384     case BaseNode::kNodeEmbedLabel: {
385       const EmbedLabelNode* node = node_->as<EmbedLabelNode>();
386       ASMJIT_PROPAGATE(sb.appendString(".label "));
387       ASMJIT_PROPAGATE(formatLabel(sb, flags, cb, node->id()));
388       break;
389     }
390 
391     case BaseNode::kNodeEmbedLabelDelta: {
392       const EmbedLabelDeltaNode* node = node_->as<EmbedLabelDeltaNode>();
393       ASMJIT_PROPAGATE(sb.appendString(".label ("));
394       ASMJIT_PROPAGATE(formatLabel(sb, flags, cb, node->id()));
395       ASMJIT_PROPAGATE(sb.appendString(" - "));
396       ASMJIT_PROPAGATE(formatLabel(sb, flags, cb, node->baseId()));
397       ASMJIT_PROPAGATE(sb.appendString(")"));
398       break;
399     }
400 
401     case BaseNode::kNodeComment: {
402       const CommentNode* node = node_->as<CommentNode>();
403       ASMJIT_PROPAGATE(sb.appendFormat("; %s", node->inlineComment()));
404       break;
405     }
406 
407     case BaseNode::kNodeSentinel: {
408       const SentinelNode* node = node_->as<SentinelNode>();
409       const char* sentinelName = nullptr;
410 
411       switch (node->sentinelType()) {
412         case SentinelNode::kSentinelFuncEnd:
413           sentinelName = "[FuncEnd]";
414           break;
415 
416         default:
417           sentinelName = "[Sentinel]";
418           break;
419       }
420 
421       ASMJIT_PROPAGATE(sb.appendString(sentinelName));
422       break;
423     }
424 
425     #ifndef ASMJIT_NO_COMPILER
426     case BaseNode::kNodeFunc: {
427       const FuncNode* node = node_->as<FuncNode>();
428 
429       ASMJIT_PROPAGATE(formatLabel(sb, flags, cb, node->id()));
430       ASMJIT_PROPAGATE(sb.appendString(": "));
431 
432       ASMJIT_PROPAGATE(formatFuncRets(sb, flags, cb, node->detail(), nullptr));
433       ASMJIT_PROPAGATE(sb.appendString(" Func("));
434       ASMJIT_PROPAGATE(formatFuncArgs(sb, flags, cb, node->detail(), node->args()));
435       ASMJIT_PROPAGATE(sb.appendString(")"));
436       break;
437     }
438 
439     case BaseNode::kNodeFuncRet: {
440       const FuncRetNode* node = node_->as<FuncRetNode>();
441       ASMJIT_PROPAGATE(sb.appendString("[FuncRet]"));
442 
443       for (uint32_t i = 0; i < 2; i++) {
444         const Operand_& op = node->_opArray[i];
445         if (!op.isNone()) {
446           ASMJIT_PROPAGATE(sb.appendString(i == 0 ? " " : ", "));
447           ASMJIT_PROPAGATE(formatOperand(sb, flags, cb, cb->archId(), op));
448         }
449       }
450       break;
451     }
452 
453     case BaseNode::kNodeFuncCall: {
454       const FuncCallNode* node = node_->as<FuncCallNode>();
455       ASMJIT_PROPAGATE(
456         Logging::formatInstruction(sb, flags, cb,
457           cb->archId(),
458           node->baseInst(), node->operands(), node->opCount()));
459       break;
460     }
461     #endif
462 
463     default: {
464       ASMJIT_PROPAGATE(sb.appendFormat("[User:%u]", node_->type()));
465       break;
466     }
467   }
468 
469   return kErrorOk;
470 }
471 #endif
472 
formatLine(String & sb,const uint8_t * binData,size_t binSize,size_t dispSize,size_t immSize,const char * comment)473 Error Logging::formatLine(String& sb, const uint8_t* binData, size_t binSize, size_t dispSize, size_t immSize, const char* comment) noexcept {
474   size_t currentSize = sb.size();
475   size_t commentSize = comment ? Support::strLen(comment, Globals::kMaxCommentSize) : 0;
476 
477   ASMJIT_ASSERT(binSize >= dispSize);
478   const size_t kNoBinSize = std::numeric_limits<size_t>::max();
479 
480   if ((binSize != 0 && binSize != kNoBinSize) || commentSize) {
481     size_t align = kMaxInstLineSize;
482     char sep = ';';
483 
484     for (size_t i = (binSize == kNoBinSize); i < 2; i++) {
485       size_t begin = sb.size();
486       ASMJIT_PROPAGATE(sb.padEnd(align));
487 
488       if (sep) {
489         ASMJIT_PROPAGATE(sb.appendChar(sep));
490         ASMJIT_PROPAGATE(sb.appendChar(' '));
491       }
492 
493       // Append binary data or comment.
494       if (i == 0) {
495         ASMJIT_PROPAGATE(sb.appendHex(binData, binSize - dispSize - immSize));
496         ASMJIT_PROPAGATE(sb.appendChars('.', dispSize * 2));
497         ASMJIT_PROPAGATE(sb.appendHex(binData + binSize - immSize, immSize));
498         if (commentSize == 0) break;
499       }
500       else {
501         ASMJIT_PROPAGATE(sb.appendString(comment, commentSize));
502       }
503 
504       currentSize += sb.size() - begin;
505       align += kMaxBinarySize;
506       sep = '|';
507     }
508   }
509 
510   return sb.appendChar('\n');
511 }
512 
513 ASMJIT_END_NAMESPACE
514 
515 #endif
516