Logging and formatting.
Overview
The initial phase of a project that generates machine code is not always smooth. Failure cases are common not just at the beginning phase, but also during the development or refactoring. AsmJit provides logging functionality to address this issue. AsmJit does already a good job with function overloading to prevent from emitting unencodable instructions, but it can't prevent from emitting machine code that is correct at instruction level, but doesn't work when it's executed asa whole. Logging has always been an important part of AsmJit's infrastructure and looking at logs can sometimes reveal code generation issues quickly.
AsmJit provides API for logging and formatting:
AsmJit's Logger serves the following purposes:
- Provides a basic foundation for logging.
- Abstract class leaving the implementation on users. The following built-in implementations are provided for simplicity:
AsmJit's FormatOptions provides the following to customize the formatting of instructions and operands through:
Logging
A Logger is typically attached to a CodeHolder, which propagates it to all attached emitters automatically. The example below illustrates how to use FileLogger that outputs to standard output:
#include <asmjit/core.h>
#include <stdio.h>
int main() {
return 0;
}
If output to FILE stream is not desired it's possible to use StringLogger, which concatenates everything into a multi-line string:
#include <asmjit/core.h>
#include <stdio.h>
#include <utility>
int main() {
printf(
"Logger content: %s\n", logger.
data());
printf(
"The same content: %s\n", content.
data());
return 0;
}
Formatting
AsmJit uses Formatter to format inputs that are then passed to Logger. Formatting is public and can be used by AsmJit users as well. The most important thing to know regarding formatting is that Formatter always appends to the output string, so it can be used to build complex strings without having to concatenate intermediate strings.
The first example illustrates how to format operands:
#include <asmjit/x86.h>
#include <stdio.h>
printf(
"%s\n", sb.
data());
}
void formattingExample() {
using namespace x86;
logOperand(arch, rax);
logOperand(arch, ptr(rax, rbx, 2));
logOperand(arch, dword_ptr(rax, rbx, 2));
logOperand(arch,
imm(42));
}
Next example illustrates how to format whole instructions:
#include <asmjit/x86.h>
#include <stdio.h>
#include <utility>
template<typename... Args>
void logInstruction(
Arch arch,
const BaseInst& inst, Args&&... args) {
Operand_ operands[] { std::forward<Args>(args)... };
sb, formatFlags, emitter, arch, inst, operands, sizeof...(args));
printf(
"%s\n", sb.
data());
}
void formattingExample() {
using namespace x86;
logInstruction(arch,
BaseInst(Inst::kIdMov), rax, rcx);
logInstruction(arch,
zmm0, zmm1, ptr(rax)._1to8());
logInstruction(arch,
ptr(rax), rcx);
logInstruction(arch,
zmm0, zmm1, ptr(rax));
}
And finally, the example below illustrates how to use a built-in function to format the content of BaseBuilder, which consists of nodes:
#include <asmjit/core.h>
#include <stdio.h>
printf(
"%s\n", sb.
data());
}
class FormatFlags : uint32_tenumstrong◆
Format flags used by Logger and FormatOptions.
Constant | Description |
---|
kNone | No formatting flags.
|
kMachineCode | Show also binary form of each logged instruction (Assembler).
|
kExplainImms | Show a text explanation of some immediate values.
|
kHexImms | Use hexadecimal notation of immediate values.
|
kHexOffsets | Use hexadecimal notation of addresses and offsets in addresses.
|
kRegCasts | Show casts between virtual register types (Compiler output).
|
kPositions | Show positions associated with nodes (Compiler output).
|
kRegType | Always format a register type (Compiler output).
|
Format indentation group, used by FormatOptions.
Constant | Description |
---|
kCode | Indentation used for instructions and directives.
|
kLabel | Indentation used for labels and function nodes.
|
kComment | Indentation used for comments (not inline comments).
|
kMaxValue | Maximum value of FormatIndentationGroup .
|
Format padding group, used by FormatOptions.
Constant | Description |
---|
kRegularLine | Describes padding of a regular line, which can represent instruction, data, or assembler directives.
|
kMachineCode | Describes padding of machine code dump that is visible next to the instruction, if enabled.
|
kMaxValue | Maximum value of FormatPaddingGroup .
|