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