logging.h 9.96 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.

// [Guard]
#ifndef _ASMJIT_BASE_LOGGING_H
#define _ASMJIT_BASE_LOGGING_H

// [Dependencies]
#include "../base/inst.h"
#include "../base/string.h"

// [Api-Begin]
#include "../asmjit_apibegin.h"

namespace asmjit {

//! \addtogroup asmjit_base
//! \{

#if !defined(ASMJIT_DISABLE_LOGGING)

// ============================================================================
// [Forward Declarations]
// ============================================================================

class CodeEmitter;
class Reg;
struct Operand_;

#if !defined(ASMJIT_DISABLE_BUILDER)
class CodeBuilder;
class CBNode;
#endif // !ASMJIT_DISABLE_BUILDER

// ============================================================================
// [asmjit::Logger]
// ============================================================================

//! Abstract logging interface and helpers.
//!
//! This class can be inherited and reimplemented to fit into your logging
//! subsystem. When reimplementing use `Logger::_log()` method to log into
//! a custom stream.
//!
//! There are two \ref Logger implementations offered by AsmJit:
//!   - \ref FileLogger - allows to log into a `FILE*` stream.
//!   - \ref StringLogger - logs into a \ref StringBuilder.
class ASMJIT_VIRTAPI Logger {
public:
  ASMJIT_NONCOPYABLE(Logger)

  // --------------------------------------------------------------------------
  // [Options]
  // --------------------------------------------------------------------------

  //! Logger options.
  ASMJIT_ENUM(Options) {
    kOptionBinaryForm      = 0x00000001, //! Output instructions also in binary form.
    kOptionImmExtended     = 0x00000002, //! Output a meaning of some immediates.
    kOptionHexImmediate    = 0x00000004, //! Output constants in hexadecimal form.
    kOptionHexDisplacement = 0x00000008  //! Output displacements in hexadecimal form.
  };

  // --------------------------------------------------------------------------
  // [Construction / Destruction]
  // --------------------------------------------------------------------------

  //! Create a `Logger` instance.
  ASMJIT_API Logger() noexcept;
  //! Destroy the `Logger` instance.
  ASMJIT_API virtual ~Logger() noexcept;

  // --------------------------------------------------------------------------
  // [Logging]
  // --------------------------------------------------------------------------

  //! Log `str` - must be reimplemented.
  virtual Error _log(const char* str, size_t len) noexcept = 0;

  //! Log a string `str`, which is either null terminated or having `len` length.
  ASMJIT_INLINE Error log(const char* str, size_t len = Globals::kInvalidIndex) noexcept { return _log(str, len); }
  //! Log a content of a `StringBuilder` `str`.
  ASMJIT_INLINE Error log(const StringBuilder& str) noexcept { return _log(str.getData(), str.getLength()); }

  //! Format the message by using `sprintf()` and then send to `log()`.
  ASMJIT_API Error logf(const char* fmt, ...) noexcept;
  //! Format the message by using `vsprintf()` and then send to `log()`.
  ASMJIT_API Error logv(const char* fmt, va_list ap) noexcept;
  //! Log binary data.
  ASMJIT_API Error logBinary(const void* data, size_t size) noexcept;

  // --------------------------------------------------------------------------
  // [Options]
  // --------------------------------------------------------------------------

  //! Get all logger options as a single integer.
  ASMJIT_INLINE uint32_t getOptions() const noexcept { return _options; }
  //! Get the given logger option.
  ASMJIT_INLINE bool hasOption(uint32_t option) const noexcept { return (_options & option) != 0; }
  ASMJIT_INLINE void addOptions(uint32_t options) noexcept { _options |= options; }
  ASMJIT_INLINE void clearOptions(uint32_t options) noexcept { _options &= ~options; }

  // --------------------------------------------------------------------------
  // [Indentation]
  // --------------------------------------------------------------------------

  //! Get indentation.
  ASMJIT_INLINE const char* getIndentation() const noexcept { return _indentation; }
  //! Set indentation.
  ASMJIT_API void setIndentation(const char* indentation) noexcept;
  //! Reset indentation.
  ASMJIT_INLINE void resetIndentation() noexcept { setIndentation(nullptr); }

  // --------------------------------------------------------------------------
  // [Members]
  // --------------------------------------------------------------------------

  //! Options, see \ref LoggerOption.
  uint32_t _options;

  //! Indentation.
  char _indentation[12];
};

// ============================================================================
// [asmjit::FileLogger]
// ============================================================================

//! Logger that can log to a `FILE*` stream.
class ASMJIT_VIRTAPI FileLogger : public Logger {
public:
  ASMJIT_NONCOPYABLE(FileLogger)

  // --------------------------------------------------------------------------
  // [Construction / Destruction]
  // --------------------------------------------------------------------------

  //! Create a new `FileLogger` that logs to a `FILE` stream.
  ASMJIT_API FileLogger(FILE* stream = nullptr) noexcept;
  //! Destroy the `FileLogger`.
  ASMJIT_API virtual ~FileLogger() noexcept;

  // --------------------------------------------------------------------------
  // [Accessors]
  // --------------------------------------------------------------------------

  //! Get the logging out put stream or null.
  ASMJIT_INLINE FILE* getStream() const noexcept { return _stream; }

  //! Set the logging output stream to `stream` or null.
  //!
  //! NOTE: If the `stream` is null it will disable logging, but it won't
  //! stop calling `log()` unless the logger is detached from the
  //! \ref Assembler.
  ASMJIT_INLINE void setStream(FILE* stream) noexcept { _stream = stream; }

  // --------------------------------------------------------------------------
  // [Logging]
  // --------------------------------------------------------------------------

  ASMJIT_API Error _log(const char* buf, size_t len = Globals::kInvalidIndex) noexcept override;

  // --------------------------------------------------------------------------
  // [Members]
  // --------------------------------------------------------------------------

  //! C file stream.
  FILE* _stream;
};

// ============================================================================
// [asmjit::StringLogger]
// ============================================================================

//! Logger that stores everything in an internal string buffer.
class ASMJIT_VIRTAPI StringLogger : public Logger {
public:
  ASMJIT_NONCOPYABLE(StringLogger)

  // --------------------------------------------------------------------------
  // [Construction / Destruction]
  // --------------------------------------------------------------------------

  //! Create new `StringLogger`.
  ASMJIT_API StringLogger() noexcept;
  //! Destroy the `StringLogger`.
  ASMJIT_API virtual ~StringLogger() noexcept;

  // --------------------------------------------------------------------------
  // [Accessors]
  // --------------------------------------------------------------------------

  //! Get `char*` pointer which represents the resulting string.
  //!
  //! The pointer is owned by `StringLogger`, it can't be modified or freed.
  ASMJIT_INLINE const char* getString() const noexcept { return _stringBuilder.getData(); }
  //! Clear the resulting string.
  ASMJIT_INLINE void clearString() noexcept { _stringBuilder.clear(); }

  //! Get the length of the string returned by `getString()`.
  ASMJIT_INLINE size_t getLength() const noexcept { return _stringBuilder.getLength(); }

  // --------------------------------------------------------------------------
  // [Logging]
  // --------------------------------------------------------------------------

  ASMJIT_API Error _log(const char* buf, size_t len = Globals::kInvalidIndex) noexcept override;

  // --------------------------------------------------------------------------
  // [Members]
  // --------------------------------------------------------------------------

  //! Output string.
  StringBuilder _stringBuilder;
};

// ============================================================================
// [asmjit::Logging]
// ============================================================================

struct Logging {
  ASMJIT_API static Error formatRegister(
    StringBuilder& sb,
    uint32_t logOptions,
    const CodeEmitter* emitter,
    uint32_t archType,
    uint32_t regType,
    uint32_t regId) noexcept;

  ASMJIT_API static Error formatLabel(
    StringBuilder& sb,
    uint32_t logOptions,
    const CodeEmitter* emitter,
    uint32_t labelId) noexcept;

  ASMJIT_API static Error formatOperand(
    StringBuilder& sb,
    uint32_t logOptions,
    const CodeEmitter* emitter,
    uint32_t archType,
    const Operand_& op) noexcept;

  ASMJIT_API static Error formatInstruction(
    StringBuilder& sb,
    uint32_t logOptions,
    const CodeEmitter* emitter,
    uint32_t archType,
    const Inst::Detail& detail, const Operand_* opArray, uint32_t opCount) noexcept;

#if !defined(ASMJIT_DISABLE_BUILDER)
  ASMJIT_API static Error formatNode(
    StringBuilder& sb,
    uint32_t logOptions,
    const CodeBuilder* cb,
    const CBNode* node_) noexcept;
#endif // !ASMJIT_DISABLE_BUILDER

// Only used by AsmJit internals, not available to users.
#if defined(ASMJIT_EXPORTS)
  enum {
    // Has to be big to be able to hold all metadata compiler can assign to a
    // single instruction.
    kMaxCommentLength = 512,
    kMaxInstLength = 40,
    kMaxBinaryLength = 26
  };

  static Error formatLine(
    StringBuilder& sb,
    const uint8_t* binData, size_t binLen, size_t dispLen, size_t imLen, const char* comment) noexcept;
#endif // ASMJIT_EXPORTS
};
#else
class Logger;
#endif // !ASMJIT_DISABLE_LOGGING

//! \}

} // asmjit namespace

// [Api-End]
#include "../asmjit_apiend.h"

// [Guard]
#endif // _ASMJIT_BASE_LOGGER_H