• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Alan-Jowett / libbtf / 28060332906

31 Mar 2026 06:26PM UTC coverage: 92.773% (-2.3%) from 95.029%
28060332906

push

github

web-flow
Merge pull request #194 from Alan-Jowett/dependabot/github_actions/actions-f78bc712d6

Bump the actions group with 3 updates

2285 of 2463 relevant lines covered (92.77%)

768.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.2
/libbtf/btf_json.cpp
1
// Copyright (c) Prevail Verifier contributors.
2
// SPDX-License-Identifier: MIT
3

4
#include "btf_json.h"
5

6
#include "btf_c_type.h"
7
#include "cycle_detector.h"
8

9
#include <functional>
10
#include <set>
11

12
namespace libbtf {
13
std::string pretty_print_json(const std::string &input) {
45✔
14
  // Walk over the input string, inserting newlines and indentation.
15
  std::string output;
45✔
16
  int indent = 0;
45✔
17
  bool in_string = false;
45✔
18
  for (size_t i = 0; i < input.size(); i++) {
141,084✔
19
    char c = input[i];
141,039✔
20
    if (c == '"') {
141,039✔
21
      in_string = !in_string;
19,950✔
22
    }
23
    if (in_string) {
141,039✔
24
      output += c;
103,347✔
25
      continue;
103,347✔
26
    }
27
    switch (c) {
37,692✔
28
    case '{':
1,721✔
29
    case '[':
30
      output += c;
1,721✔
31
      if (i + 1 < input.size() && input[i + 1] != '}' && input[i + 1] != ']') {
1,721✔
32
        output += '\n';
1,721✔
33
        indent += 2;
1,721✔
34
        output += std::string(indent, ' ');
1,721✔
35
      } else {
36
        output += input[++i];
×
37
      }
38
      break;
1,721✔
39
    case '}':
1,721✔
40
    case ']':
41
      output += '\n';
1,721✔
42
      indent -= 2;
1,721✔
43
      output += std::string(indent, ' ');
1,721✔
44
      output += c;
1,721✔
45
      break;
1,721✔
46
    case ',':
6,384✔
47
      output += c;
6,384✔
48
      output += '\n';
6,384✔
49
      output += std::string(indent, ' ');
6,384✔
50
      break;
6,384✔
51
    case ':':
7,662✔
52
      output += c;
7,662✔
53
      output += ' ';
7,662✔
54
      break;
7,662✔
55
    default:
20,204✔
56
      output += c;
20,204✔
57
      break;
20,204✔
58
    }
59
  }
60
  return output;
45✔
61
}
×
62

63
template <typename T>
64
static void _print_json_value(bool &first, const std::string &name, T value,
6,570✔
65
                              std::ostream &out) {
66
  // If T is a string type, print it as a string, then quote the value.
67
  if constexpr (std::is_same_v<T, std::string> ||
68
                std::is_same_v<T, const char *> || std::is_same_v<T, char *>) {
69
    out << (first ? "" : ",") << "\"" << name << "\":\"" << value << "\"";
2,048✔
70
    first = false;
2,048✔
71
  }
72
  // If T is a bool, print it as a string, then quote the value.
73
  else if constexpr (std::is_same_v<T, bool>) {
74
    out << (first ? "" : ",") << "\"" << name
75
        << "\":" << (value ? "true" : "false");
1,252✔
76
    first = false;
1,252✔
77
  }
78
  // If T is a std::optional<std::string>, then only print if it's present
79
  else if constexpr (std::is_same_v<T, std::optional<std::string>>) {
80
    if (value.has_value()) {
349✔
81
      out << (first ? "" : ",") << "\"" << name << "\":\"" << value.value()
612✔
82
          << "\"";
306✔
83
      first = false;
306✔
84
    }
85
  } else {
86
    out << (first ? "" : ",") << "\"" << name << "\":" << std::to_string(value);
2,921✔
87
    first = false;
2,921✔
88
  }
89
}
6,570✔
90

91
void print_array_start(const std::string &name, std::ostream &out) {
185✔
92
  out << "\"" << name << "\":[";
185✔
93
}
185✔
94

95
void print_array_end(std::ostream &out) { out << "]"; }
185✔
96

97
#define PRINT_JSON_FIXED(name, value)                                          \
98
  _print_json_value(first, name, value, out);
99

100
#define PRINT_JSON_VALUE(object, value)                                        \
101
  _print_json_value(first, #value, object.value, out)
102

103
#define PRINT_JSON_TYPE(object, value)                                         \
104
  if (!first) {                                                                \
105
    out << ",";                                                                \
106
  } else {                                                                     \
107
    first = false;                                                             \
108
  };                                                                           \
109
  out << "\"" << #value << "\":";                                              \
110
  print_btf_kind(object.value, id_to_kind.at(object.value));
111

112
#define PRINT_JSON_ARRAY_START(object, value)                                  \
113
  if (!first) {                                                                \
114
    out << ",";                                                                \
115
  } else {                                                                     \
116
    first = false;                                                             \
117
  }                                                                            \
118
  print_array_start(#value, out);                                              \
119
  {                                                                            \
120
    bool first = true;
121

122
#define PRINT_JSON_ARRAY_END()                                                 \
123
  print_array_end(out);                                                        \
124
  }
125

126
#define PRINT_JSON_OBJECT_START()                                              \
127
  if (!first) {                                                                \
128
    out << ",";                                                                \
129
  } else {                                                                     \
130
    first = false;                                                             \
131
  };                                                                           \
132
  {                                                                            \
133
    bool first = true;                                                         \
134
    out << "{";
135

136
#define PRINT_JSON_OBJECT_END()                                                \
137
  out << "}";                                                                  \
138
  }
139

140
#define PRINT_JSON_VALUE_IF_PRESENT(object, value)                             \
141
  if constexpr (btf_kind_traits<decltype(object)>::has_##value) {              \
142
    PRINT_JSON_VALUE(object, value);                                           \
143
  }
144

145
#define PRINT_JSON_TYPE_IF_PRESENT(object, value)                              \
146
  if constexpr (btf_kind_traits<decltype(object)>::has_##value) {              \
147
    PRINT_JSON_TYPE(object, value);                                            \
148
  }
149

150
// Suppress C4456 on when using MSVC:
151
// declaration of 'first' hides previous local declaration
152
#pragma warning(push)
153
#pragma warning(disable : 4456)
154
#pragma warning(disable : 4458)
155

156
void btf_type_to_json(const std::map<btf_type_id, btf_kind> &id_to_kind,
54✔
157
                      std::ostream &out,
158
                      std::optional<std::function<bool(btf_type_id)>> filter) {
159
  cycle_detector detector; // Track cycles using cycle_detector
54✔
160
  using scoped_visit = libbtf::scoped_visit;
161

162
  std::function<void(btf_type_id, const btf_kind &)> print_btf_kind =
163
      [&](btf_type_id id, const btf_kind &kind) {
1,158✔
164
        // Use scoped_visit for automatic cycle detection and cleanup
165
        scoped_visit visit(detector, id, std::nothrow);
1,158✔
166

167
        // Check for cycles using scoped_visit
168
        if (!visit.is_marked()) {
1,158✔
169
          // We're in a cycle - print just a reference
170
          bool first = true;
×
171
          PRINT_JSON_OBJECT_START();
×
172
          PRINT_JSON_FIXED("id", id);
×
173
          PRINT_JSON_FIXED("kind_type", "reference");
×
174
          PRINT_JSON_OBJECT_END();
×
175
          return;
×
176
        }
177

178
        // No cycle detected, proceed with normal printing
179
        // The scoped_visit will automatically unmark when it goes out of scope
180

181
        bool first = true;
1,158✔
182
        PRINT_JSON_OBJECT_START();
1,158✔
183
        PRINT_JSON_FIXED("id", id);
1,158✔
184
        PRINT_JSON_FIXED("kind_type",
1,158✔
185
                         BTF_KIND_INDEX_TO_STRING(
186
                             static_cast<btf_kind_index>(kind.index())));
187

188
        std::visit(
1,158✔
189
            [&](auto &kind) {
1,158✔
190
              // Print JSON values.
191
              PRINT_JSON_VALUE_IF_PRESENT(kind, name);
2,618✔
192
              if constexpr (btf_kind_traits<decltype(kind)>::has_linkage) {
193
                PRINT_JSON_FIXED("linkage",
74✔
194
                                 BTF_KIND_LINKAGE_TO_STRING(kind.linkage));
195
              }
196
              PRINT_JSON_VALUE_IF_PRESENT(kind, count_of_elements);
84✔
197
              PRINT_JSON_VALUE_IF_PRESENT(kind, size_in_bytes);
472✔
198
              PRINT_JSON_VALUE_IF_PRESENT(kind, size);
26✔
199
              PRINT_JSON_VALUE_IF_PRESENT(kind, is_struct);
20✔
200
              PRINT_JSON_VALUE_IF_PRESENT(kind, offset_from_start_in_bits);
409✔
201
              PRINT_JSON_VALUE_IF_PRESENT(kind, field_width_in_bits);
409✔
202
              PRINT_JSON_VALUE_IF_PRESENT(kind, is_signed);
414✔
203
              PRINT_JSON_VALUE_IF_PRESENT(kind, is_char);
409✔
204
              PRINT_JSON_VALUE_IF_PRESENT(kind, is_bool);
409✔
205

206
              // Print JSON arrays.
207
              if constexpr (btf_kind_traits<decltype(kind)>::has_members) {
208
                PRINT_JSON_ARRAY_START(kind, members);
87✔
209
                for (auto &member : kind.members) {
420✔
210
                  PRINT_JSON_OBJECT_START();
333✔
211
                  PRINT_JSON_VALUE_IF_PRESENT(member, name);
303✔
212
                  PRINT_JSON_VALUE_IF_PRESENT(member, value);
15✔
213
                  PRINT_JSON_VALUE_IF_PRESENT(member,
288✔
214
                                              offset_from_start_in_bits);
215
                  PRINT_JSON_VALUE_IF_PRESENT(member, offset);
30✔
216
                  PRINT_JSON_VALUE_IF_PRESENT(member, size);
30✔
217
                  PRINT_JSON_TYPE_IF_PRESENT(member, type);
1,074✔
218
                  PRINT_JSON_OBJECT_END();
333✔
219
                }
220
                PRINT_JSON_ARRAY_END();
87✔
221
              }
222

223
              if constexpr (btf_kind_traits<decltype(kind)>::has_parameters) {
224
                PRINT_JSON_ARRAY_START(kind, parameters);
44✔
225
                for (auto &parameter : kind.parameters) {
88✔
226
                  PRINT_JSON_OBJECT_START();
44✔
227
                  PRINT_JSON_VALUE_IF_PRESENT(parameter, name);
44✔
228
                  PRINT_JSON_TYPE_IF_PRESENT(parameter, type);
44✔
229
                  PRINT_JSON_OBJECT_END();
44✔
230
                }
231
                PRINT_JSON_ARRAY_END();
44✔
232
              }
233

234
              // Print JSON child object.
235
              PRINT_JSON_TYPE_IF_PRESENT(kind, type);
500✔
236
              PRINT_JSON_TYPE_IF_PRESENT(kind, element_type);
84✔
237
              PRINT_JSON_TYPE_IF_PRESENT(kind, index_type);
84✔
238
              PRINT_JSON_TYPE_IF_PRESENT(kind, return_type);
44✔
239
            },
1,158✔
240
            kind);
241
        PRINT_JSON_OBJECT_END();
1,158✔
242

243
        // scoped_visit automatically unmarks when it goes out of scope
244
      };
1,212✔
245

246
  // Determine the list of types that are not referenced by other types. These
247
  // are the root types.
248
  std::set<btf_type_id> root_types;
54✔
249

250
  // Add all types as root types.
251
  for (auto &[id, kind] : id_to_kind) {
738✔
252
    root_types.insert(id);
684✔
253
  }
254

255
  // Erase the VOID type.
256
  root_types.erase(0);
54✔
257

258
  // Remove all types that are referenced by other types.
259
  for (auto &[id, kind] : id_to_kind) {
738✔
260
    if (filter.has_value()) {
684✔
261
      if (!(*filter)(id)) {
×
262
        root_types.erase(id);
×
263
      }
264
      continue;
×
265
    }
266

267
    std::visit(
684✔
268
        [&](const auto &kind) {
684✔
269
          if constexpr (btf_kind_traits<decltype(kind)>::has_type) {
270
            root_types.erase(kind.type);
816✔
271
          }
272
          if constexpr (btf_kind_traits<decltype(kind)>::has_element_type) {
273
            root_types.erase(kind.element_type);
68✔
274
          }
275
          if constexpr (btf_kind_traits<decltype(kind)>::has_index_type) {
276
            root_types.erase(kind.index_type);
68✔
277
          }
278
          if constexpr (btf_kind_traits<decltype(kind)>::has_members) {
279
            for (auto &member : kind.members) {
382✔
280
              if constexpr (btf_kind_traits<decltype(member)>::has_type) {
281
                root_types.erase(member.type);
286✔
282
              }
283
            }
284
          }
285
          if constexpr (btf_kind_traits<decltype(kind)>::has_parameters) {
286
            for (auto &parameter : kind.parameters) {
88✔
287
              root_types.erase(parameter.type);
44✔
288
            }
289
          }
290
          if constexpr (btf_kind_traits<decltype(kind)>::has_return_type) {
291
            root_types.erase(kind.return_type);
44✔
292
          }
293
        },
684✔
294
        kind);
295
  }
296
  bool first = true;
54✔
297
  PRINT_JSON_OBJECT_START();
54✔
298
  PRINT_JSON_ARRAY_START("", btf_kinds);
54✔
299
  for (const auto &[id, kind] : id_to_kind) {
738✔
300
    // Skip non-root types.
301
    if (root_types.find(id) == root_types.end()) {
684✔
302
      continue;
600✔
303
    }
304

305
    out << (first ? "" : ",");
84✔
306
    first = false;
84✔
307
    print_btf_kind(id, kind);
84✔
308
  }
309
  PRINT_JSON_ARRAY_END();
54✔
310
  PRINT_JSON_OBJECT_END();
54✔
311
}
54✔
312

313
#pragma warning(pop)
314

315
} // namespace libbtf
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc