1// Copyright 2017 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <mini-process/mini-process.h>
6#include <unittest/unittest.h>
7#include <zircon/process.h>
8#include <zircon/status.h>
9#include <zircon/syscalls.h>
10#include <zircon/syscalls/exception.h>
11#include <zircon/syscalls/object.h>
12
13#include <inttypes.h>
14#include <limits.h>
15#include <stdio.h>
16#include <stdlib.h>
17
18#include <fbl/algorithm.h>
19
20#define LOCAL_TRACE 0
21#define LTRACEF(str, x...)                                  \
22    do {                                                    \
23        if (LOCAL_TRACE) {                                  \
24            printf("%s:%d: " str, __func__, __LINE__, ##x); \
25        }                                                   \
26    } while (0)
27
28namespace {
29
30// A function that returns a handle to get the info of.
31// Typically get_test_process, get_test_job, zx_process_self, zx_job_default.
32typedef zx_handle_t (*handle_source_fn)();
33
34bool handle_valid_on_valid_handle_succeeds() {
35    BEGIN_TEST;
36    EXPECT_EQ(zx_object_get_info(zx_process_self(), ZX_INFO_HANDLE_VALID,
37                                 nullptr, 0, nullptr, nullptr),
38              ZX_OK);
39    END_TEST;
40}
41
42bool handle_valid_on_closed_handle_fails() {
43    BEGIN_TEST;
44    // Create an event and show that it's valid.
45    zx_handle_t event;
46    ASSERT_EQ(zx_event_create(0u, &event), ZX_OK);
47    EXPECT_EQ(zx_object_get_info(event, ZX_INFO_HANDLE_VALID,
48                                 nullptr, 0, nullptr, nullptr),
49              ZX_OK);
50
51    // Close the handle and show that it becomes invalid.
52    zx_handle_close(event);
53    EXPECT_NE(zx_object_get_info(event, ZX_INFO_HANDLE_VALID,
54                                 nullptr, 0, nullptr, nullptr),
55              ZX_OK);
56    END_TEST;
57}
58
59// Tests that ZX_INFO_TASK_STATS seems to work.
60bool task_stats_smoke() {
61    BEGIN_TEST;
62    zx_info_task_stats_t info;
63    ASSERT_EQ(zx_object_get_info(zx_process_self(), ZX_INFO_TASK_STATS,
64                                 &info, sizeof(info), nullptr, nullptr),
65              ZX_OK);
66    ASSERT_GT(info.mem_private_bytes, 0u);
67    ASSERT_GT(info.mem_shared_bytes, 0u);
68    ASSERT_GE(info.mem_mapped_bytes,
69              info.mem_private_bytes + info.mem_shared_bytes);
70
71    ASSERT_GT(info.mem_scaled_shared_bytes, 0u);
72    ASSERT_GT(info.mem_shared_bytes, info.mem_scaled_shared_bytes);
73    END_TEST;
74}
75
76// Structs to keep track of VMARs/mappings in the test child process.
77typedef struct test_mapping {
78    uintptr_t base;
79    size_t size;
80    uint32_t flags; // ZX_INFO_MAPS_MMU_FLAG_PERM_{READ,WRITE,EXECUTE}
81} test_mapping_t;
82
83// A VMO that the test process maps or has a handle to.
84typedef struct test_vmo {
85    zx_koid_t koid;
86    size_t size;
87    uint32_t flags; // ZX_INFO_VMO_VIA_{HANDLE,MAPPING}
88} test_vmo_t;
89
90typedef struct test_mapping_info {
91    uintptr_t vmar_base;
92    size_t vmar_size;
93    size_t num_mappings;
94    test_mapping_t* mappings; // num_mappings entries
95    size_t num_vmos;
96    test_vmo_t* vmos; // num_vmos entries
97} test_mapping_info_t;
98
99// Gets the koid of the object pointed to by |handle|.
100zx_status_t get_koid(zx_handle_t handle, zx_koid_t* koid) {
101    zx_info_handle_basic_t info;
102    zx_status_t s = zx_object_get_info(handle, ZX_INFO_HANDLE_BASIC,
103                                       &info, sizeof(info), nullptr, nullptr);
104    if (s == ZX_OK) {
105        *koid = info.koid;
106    }
107    return s;
108}
109
110// Returns a process singleton. ZX_INFO_PROCESS_MAPS can't run on the current
111// process, so tests should use this instead.
112// This handle is leaked, and we expect our process teardown to clean it up
113// naturally.
114zx_handle_t get_test_process_etc(const test_mapping_info_t** info) {
115    static zx_handle_t test_process = ZX_HANDLE_INVALID;
116    static test_mapping_info_t* test_info = nullptr;
117
118    if (info != nullptr) {
119        *info = nullptr;
120    }
121    if (test_process == ZX_HANDLE_INVALID) {
122        // Create a VMO whose handle we'll give to the test process.
123        // It will not be mapped into the test process's VMAR.
124        const size_t unmapped_vmo_size = PAGE_SIZE;
125        zx_handle_t unmapped_vmo;
126        zx_status_t s = zx_vmo_create(
127            unmapped_vmo_size, /* options */ 0u, &unmapped_vmo);
128        if (s != ZX_OK) {
129            EXPECT_EQ(s, ZX_OK, "zx_vmo_create"); // Poison the test.
130            return ZX_HANDLE_INVALID;
131        }
132        zx_koid_t unmapped_vmo_koid;
133        s = get_koid(unmapped_vmo, &unmapped_vmo_koid);
134        if (s != ZX_OK) {
135            EXPECT_EQ(s, ZX_OK, "get_koid");
136            return ZX_HANDLE_INVALID;
137        }
138        // Try to set the name, but ignore any errors.
139        static const char unmapped_vmo_name[] = "test:unmapped";
140        zx_object_set_property(unmapped_vmo, ZX_PROP_NAME,
141                               unmapped_vmo_name, sizeof(unmapped_vmo_name));
142
143        // Failures from here on will start to leak handles, but they'll
144        // be cleaned up when this binary exits.
145
146        zx_handle_t process;
147        zx_handle_t vmar;
148        static const char pname[] = "object-info-minipr";
149        s = zx_process_create(zx_job_default(), pname, sizeof(pname),
150                              /* options */ 0u, &process, &vmar);
151        if (s != ZX_OK) {
152            EXPECT_EQ(s, ZX_OK, "zx_process_create");
153            return ZX_HANDLE_INVALID;
154        }
155
156        zx_handle_t thread;
157        static const char tname[] = "object-info-minith";
158        s = zx_thread_create(process, tname, sizeof(tname),
159                             /* options */ 0u, &thread);
160        if (s != ZX_OK) {
161            EXPECT_EQ(s, ZX_OK, "zx_thread_create");
162            return ZX_HANDLE_INVALID;
163        }
164
165        zx_handle_t minip_channel;
166        // Start the process before we mess with the VMAR,
167        // so we don't step on the mapping done by start_mini_process_etc.
168        s = start_mini_process_etc(process, thread, vmar, unmapped_vmo,
169                                   &minip_channel);
170        if (s != ZX_OK) {
171            EXPECT_EQ(s, ZX_OK, "start_mini_process_etc");
172            return ZX_HANDLE_INVALID;
173        }
174        unmapped_vmo = ZX_HANDLE_INVALID; // Transferred to the test process.
175        zx_handle_close(minip_channel);
176
177        // Create a child VMAR and a mapping under it, so we have
178        // something interesting to look at when getting the process's
179        // memory maps. After this, the process maps should at least contain:
180        //
181        //   Root Aspace
182        //   - Root VMAR
183        //     - Code+stack mapping created by start_mini_process_etc
184        //     - Sub VMAR created below
185        //       - kNumMappings mappings created below
186
187        static const size_t kNumMappings = 8;
188        // Leaked on failure. Never freed on success.
189        test_mapping_info_t* ti = (test_mapping_info_t*)malloc(sizeof(*ti));
190        ti->num_mappings = kNumMappings;
191        ti->mappings =
192            (test_mapping_t*)malloc(kNumMappings * sizeof(test_mapping_t));
193
194        // Big enough to fit all of the mappings with some slop.
195        ti->vmar_size = PAGE_SIZE * kNumMappings * 16;
196        zx_handle_t sub_vmar;
197        s = zx_vmar_allocate(vmar,
198                             ZX_VM_CAN_MAP_READ |
199                                 ZX_VM_CAN_MAP_WRITE |
200                                 ZX_VM_CAN_MAP_EXECUTE,
201                             /* offset */ 0,
202                             ti->vmar_size,
203                             &sub_vmar, &ti->vmar_base);
204        if (s != ZX_OK) {
205            EXPECT_EQ(s, ZX_OK, "zx_vmar_allocate");
206            return ZX_HANDLE_INVALID;
207        }
208
209        zx_handle_t vmo;
210        const size_t vmo_size = PAGE_SIZE * kNumMappings;
211        s = zx_vmo_create(vmo_size, /* options */ 0u, &vmo);
212        if (s != ZX_OK) {
213            EXPECT_EQ(s, ZX_OK, "zx_vmo_create");
214            return ZX_HANDLE_INVALID;
215        }
216        zx_koid_t vmo_koid;
217        s = get_koid(vmo, &vmo_koid);
218        if (s != ZX_OK) {
219            EXPECT_EQ(s, ZX_OK, "get_koid");
220            return ZX_HANDLE_INVALID;
221        }
222        // Try to set the name, but ignore any errors.
223        static const char vmo_name[] = "test:mapped";
224        zx_object_set_property(vmo, ZX_PROP_NAME, vmo_name, sizeof(vmo_name));
225
226        // Record the VMOs now that we have both of them.
227        ti->num_vmos = 2;
228        ti->vmos = (test_vmo_t*)malloc(2 * sizeof(test_vmo_t));
229        ti->vmos[0].koid = unmapped_vmo_koid;
230        ti->vmos[0].size = unmapped_vmo_size;
231        ti->vmos[0].flags = ZX_INFO_VMO_VIA_HANDLE;
232        ti->vmos[1].koid = vmo_koid;
233        ti->vmos[1].size = vmo_size;
234        ti->vmos[1].flags = ZX_INFO_VMO_VIA_MAPPING;
235
236        // Map each page of the VMO to some arbitray location in the VMAR.
237        for (size_t i = 0; i < kNumMappings; i++) {
238            test_mapping_t* m = &ti->mappings[i];
239            m->size = PAGE_SIZE;
240
241            // Pick flags for this mapping; cycle through different
242            // combinations for the test. Must always have READ set
243            // to be mapped.
244            m->flags = ZX_VM_PERM_READ;
245            if (i & 1) {
246                m->flags |= ZX_VM_PERM_WRITE;
247            }
248            if (i & 2) {
249                m->flags |= ZX_VM_PERM_EXECUTE;
250            }
251
252            s = zx_vmar_map(sub_vmar, m->flags, /* vmar_offset (ignored) */ 0,
253                            vmo, /* vmo_offset */ i * PAGE_SIZE,
254                            /* len */ PAGE_SIZE,
255                            &m->base);
256            if (s != ZX_OK) {
257                char msg[32];
258                snprintf(msg, sizeof(msg), "zx_vmar_map: [%zd]", i);
259                EXPECT_EQ(s, ZX_OK, msg);
260                return ZX_HANDLE_INVALID;
261            }
262        }
263        zx_handle_close(vmo);      // Kept alive by the VMAR.
264        zx_handle_close(sub_vmar); // Kept alive by the process.
265
266        test_process = process;
267        test_info = ti;
268    }
269    if (info != nullptr) {
270        *info = test_info;
271    }
272    return test_process;
273}
274
275zx_handle_t get_test_process() {
276    return get_test_process_etc(nullptr);
277}
278
279// Tests that ZX_INFO_PROCESS_MAPS seems to work.
280bool process_maps_smoke() {
281    BEGIN_TEST;
282    const test_mapping_info_t* test_info;
283    const zx_handle_t process = get_test_process_etc(&test_info);
284    ASSERT_NONNULL(test_info, "get_test_process_etc");
285
286    // Buffer big enough to read all of the test process's map entries.
287    const size_t bufsize = test_info->num_mappings * 4 * sizeof(zx_info_maps_t);
288    zx_info_maps_t* maps = (zx_info_maps_t*)malloc(bufsize);
289
290    // Read the map entries.
291    size_t actual;
292    size_t avail;
293    ASSERT_EQ(zx_object_get_info(process, ZX_INFO_PROCESS_MAPS,
294                                 maps, bufsize,
295                                 &actual, &avail),
296              ZX_OK);
297    EXPECT_EQ(actual, avail, "Should have read all entries");
298
299    // The first two entries should always be the ASpace and root VMAR.
300    ASSERT_GE(actual, 2u, "Root aspace/vmar missing?");
301    EXPECT_EQ(maps[0].type, (uint32_t)ZX_INFO_MAPS_TYPE_ASPACE);
302    EXPECT_EQ(maps[0].depth, 0u, "ASpace depth");
303    EXPECT_GT(maps[0].size, 1u * 1024 * 1024 * 1024 * 1024, "ASpace size");
304    EXPECT_EQ(maps[1].type, (uint32_t)ZX_INFO_MAPS_TYPE_VMAR);
305    EXPECT_EQ(maps[1].depth, 1u, "Root VMAR depth");
306    EXPECT_GT(maps[1].size, 1u * 1024 * 1024 * 1024 * 1024, "Root VMAR size");
307
308    // Look for the VMAR and all of the mappings we created.
309    bool saw_vmar = false;   // Whether we've seen our VMAR.
310    bool under_vmar = false; // If we're looking at children of our VMAR.
311    size_t vmar_depth = 0;
312    uint32_t saw_mapping = 0u; // bitmask of mapping indices we've seen.
313    ASSERT_LT(test_info->num_mappings, 32u);
314
315    LTRACEF("\n");
316    for (size_t i = 2; i < actual; i++) {
317        zx_info_maps_t* entry = maps + i;
318        char msg[128];
319        snprintf(msg, sizeof(msg),
320                 "[%2zd] %*stype:%u base:0x%" PRIx64 " size:%" PRIu64,
321                 i, (int)(entry->depth - 2) * 2, "",
322                 entry->type, entry->base, entry->size);
323        LTRACEF("%s\n", msg);
324        // All entries should be children of the root VMAR.
325        EXPECT_GT(entry->depth, 1u, msg);
326        EXPECT_TRUE(entry->type >= ZX_INFO_MAPS_TYPE_ASPACE &&
327                        entry->type <= ZX_INFO_MAPS_TYPE_MAPPING,
328                    msg);
329
330        if (entry->type == ZX_INFO_MAPS_TYPE_VMAR &&
331            entry->base == test_info->vmar_base &&
332            entry->size == test_info->vmar_size) {
333            saw_vmar = true;
334            under_vmar = true;
335            vmar_depth = entry->depth;
336        } else if (under_vmar) {
337            if (entry->depth <= vmar_depth) {
338                under_vmar = false;
339                vmar_depth = 0;
340            } else {
341                // |entry| should be a child mapping of our VMAR.
342                EXPECT_EQ((uint32_t)ZX_INFO_MAPS_TYPE_MAPPING, entry->type,
343                          msg);
344                // The mapping should fit inside the VMAR.
345                EXPECT_LE(test_info->vmar_base, entry->base, msg);
346                EXPECT_LE(entry->base + entry->size,
347                          test_info->vmar_base + test_info->vmar_size,
348                          msg);
349                // Look for it in the expected mappings.
350                bool found = false;
351                for (size_t j = 0; j < test_info->num_mappings; j++) {
352                    const test_mapping_t* t = &test_info->mappings[j];
353                    if (t->base == entry->base && t->size == entry->size) {
354                        // Make sure we don't see duplicates.
355                        EXPECT_EQ(0u, saw_mapping & (1 << j), msg);
356                        saw_mapping |= 1 << j;
357                        EXPECT_EQ(t->flags, entry->u.mapping.mmu_flags, msg);
358                        found = true;
359                        break;
360                    }
361                }
362                EXPECT_TRUE(found, msg);
363            }
364        }
365    }
366
367    // Make sure we saw our VMAR and all of our mappings.
368    EXPECT_TRUE(saw_vmar);
369    EXPECT_EQ((uint32_t)(1 << test_info->num_mappings) - 1, saw_mapping);
370
371    // Do one more read with a short buffer to test actual < avail.
372    const size_t bufsize2 = actual * 3 / 4 * sizeof(zx_info_maps_t);
373    zx_info_maps_t* maps2 = (zx_info_maps_t*)malloc(bufsize2);
374    size_t actual2;
375    size_t avail2;
376    ASSERT_EQ(zx_object_get_info(process, ZX_INFO_PROCESS_MAPS,
377                                 maps2, bufsize2,
378                                 &actual2, &avail2),
379              ZX_OK);
380    EXPECT_LT(actual2, avail2);
381    // mini-process is very simple, and won't have modified its own memory
382    // maps since the previous dump. Its "committed_pages" values could be
383    // different, though.
384    EXPECT_EQ(avail, avail2);
385    LTRACEF("\n");
386    EXPECT_GT(actual2, 3u); // Make sure we're looking at something.
387    for (size_t i = 0; i < actual2; i++) {
388        zx_info_maps_t* e1 = maps + i;
389        zx_info_maps_t* e2 = maps2 + i;
390        char msg[128];
391        snprintf(msg, sizeof(msg),
392                 "[%2zd] %*stype:%u/%u base:0x%" PRIx64 "/0x%" PRIx64
393                 " size:%" PRIu64 "/%" PRIu64,
394                 i, (int)e1->depth * 2, "",
395                 e1->type, e2->type, e1->base, e2->base, e1->size, e2->size);
396        LTRACEF("%s\n", msg);
397        EXPECT_EQ(e1->base, e2->base, msg);
398        EXPECT_EQ(e1->size, e2->size, msg);
399        EXPECT_EQ(e1->depth, e2->depth, msg);
400        EXPECT_EQ(e1->type, e2->type, msg);
401        if (e1->type == e2->type && e2->type == ZX_INFO_MAPS_TYPE_MAPPING) {
402            EXPECT_EQ(e1->u.mapping.mmu_flags, e2->u.mapping.mmu_flags, msg);
403        }
404    }
405
406    free(maps);
407    free(maps2);
408    END_TEST;
409}
410
411template <uint32_t Topic, typename EntryType>
412bool self_fails() {
413    BEGIN_TEST;
414    EntryType entries[2];
415    size_t actual;
416    size_t avail;
417    // It's illegal to look at your own entries, because the output buffer
418    // lives inside the address space that's being examined.
419    EXPECT_EQ(zx_object_get_info(zx_process_self(), Topic,
420                                 entries, sizeof(entries), &actual, &avail),
421              ZX_ERR_ACCESS_DENIED);
422    END_TEST;
423}
424
425template <uint32_t Topic, typename EntryType>
426bool invalid_handle_fails() {
427    BEGIN_TEST;
428    EntryType entries[2];
429    size_t actual;
430    size_t avail;
431    // Passing ZX_HANDLE_INVALID should fail.
432    EXPECT_EQ(zx_object_get_info(ZX_HANDLE_INVALID, Topic,
433                                 entries, sizeof(entries), &actual, &avail),
434              ZX_ERR_BAD_HANDLE);
435    END_TEST;
436}
437
438template <uint32_t Topic, typename EntryType, handle_source_fn GetWrongHandle>
439bool wrong_handle_type_fails() {
440    BEGIN_TEST;
441    EntryType entries[2];
442    size_t actual;
443    size_t avail;
444    // Passing a handle to an unsupported object type should fail.
445    EXPECT_NE(zx_object_get_info(GetWrongHandle(), Topic,
446                                 entries, sizeof(entries), &actual, &avail),
447              ZX_OK);
448    END_TEST;
449}
450
451template <uint32_t Topic, typename EntryType,
452          handle_source_fn GetHandle, zx_rights_t MissingRights>
453bool missing_rights_fails() {
454    BEGIN_TEST;
455    // Call should succeed with the default rights.
456    zx_handle_t obj = GetHandle();
457    EntryType entries[2];
458    size_t actual;
459    size_t avail;
460    EXPECT_EQ(zx_object_get_info(obj, Topic,
461                                 entries, sizeof(entries), &actual, &avail),
462              ZX_OK);
463
464    // Get the test object handle rights.
465    zx_info_handle_basic_t hi;
466    ASSERT_EQ(zx_object_get_info(obj, ZX_INFO_HANDLE_BASIC,
467                                 &hi, sizeof(hi), nullptr, nullptr),
468              ZX_OK);
469    char msg[32];
470    snprintf(msg, sizeof(msg), "rights 0x%" PRIx32, hi.rights);
471    EXPECT_EQ(hi.rights & MissingRights, MissingRights, msg);
472
473    // Create a handle without the important rights.
474    zx_handle_t handle;
475    ASSERT_EQ(zx_handle_duplicate(obj, hi.rights & ~MissingRights, &handle),
476              ZX_OK);
477
478    // Call should fail without these rights.
479    EXPECT_EQ(zx_object_get_info(handle, Topic,
480                                 entries, sizeof(entries), &actual, &avail),
481              ZX_ERR_ACCESS_DENIED);
482
483    zx_handle_close(handle);
484    END_TEST;
485}
486
487template <uint32_t Topic, typename EntryType, handle_source_fn GetHandle>
488bool single_zero_buffer_fails() {
489    BEGIN_TEST;
490    EntryType entry;
491    size_t actual;
492    size_t avail;
493    // Passing a zero-sized buffer to a topic that expects a single
494    // in/out entry should fail.
495    EXPECT_EQ(zx_object_get_info(GetHandle(), Topic,
496                                 &entry, // buffer
497                                 0,      // len
498                                 &actual, &avail),
499              ZX_ERR_BUFFER_TOO_SMALL);
500    EXPECT_EQ(0u, actual);
501    EXPECT_GT(avail, 0u);
502    END_TEST;
503}
504
505template <uint32_t Topic, handle_source_fn GetHandle>
506bool multi_zero_buffer_succeeds() {
507    BEGIN_TEST;
508    size_t actual;
509    size_t avail;
510    // Passing a zero-sized null buffer to a topic that can handle multiple
511    // in/out entries should succeed.
512    EXPECT_EQ(zx_object_get_info(GetHandle(), Topic,
513                                 nullptr, // buffer
514                                 0,       // len
515                                 &actual, &avail),
516              ZX_OK);
517    EXPECT_EQ(0u, actual);
518    EXPECT_GT(avail, 0u);
519    END_TEST;
520}
521
522template <uint32_t Topic, typename EntryType, handle_source_fn GetHandle>
523bool short_buffer_succeeds() {
524    BEGIN_TEST;
525    EntryType entries[1];
526    size_t actual;
527    size_t avail;
528    // Passing a buffer shorter than avail should succeed.
529    EXPECT_EQ(zx_object_get_info(GetHandle(), Topic,
530                                 entries,
531                                 sizeof(entries),
532                                 &actual, &avail),
533              ZX_OK);
534    EXPECT_EQ(1u, actual);
535    EXPECT_GT(avail, actual);
536    END_TEST;
537}
538
539template <uint32_t Topic, typename EntryType, handle_source_fn GetHandle>
540bool null_avail_actual_succeeds() {
541    BEGIN_TEST;
542    EntryType entries[2];
543    EXPECT_EQ(zx_object_get_info(GetHandle(), Topic,
544                                 entries, sizeof(entries),
545                                 nullptr,  // actual
546                                 nullptr), // avail
547              ZX_OK);
548    END_TEST;
549}
550
551template <uint32_t Topic, typename EntryType, handle_source_fn GetHandle>
552bool bad_buffer_fails() {
553    BEGIN_TEST;
554    size_t actual;
555    size_t avail;
556    EXPECT_EQ(zx_object_get_info(GetHandle(), Topic,
557                                 // Bad buffer pointer value.
558                                 (EntryType*)1,
559                                 sizeof(EntryType),
560                                 &actual, &avail),
561              ZX_ERR_INVALID_ARGS);
562    END_TEST;
563}
564
565// Tests the behavior when passing a buffer that starts in mapped
566// memory but crosses into unmapped memory.
567template <uint32_t Topic, typename EntryType, handle_source_fn GetHandle>
568bool partially_unmapped_buffer_fails() {
569    BEGIN_TEST;
570    // Create a two-page VMAR.
571    zx_handle_t vmar;
572    uintptr_t vmar_addr;
573    ASSERT_EQ(zx_vmar_allocate(zx_vmar_root_self(),
574                               ZX_VM_CAN_MAP_READ |
575                                   ZX_VM_CAN_MAP_WRITE |
576                                   ZX_VM_CAN_MAP_SPECIFIC,
577                               0, 2 * PAGE_SIZE,
578                               &vmar, &vmar_addr),
579              ZX_OK);
580
581    // Create a one-page VMO.
582    zx_handle_t vmo;
583    ASSERT_EQ(zx_vmo_create(PAGE_SIZE, 0, &vmo), ZX_OK);
584
585    // Map the first page of the VMAR.
586    uintptr_t vmo_addr;
587    ASSERT_EQ(zx_vmar_map(vmar,
588                          ZX_VM_SPECIFIC |
589                              ZX_VM_PERM_READ |
590                              ZX_VM_PERM_WRITE,
591                          0, vmo, 0, PAGE_SIZE, &vmo_addr),
592              ZX_OK);
593    ASSERT_EQ(vmar_addr, vmo_addr);
594
595    // Point to a spot in the mapped page just before the unmapped region:
596    // the first entry will hit mapped memory, the second entry will hit
597    // unmapped memory.
598    EntryType* entries = (EntryType*)(vmo_addr + PAGE_SIZE) - 1;
599
600    size_t actual;
601    size_t avail;
602    EXPECT_EQ(zx_object_get_info(GetHandle(), Topic,
603                                 entries, sizeof(EntryType) * 4,
604                                 &actual, &avail),
605              // Bad user buffer should return ZX_ERR_INVALID_ARGS.
606              ZX_ERR_INVALID_ARGS);
607
608    zx_vmar_destroy(vmar);
609    zx_handle_close(vmar);
610    zx_handle_close(vmo);
611    END_TEST;
612}
613
614template <uint32_t Topic, typename EntryType, handle_source_fn GetHandle>
615bool bad_actual_fails() {
616    BEGIN_TEST;
617    EntryType entries[2];
618    size_t avail;
619    EXPECT_EQ(zx_object_get_info(GetHandle(), Topic,
620                                 entries, sizeof(entries),
621                                 // Bad actual pointer value.
622                                 (size_t*)1,
623                                 &avail),
624              ZX_ERR_INVALID_ARGS);
625    END_TEST;
626}
627
628template <uint32_t Topic, typename EntryType, handle_source_fn GetHandle>
629bool bad_avail_fails() {
630    BEGIN_TEST;
631    EntryType entries[2];
632    size_t actual;
633    EXPECT_EQ(zx_object_get_info(GetHandle(), Topic,
634                                 entries, sizeof(entries), &actual,
635                                 // Bad available pointer value.
636                                 (size_t*)1),
637              ZX_ERR_INVALID_ARGS);
638    END_TEST;
639}
640
641// Tests that ZX_INFO_PROCESS_VMOS seems to work.
642bool process_vmos_smoke() {
643    BEGIN_TEST;
644    const test_mapping_info_t* test_info;
645    const zx_handle_t process = get_test_process_etc(&test_info);
646    ASSERT_NONNULL(test_info, "get_test_process_etc");
647
648    // Buffer big enough to read all of the test process's VMO entries.
649    // There'll be one per mapping, one for the unmapped VMO, plus some
650    // extras (at least the vDSO and the mini-process stack).
651    const size_t bufsize =
652        (test_info->num_mappings + 1 + 8) * sizeof(zx_info_vmo_t);
653    zx_info_vmo_t* vmos = (zx_info_vmo_t*)malloc(bufsize);
654
655    // Read the VMO entries.
656    size_t actual;
657    size_t avail;
658    ASSERT_EQ(zx_object_get_info(process, ZX_INFO_PROCESS_VMOS,
659                                 vmos, bufsize,
660                                 &actual, &avail),
661              ZX_OK);
662    EXPECT_EQ(actual, avail, "Should have read all entries");
663
664    // Look for the expected VMOs.
665    uint32_t saw_vmo = 0u; // Bitmask of VMO indices we've seen
666    ASSERT_LT(test_info->num_vmos, 32u);
667
668    LTRACEF("\n");
669    for (size_t i = 0; i < actual; i++) {
670        zx_info_vmo_t* entry = vmos + i;
671        char msg[128];
672        snprintf(msg, sizeof(msg),
673                 "[%2zd] koid:%" PRIu64 " name:'%s' size:%" PRIu64
674                 " flags:0x%" PRIx32,
675                 i, entry->koid, entry->name, entry->size_bytes, entry->flags);
676        LTRACEF("%s\n", msg);
677
678        // Look for it in the expected VMOs. We won't find all VMOs here,
679        // since we don't track the vDSO or mini-process stack.
680        for (size_t j = 0; j < test_info->num_vmos; j++) {
681            const test_vmo_t* t = &test_info->vmos[j];
682            if (t->koid == entry->koid && t->size == entry->size_bytes) {
683                // These checks aren't appropriate for all VMOs.
684                // The VMOs we track are:
685                // - Only mapped or via handle, not both
686                // - Not clones
687                // - Not shared
688                EXPECT_EQ(entry->parent_koid, 0u, msg);
689                EXPECT_EQ(entry->num_children, 0u, msg);
690                EXPECT_EQ(entry->share_count, 1u, msg);
691                EXPECT_EQ(t->flags & entry->flags, t->flags, msg);
692                if (entry->flags & ZX_INFO_VMO_VIA_HANDLE) {
693                    EXPECT_EQ(entry->num_mappings, 0u, msg);
694                } else {
695                    EXPECT_NE(entry->flags & ZX_INFO_VMO_VIA_MAPPING, 0u, msg);
696                    EXPECT_EQ(
697                        entry->num_mappings, test_info->num_mappings, msg);
698                }
699                EXPECT_EQ(entry->flags & ZX_INFO_VMO_IS_COW_CLONE, 0u, msg);
700
701                saw_vmo |= 1 << j; // Duplicates are fine and expected
702                break;
703            }
704        }
705
706        // All of our VMOs should be paged, not physical.
707        EXPECT_EQ(ZX_INFO_VMO_TYPE(entry->flags), ZX_INFO_VMO_TYPE_PAGED, msg);
708
709        // Each entry should be via either map or handle, but not both.
710        // NOTE: This could change in the future, but currently reflects
711        // the way things work.
712        const uint32_t kViaMask =
713            ZX_INFO_VMO_VIA_HANDLE | ZX_INFO_VMO_VIA_MAPPING;
714        EXPECT_NE(entry->flags & kViaMask, kViaMask, msg);
715
716        // TODO(dbort): Test more fields/flags of zx_info_vmo_t by adding some
717        // clones, shared VMOs, mapped+handle VMOs, physical VMOs if possible.
718        // All but committed_bytes should be predictable.
719    }
720
721    // Make sure we saw all of the expected VMOs.
722    EXPECT_EQ((uint32_t)(1 << test_info->num_vmos) - 1, saw_vmo);
723
724    // Do one more read with a short buffer to test actual < avail.
725    const size_t bufsize2 = actual * 3 / 4 * sizeof(zx_info_vmo_t);
726    zx_info_vmo_t* vmos2 = (zx_info_vmo_t*)malloc(bufsize2);
727    size_t actual2;
728    size_t avail2;
729    ASSERT_EQ(zx_object_get_info(process, ZX_INFO_PROCESS_VMOS,
730                                 vmos2, bufsize2,
731                                 &actual2, &avail2),
732              ZX_OK);
733    EXPECT_LT(actual2, avail2);
734    // mini-process is very simple, and won't have modified its own set of VMOs
735    // since the previous dump.
736    EXPECT_EQ(avail, avail2);
737    LTRACEF("\n");
738    EXPECT_GT(actual2, 3u); // Make sure we're looking at something.
739    for (size_t i = 0; i < actual2; i++) {
740        zx_info_vmo_t* e1 = vmos + i;
741        zx_info_vmo_t* e2 = vmos2 + i;
742        char msg[128];
743        snprintf(msg, sizeof(msg),
744                 "[%2zd] koid:%" PRIu64 "/%" PRIu64 " name:'%s'/'%s' "
745                 "size:%" PRIu64 "/%" PRIu64 " flags:0x%" PRIx32 "/0x%" PRIx32,
746                 i, e1->koid, e2->koid, e1->name, e2->name,
747                 e1->size_bytes, e2->size_bytes, e1->flags, e2->flags);
748        LTRACEF("%s\n", msg);
749        EXPECT_EQ(e1->koid, e2->koid, msg);
750        EXPECT_EQ(e1->size_bytes, e2->size_bytes, msg);
751        EXPECT_EQ(e1->flags, e2->flags, msg);
752        if (e1->flags == e2->flags && e2->flags & ZX_INFO_VMO_VIA_HANDLE) {
753            EXPECT_EQ(e1->handle_rights, e2->handle_rights, msg);
754        }
755    }
756
757    free(vmos);
758    free(vmos2);
759    END_TEST;
760}
761
762// ZX_INFO_JOB_PROCESS/ZX_INFO_JOB_CHILDREN tests
763
764// Returns a job with the structure:
765// - returned job
766//   - child process 1
767//   - child process 2
768//   - child process 3 (kTestJobChildProcs)
769//   - child job 1
770//     - grandchild process 1.1
771//     - grandchild job 1.1
772//   - child job 2 (kTestJobChildJobs)
773//     - grandchild process 2.1
774//     - grandchild job 2.1
775const size_t kTestJobChildProcs = 3;
776const size_t kTestJobChildJobs = 2;
777zx_handle_t get_test_job() {
778    static zx_handle_t test_job = ZX_HANDLE_INVALID;
779
780    if (test_job == ZX_HANDLE_INVALID) {
781        char msg[64];
782        zx_handle_t root;
783        zx_status_t s = zx_job_create(zx_job_default(), 0, &root);
784        if (s != ZX_OK) {
785            EXPECT_EQ(s, ZX_OK, "zx_job_create"); // Poison the test.
786            return ZX_HANDLE_INVALID;
787        }
788        for (size_t i = 0; i < kTestJobChildProcs; i++) {
789            zx_handle_t proc;
790            zx_handle_t vmar;
791            s = zx_process_create(root, "child", 6, 0, &proc, &vmar);
792            if (s != ZX_OK) {
793                snprintf(msg, sizeof(msg), "zx_process_create(child %zu)", i);
794                goto fail;
795            }
796        }
797        for (size_t i = 0; i < kTestJobChildJobs; i++) {
798            zx_handle_t job;
799            s = zx_job_create(root, 0, &job);
800            if (s != ZX_OK) {
801                snprintf(msg, sizeof(msg), "zx_job_create(child %zu)", i);
802                goto fail;
803            }
804            zx_handle_t proc;
805            zx_handle_t vmar;
806            s = zx_process_create(job, "grandchild", 6, 0, &proc, &vmar);
807            if (s != ZX_OK) {
808                snprintf(msg, sizeof(msg), "zx_process_create(grandchild)");
809                goto fail;
810            }
811            zx_handle_t subjob;
812            s = zx_job_create(job, 0, &subjob);
813            if (s != ZX_OK) {
814                snprintf(msg, sizeof(msg), "zx_job_create(grandchild)");
815                goto fail;
816            }
817        }
818
819        if (false) {
820        fail:
821            EXPECT_EQ(s, ZX_OK, msg); // Poison the test
822            zx_task_kill(root);       // Clean up all tasks; leaks handles
823            return ZX_HANDLE_INVALID;
824        }
825        test_job = root;
826    }
827
828    return test_job;
829}
830
831// The jobch_helper_* (job child helper) functions allow testing both
832// ZX_INFO_JOB_PROCESS and ZX_INFO_JOB_CHILDREN.
833bool jobch_helper_smoke(uint32_t topic, size_t expected_count) {
834    BEGIN_TEST;
835    zx_koid_t koids[32];
836    size_t actual;
837    size_t avail;
838    EXPECT_EQ(zx_object_get_info(get_test_job(), topic,
839                                 koids, sizeof(koids), &actual, &avail),
840              ZX_OK);
841    EXPECT_EQ(expected_count, actual);
842    EXPECT_EQ(expected_count, avail);
843
844    // All returned koids should produce a valid handle when passed to
845    // zx_object_get_child.
846    for (size_t i = 0; i < actual; i++) {
847        char msg[32];
848        snprintf(msg, sizeof(msg), "koid %zu", koids[i]);
849        zx_handle_t h = ZX_HANDLE_INVALID;
850        EXPECT_EQ(zx_object_get_child(get_test_job(), koids[i],
851                                      ZX_RIGHT_SAME_RIGHTS, &h),
852                  ZX_OK, msg);
853        zx_handle_close(h);
854    }
855    END_TEST;
856}
857
858bool job_processes_smoke() {
859    return jobch_helper_smoke(ZX_INFO_JOB_PROCESSES, kTestJobChildProcs);
860}
861
862bool job_children_smoke() {
863    return jobch_helper_smoke(ZX_INFO_JOB_CHILDREN, kTestJobChildJobs);
864}
865
866uint32_t handle_count_or_zero(zx_handle_t handle) {
867    zx_info_handle_count_t info;
868    if (ZX_OK != zx_object_get_info(
869                     handle, ZX_INFO_HANDLE_COUNT, &info, sizeof(info), nullptr, nullptr)) {
870        return 0u;
871    }
872    return info.handle_count;
873}
874
875bool handle_count_valid() {
876    // We create an event and check that ZX_INFO_HANDLE_COUNT stats at 1 and
877    // goes up for each new handle minted from it and goes down for each handle
878    // closed.
879    zx_handle_t event[4];
880    ASSERT_EQ(zx_event_create(0u, &event[0]), ZX_OK);
881    EXPECT_EQ(handle_count_or_zero(event[0]), 1u);
882
883    for (size_t i = 1; i != fbl::count_of(event); ++i) {
884        ASSERT_EQ(zx_handle_duplicate(
885                      event[0], ZX_RIGHT_SIGNAL, &event[i]),
886                  ZX_OK);
887        EXPECT_EQ(handle_count_or_zero(event[0]), i + 1);
888    }
889
890    for (size_t i = fbl::count_of(event) - 1; i != 0; --i) {
891        ASSERT_EQ(zx_handle_close(event[i]), ZX_OK);
892        EXPECT_EQ(handle_count_or_zero(event[0]), i);
893    }
894
895    zx_handle_close(event[0]);
896    return true;
897}
898
899bool handle_stats_control() {
900    zx_info_process_handle_stats_t info;
901    zx_status_t status = zx_object_get_info(zx_process_self(), ZX_INFO_PROCESS_HANDLE_STATS,
902                                            &info, sizeof(info), nullptr, nullptr);
903    ASSERT_EQ(status, ZX_OK);
904    EXPECT_EQ(info.handle_count[ZX_OBJ_TYPE_NONE], 0);
905    EXPECT_GT(info.handle_count[ZX_OBJ_TYPE_PROCESS], 0);
906    EXPECT_GT(info.handle_count[ZX_OBJ_TYPE_THREAD], 0);
907    EXPECT_GT(info.handle_count[ZX_OBJ_TYPE_VMO], 0);
908    EXPECT_EQ(info.handle_count[ZX_OBJ_TYPE_INTERRUPT], 0);
909
910    uint32_t channel_count = info.handle_count[ZX_OBJ_TYPE_CHANNEL];
911
912    zx_handle_t h1, h2;
913    status = zx_channel_create(0, &h1, &h2);
914    ASSERT_EQ(status, ZX_OK);
915
916    status = zx_object_get_info(zx_process_self(), ZX_INFO_PROCESS_HANDLE_STATS,
917                                &info, sizeof(info), nullptr, nullptr);
918    ASSERT_EQ(status, ZX_OK);
919    EXPECT_EQ(info.handle_count[ZX_OBJ_TYPE_CHANNEL], channel_count + 2);
920    zx_handle_close(h1);
921    zx_handle_close(h2);
922    return true;
923}
924
925} // namespace
926
927// Tests that should pass for any topic. Use the wrappers below instead of
928// calling this directly.
929#define _RUN_COMMON_TESTS(topic, entry_type, get_handle)                   \
930    RUN_TEST((invalid_handle_fails<topic, entry_type>));                   \
931    RUN_TEST((null_avail_actual_succeeds<topic, entry_type, get_handle>)); \
932    RUN_TEST((bad_buffer_fails<topic, entry_type, get_handle>));           \
933    RUN_TEST((bad_actual_fails<topic, entry_type, get_handle>));           \
934    RUN_TEST((bad_avail_fails<topic, entry_type, get_handle>))
935
936// Tests that should pass for any topic that expects a single entry in its
937// in/out buffer.
938#define RUN_SINGLE_ENTRY_TESTS(topic, entry_type, get_handle) \
939    _RUN_COMMON_TESTS(topic, entry_type, get_handle);         \
940    RUN_TEST((single_zero_buffer_fails<topic, entry_type, get_handle>))
941
942// Tests that should pass for any topic that can handle multiple entries in its
943// in/out buffer.
944#define RUN_MULTI_ENTRY_TESTS(topic, entry_type, get_handle)          \
945    _RUN_COMMON_TESTS(topic, entry_type, get_handle);                 \
946    RUN_TEST((multi_zero_buffer_succeeds<topic, get_handle>));        \
947    RUN_TEST((short_buffer_succeeds<topic, entry_type, get_handle>)); \
948    RUN_TEST((partially_unmapped_buffer_fails<topic, entry_type, get_handle>))
949
950BEGIN_TEST_CASE(object_info_tests)
951
952// ZX_INFO_HANDLE_VALID is an oddball that doesn't care about its buffer,
953// so we can't use the normal topic test suites.
954RUN_TEST(handle_valid_on_valid_handle_succeeds);
955RUN_TEST(handle_valid_on_closed_handle_fails);
956RUN_TEST((invalid_handle_fails<ZX_INFO_HANDLE_VALID, void*>));
957
958RUN_TEST(task_stats_smoke);
959RUN_SINGLE_ENTRY_TESTS(ZX_INFO_TASK_STATS, zx_info_task_stats_t, zx_process_self);
960RUN_TEST((wrong_handle_type_fails<ZX_INFO_TASK_STATS, zx_info_task_stats_t, get_test_job>));
961RUN_TEST((wrong_handle_type_fails<ZX_INFO_TASK_STATS, zx_info_task_stats_t, zx_thread_self>));
962
963RUN_TEST(process_maps_smoke);
964RUN_MULTI_ENTRY_TESTS(ZX_INFO_PROCESS_MAPS, zx_info_maps_t, get_test_process);
965RUN_TEST((self_fails<ZX_INFO_PROCESS_MAPS, zx_info_maps_t>))
966RUN_TEST((wrong_handle_type_fails<ZX_INFO_PROCESS_MAPS, zx_info_maps_t, get_test_job>));
967RUN_TEST((wrong_handle_type_fails<ZX_INFO_PROCESS_MAPS, zx_info_maps_t, zx_thread_self>));
968RUN_TEST((missing_rights_fails<ZX_INFO_PROCESS_MAPS, zx_info_maps_t, get_test_process,
969                               ZX_RIGHT_INSPECT>));
970
971RUN_TEST(process_vmos_smoke);
972RUN_MULTI_ENTRY_TESTS(ZX_INFO_PROCESS_VMOS, zx_info_vmo_t, get_test_process);
973RUN_TEST((self_fails<ZX_INFO_PROCESS_VMOS, zx_info_vmo_t>))
974RUN_TEST((wrong_handle_type_fails<ZX_INFO_PROCESS_VMOS, zx_info_vmo_t, get_test_job>));
975RUN_TEST((wrong_handle_type_fails<ZX_INFO_PROCESS_VMOS, zx_info_vmo_t, zx_thread_self>));
976RUN_TEST((missing_rights_fails<ZX_INFO_PROCESS_VMOS, zx_info_vmo_t, get_test_process,
977                               ZX_RIGHT_INSPECT>));
978
979RUN_TEST(job_processes_smoke);
980RUN_MULTI_ENTRY_TESTS(ZX_INFO_JOB_PROCESSES, zx_koid_t, get_test_job);
981RUN_TEST((wrong_handle_type_fails<ZX_INFO_JOB_PROCESSES, zx_koid_t, get_test_process>));
982RUN_TEST((wrong_handle_type_fails<ZX_INFO_JOB_PROCESSES, zx_koid_t, zx_thread_self>));
983RUN_TEST((missing_rights_fails<ZX_INFO_JOB_PROCESSES, zx_koid_t, get_test_job,
984                               ZX_RIGHT_ENUMERATE>));
985
986RUN_TEST(job_children_smoke);
987RUN_MULTI_ENTRY_TESTS(ZX_INFO_JOB_CHILDREN, zx_koid_t, get_test_job);
988RUN_TEST((wrong_handle_type_fails<ZX_INFO_JOB_CHILDREN, zx_koid_t, get_test_process>));
989RUN_TEST((wrong_handle_type_fails<ZX_INFO_JOB_CHILDREN, zx_koid_t, zx_thread_self>));
990RUN_TEST((missing_rights_fails<ZX_INFO_JOB_CHILDREN, zx_koid_t, get_test_job,
991                               ZX_RIGHT_ENUMERATE>));
992
993// Basic tests for all other topics.
994
995RUN_SINGLE_ENTRY_TESTS(ZX_INFO_HANDLE_BASIC, zx_info_handle_basic_t, get_test_job);
996RUN_SINGLE_ENTRY_TESTS(ZX_INFO_HANDLE_BASIC, zx_info_handle_basic_t, get_test_process);
997RUN_SINGLE_ENTRY_TESTS(ZX_INFO_HANDLE_BASIC, zx_info_handle_basic_t, zx_thread_self);
998RUN_SINGLE_ENTRY_TESTS(ZX_INFO_HANDLE_BASIC, zx_info_handle_basic_t, zx_vmar_root_self);
999
1000RUN_SINGLE_ENTRY_TESTS(ZX_INFO_HANDLE_COUNT, zx_info_handle_count_t, zx_thread_self);
1001
1002RUN_SINGLE_ENTRY_TESTS(ZX_INFO_PROCESS, zx_info_process_t, get_test_process);
1003RUN_TEST((wrong_handle_type_fails<ZX_INFO_PROCESS, zx_info_process_t, get_test_job>));
1004RUN_TEST((wrong_handle_type_fails<ZX_INFO_PROCESS, zx_info_process_t, zx_thread_self>));
1005
1006RUN_SINGLE_ENTRY_TESTS(ZX_INFO_VMAR, zx_info_vmar_t, zx_vmar_root_self);
1007RUN_TEST((wrong_handle_type_fails<ZX_INFO_VMAR, zx_info_vmar_t, get_test_job>));
1008RUN_TEST((wrong_handle_type_fails<ZX_INFO_VMAR, zx_info_vmar_t, get_test_process>));
1009RUN_TEST((wrong_handle_type_fails<ZX_INFO_VMAR, zx_info_vmar_t, zx_thread_self>));
1010
1011RUN_SINGLE_ENTRY_TESTS(ZX_INFO_THREAD, zx_info_thread_t, zx_thread_self);
1012RUN_TEST((wrong_handle_type_fails<ZX_INFO_THREAD, zx_info_thread_t, get_test_job>));
1013RUN_TEST((wrong_handle_type_fails<ZX_INFO_THREAD, zx_info_thread_t, get_test_process>));
1014
1015RUN_SINGLE_ENTRY_TESTS(ZX_INFO_THREAD_STATS, zx_info_thread_stats_t, zx_thread_self);
1016RUN_TEST((wrong_handle_type_fails<ZX_INFO_THREAD_STATS, zx_info_thread_t, get_test_job>));
1017RUN_TEST((wrong_handle_type_fails<ZX_INFO_THREAD_STATS, zx_info_thread_t, get_test_process>));
1018
1019// ZX_INFO_PROCESS_THREADS tests.
1020// TODO(dbort): Use RUN_MULTI_ENTRY_TESTS instead. |short_buffer_succeeds| and
1021// |partially_unmapped_buffer_fails| currently fail because those tests expect
1022// avail > 1, but the test process only has one thread and it's not trivial to
1023// add more.
1024RUN_TEST((invalid_handle_fails<ZX_INFO_PROCESS_THREADS, zx_koid_t>));
1025RUN_TEST((null_avail_actual_succeeds<ZX_INFO_PROCESS_THREADS, zx_koid_t, get_test_process>));
1026RUN_TEST((bad_buffer_fails<ZX_INFO_PROCESS_THREADS, zx_koid_t, get_test_process>));
1027RUN_TEST((bad_actual_fails<ZX_INFO_PROCESS_THREADS, zx_koid_t, get_test_process>));
1028RUN_TEST((bad_avail_fails<ZX_INFO_PROCESS_THREADS, zx_koid_t, get_test_process>))
1029RUN_TEST((multi_zero_buffer_succeeds<ZX_INFO_PROCESS_THREADS, get_test_process>));
1030
1031// Skip most tests for ZX_INFO_THREAD_EXCEPTION_REPORT, which is tested
1032// elsewhere and requires the target thread to be in a certain state.
1033RUN_TEST((invalid_handle_fails<ZX_INFO_THREAD_EXCEPTION_REPORT, zx_exception_report_t>));
1034
1035// TODO(dbort): Test resource topics
1036// RUN_MULTI_ENTRY_TESTS(ZX_INFO_CPU_STATS, zx_info_cpu_stats_t, get_root_resource);
1037// RUN_SINGLE_ENTRY_TESTS(ZX_INFO_KMEM_STATS, zx_info_kmem_stats_t, get_root_resource);
1038
1039RUN_TEST(handle_count_valid);
1040
1041RUN_TEST(handle_stats_control);
1042
1043END_TEST_CASE(object_info_tests)
1044
1045#ifndef BUILD_COMBINED_TESTS
1046int main(int argc, char** argv) {
1047    return unittest_run_all_tests(argc, argv) ? 0 : -1;
1048}
1049#endif
1050