Flutter Engine
The Flutter Engine
os_fuchsia.cc
Go to the documentation of this file.
1// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "vm/globals.h"
6#if defined(DART_HOST_OS_FUCHSIA)
7
8#include "vm/os.h"
9
10#include <dlfcn.h>
11#include <elf.h>
12#include <errno.h>
13#include <fcntl.h>
14#include <stdint.h>
15#include <string.h>
16#include <unistd.h>
17
18#include <fuchsia/intl/cpp/fidl.h>
19#include <lib/async-loop/default.h>
20#include <lib/async-loop/loop.h>
21#include <lib/async/default.h>
22#include <lib/inspect/component/cpp/component.h>
23#include <lib/inspect/cpp/inspect.h>
24#include <lib/sys/cpp/component_context.h>
25#include <lib/sys/cpp/service_directory.h>
26#include <zircon/process.h>
27#include <zircon/syscalls.h>
28#include <zircon/syscalls/object.h>
29#include <zircon/threads.h>
30#include <zircon/time.h>
31#include <zircon/types.h>
32
33#include <set>
34
35#include "unicode/errorcode.h"
36#include "unicode/timezone.h"
37#include "unicode/umachine.h"
38
39#include "platform/assert.h"
40#include "platform/syslog.h"
41#include "platform/utils.h"
42#include "vm/image_snapshot.h"
43#include "vm/lockers.h"
44#include "vm/os_thread.h"
45#include "vm/zone.h"
46
47namespace {
48
49using dart::Mutex;
51using dart::Syslog;
52using dart::Zone;
53
54// This is the default timezone returned if it could not be obtained. For
55// Fuchsia, the default device timezone is always UTC.
56static const char kDefaultTimezone[] = "UTC";
57
58static constexpr int32_t kMsPerSec = 1000;
59
60// The data directory containing ICU timezone data files.
61static constexpr char kICUTZDataDir[] = "/config/data/tzdata/icu/44/le";
62// An updated location for ICU timezone data files.
63// See:
64// https://fuchsia.dev/fuchsia-src/development/internationalization/icu_data#timezone_configuration_data
65// https://fuchsia.dev/fuchsia-src/concepts/process/namespaces
66static constexpr char kICUTZDataDir2[] = "/config/tzdata/icu/44/le";
67
68// This is the general OK status.
69static constexpr int32_t kOk = 0;
70
71// This status means that the error code is not initialized yet ("set" was not
72// yet called). Error codes are usually either 0 (kOk), or negative.
73static constexpr int32_t kUninitialized = 1;
74
75// The status codes for tzdata file open and read.
76enum class TZDataStatus {
77 // The operation completed without error.
78 OK = 0,
79 // The open call for the tzdata file did not succeed.
80 COULD_NOT_OPEN = -1,
81 // The close call (after tzdata was loaded) did not succeed.
82 COULD_NOT_CLOSE = -2,
83};
84
85// Adds a facility for introspecting timezone data errors. Allows insight into
86// the internal state of the VM even if error reporting facilities fail.
87//
88// Under normal operation, all metric values below should be zero.
89class InspectMetrics {
90 public:
91 // Takes ownership of the vm_node.
92 explicit InspectMetrics(std::unique_ptr<inspect::Node> vm_node)
93 : vm_node_(std::move(vm_node)),
94 dst_status_(vm_node_->CreateInt("dst_status", kUninitialized)),
95 tz_data_status_(vm_node_->CreateInt("tz_data_status", kUninitialized)),
96 tz_data_close_status_(
97 vm_node_->CreateInt("tz_data_close_status", kUninitialized)),
98 get_profile_status_(
99 vm_node_->CreateInt("get_profile_status", kUninitialized)),
100 profiles_timezone_content_status_(
101 vm_node_->CreateInt("timezone_content_status", kOk)),
102 num_get_profile_calls_(vm_node_->CreateInt("num_get_profile_calls", 0)),
103 num_on_change_calls_(vm_node_->CreateInt("num_on_change_calls", 0)),
104 num_intl_provider_errors_(
105 vm_node_->CreateInt("num_intl_provider_errors", 0)) {}
106
107 // Registers a single call to GetProfile callback.
108 void RegisterGetProfileCall() { num_get_profile_calls_.Add(1); }
109
110 // Registers a single call to OnChange callback.
111 void RegisterOnChangeCall() { num_on_change_calls_.Add(1); }
112
113 // Registers a provider error.
114 void RegisterIntlProviderError() { num_intl_provider_errors_.Add(1); }
115
116 // Sets the last status code for DST offset calls.
117 void SetDSTOffsetStatus(zx_status_t status) {
118 dst_status_.Set(static_cast<int32_t>(status));
119 }
120
121 // Sets the return value of call to InitializeTZData, and the status of the
122 // reported by close() on tzdata files.
123 void SetInitTzData(TZDataStatus value, int32_t status) {
124 tz_data_status_.Set(static_cast<int32_t>(value));
125 tz_data_close_status_.Set(status);
126 }
127
128 // Sets the last status code for the call to PropertyProvider::GetProfile.
129 void SetProfileStatus(zx_status_t status) {
130 get_profile_status_.Set(static_cast<int32_t>(status));
131 }
132
133 // Sets the last status seen while examining timezones returned from
134 // PropertyProvider::GetProfile.
135 void SetTimeZoneContentStatus(zx_status_t status) {
136 profiles_timezone_content_status_.Set(static_cast<int32_t>(status));
137 }
138
139 private:
140 // The OS metrics node.
141 std::unique_ptr<inspect::Node> vm_node_;
142
143 // The status of the last GetTimeZoneOffset call.
144 inspect::IntProperty dst_status_;
145
146 // The status of the initialization.
147 inspect::IntProperty tz_data_status_;
148
149 // The return code for the close() call for tzdata files.
150 inspect::IntProperty tz_data_close_status_;
151
152 // The return code of the GetProfile call in GetTimeZoneName. If this is
153 // nonzero, then os_fuchsia.cc reported a default timezone as a fallback.
154 inspect::IntProperty get_profile_status_;
155
156 // U_ILLEGAL_ARGUMENT_ERROR(=1) if timezones read from ProfileProvider were
157 // incorrect. Otherwise 0. If this metric reports U_ILLEGAL_ARGUMENT_ERROR,
158 // the os_fuchsia.cc module reported a default timezone as a fallback.
159 inspect::IntProperty profiles_timezone_content_status_;
160
161 // Keeps a number of get_profile update calls.
162 inspect::IntProperty num_get_profile_calls_;
163
164 // Number of "on change" callback calls.
165 inspect::IntProperty num_on_change_calls_;
166
167 // Keeps a number of errors encountered in intl provider.
168 inspect::IntProperty num_intl_provider_errors_;
169};
170
171// Thread-safe storage for the current timezone name.
172//
173// Keeps an up to date timezone cache, updating if needed through the
174// asynchronous update interface. Access to this class is thread-safe.
175class TimezoneName final {
176 public:
177 // Creates a new instance of TimezoneName. Does not take ownership of
178 // metrics.
179 static std::shared_ptr<TimezoneName> New(
180 fuchsia::intl::PropertyProviderPtr proxy,
181 std::weak_ptr<InspectMetrics> metrics) {
182 auto timezone_name =
183 std::make_shared<TimezoneName>(std::move(proxy), metrics);
184 timezone_name->InitHandlers(timezone_name);
185 return timezone_name;
186 }
187
188 TimezoneName(fuchsia::intl::PropertyProviderPtr proxy,
189 std::weak_ptr<InspectMetrics> metrics)
190 : m_(),
191 metrics_(std::move(metrics)),
192 proxy_(std::move(proxy)),
193 timezone_name_(kDefaultTimezone) {
194 ASSERT(metrics_.lock() != nullptr);
195 }
196
197 // Gets the current timezone name. Repeated calls may retrieve updated
198 // values.
199 std::string Get() const {
200 MutexLocker lock(&m_);
201 // Returns a copy, to avoid a data race with async updates.
202 return timezone_name_;
203 }
204
205 private:
206 // Sets the event handlers in this resolver. Intended to resolve a circular
207 // reference between the shared timezone name and this.
208 void InitHandlers(std::shared_ptr<TimezoneName> timezone_name) {
209 ASSERT(timezone_name.get() == this);
210 timezone_name->proxy_.set_error_handler(
211 [weak_this =
212 std::weak_ptr<TimezoneName>(timezone_name)](zx_status_t status) {
213 if (!weak_this.expired()) {
214 weak_this.lock()->ErrorHandler(status);
215 }
216 });
217 timezone_name->proxy_.events().OnChange =
218 [weak_this = std::weak_ptr<TimezoneName>(timezone_name)]() {
219 if (!weak_this.expired()) {
220 weak_this.lock()->OnChangeCallback();
221 }
222 };
223 timezone_name->proxy_->GetProfile(
224 [weak_this = std::weak_ptr<TimezoneName>(timezone_name)](
225 fuchsia::intl::Profile profile) {
226 if (!weak_this.expired()) {
227 weak_this.lock()->GetProfileCallback(std::move(profile));
228 }
229 });
230 }
231
232 // Called on a profile provider error in the context of the event loop
233 // thread.
234 void ErrorHandler(zx_status_t status) {
235 MutexLocker lock(&m_);
236 WithMetrics([status](std::shared_ptr<InspectMetrics> metrics) {
237 metrics->SetProfileStatus(status);
238 metrics->RegisterIntlProviderError();
239 });
240 }
241
242 // Called when an OnChange event is received in the context of the event loop
243 // thread. The only action here is to trigger an asynchronous update of the
244 // intl profile.
245 void OnChangeCallback() {
246 MutexLocker lock(&m_);
247 WithMetrics([](std::shared_ptr<InspectMetrics> metrics) {
248 metrics->RegisterOnChangeCall();
249 });
250 proxy_->GetProfile([this](fuchsia::intl::Profile profile) {
251 this->GetProfileCallback(std::move(profile));
252 });
253 }
254
255 // Called when a GetProfile async request is resolved, in the context of the
256 // event loop thread.
257 void GetProfileCallback(fuchsia::intl::Profile profile) {
258 MutexLocker lock(&m_);
259 WithMetrics([](std::shared_ptr<InspectMetrics> metrics) {
260 metrics->RegisterGetProfileCall();
261 });
262 const std::vector<fuchsia::intl::TimeZoneId>& timezones =
263 profile.time_zones();
264 if (timezones.empty()) {
265 WithMetrics([](std::shared_ptr<InspectMetrics> metrics) {
266 metrics->SetTimeZoneContentStatus(U_ILLEGAL_ARGUMENT_ERROR);
267 });
268 // Empty timezone array is not up to fuchsia::intl spec. The serving
269 // endpoint is broken and should be fixed.
270 Syslog::PrintErr("got empty timezone value\n");
271 return;
272 }
273 WithMetrics([](std::shared_ptr<InspectMetrics> metrics) {
274 metrics->SetProfileStatus(ZX_OK);
275 metrics->SetTimeZoneContentStatus(ZX_OK);
276 });
277
278 timezone_name_ = timezones[0].id;
279 }
280
281 // Runs the provided function only on valid metrics.
282 void WithMetrics(std::function<void(std::shared_ptr<InspectMetrics> m)> f) {
283 std::shared_ptr<InspectMetrics> l = metrics_.lock();
284 if (l != nullptr) {
285 f(l);
286 }
287 }
288
289 // Guards timezone_name_ because the callbacks will be called in an
290 // asynchronous thread.
291 mutable Mutex m_;
292
293 // Used to keep tally on the update events. Not owned.
294 std::weak_ptr<InspectMetrics> metrics_;
295
296 // A client-side proxy for a connection to the property provider service.
297 fuchsia::intl::PropertyProviderPtr proxy_;
298
299 // Caches the current timezone name. This is updated asynchronously through
300 // GetProfileCallback.
301 std::string timezone_name_;
302};
303
304// The timezone names encountered so far. The timezone names must live forever.
305std::set<std::string> timezone_names;
306
307// Initialized on OS:Init(), deinitialized on OS::Cleanup.
308std::shared_ptr<InspectMetrics> metrics;
309std::shared_ptr<TimezoneName> timezone_name;
310async_loop_t* message_loop = nullptr;
311
312// Initializes the source of timezone data if available. Timezone data file in
313// Fuchsia is at a fixed directory path. Returns true on success.
314bool InitializeTZData() {
315 ASSERT(metrics != nullptr);
316 // Try opening the path to check if present. No need to verify that it is a
317 // directory since ICU loading will return an error if the TZ data path is
318 // wrong.
319 //
320 // Try the new dir first, sub with the old fallback.
321 const char* tz_dirname = kICUTZDataDir2;
322 int fd = openat(AT_FDCWD, tz_dirname, O_RDONLY);
323 if (fd < 0) {
324 tz_dirname = kICUTZDataDir;
325 fd = openat(AT_FDCWD, tz_dirname, O_RDONLY);
326 }
327 if (fd < 0) {
328 metrics->SetInitTzData(TZDataStatus::COULD_NOT_OPEN, fd);
329 return false;
330 }
331 // 0 == Not overwriting the env var if already set.
332 setenv("ICU_TIMEZONE_FILES_DIR", tz_dirname, 0);
333 int32_t close_status = close(fd);
334 if (close_status != 0) {
335 metrics->SetInitTzData(TZDataStatus::COULD_NOT_CLOSE, close_status);
336 return false;
337 }
338 metrics->SetInitTzData(TZDataStatus::OK, 0);
339 return true;
340}
341
342int64_t GetCurrentTimeNanos() {
343 struct timespec ts;
344 if (timespec_get(&ts, TIME_UTC) == 0) {
345 FATAL("timespec_get failed");
346 return 0;
347 }
348 return zx_time_add_duration(ZX_SEC(ts.tv_sec), ZX_NSEC(ts.tv_nsec));
349}
350
351} // namespace
352
353namespace dart {
354
355#ifndef PRODUCT
356
357DEFINE_FLAG(bool,
358 generate_perf_events_symbols,
359 false,
360 "Generate events symbols for profiling with perf");
361
362#endif // !PRODUCT
363
364intptr_t OS::ProcessId() {
365 return static_cast<intptr_t>(getpid());
366}
367
368// TODO(FL-98): Change this to talk to fuchsia.dart to get timezone service to
369// directly get timezone.
370//
371// Putting this hack right now due to CP-120 as I need to remove
372// component:ConnectToEnvironmentServices and this is the only thing that is
373// blocking it and FL-98 will take time.
374static fuchsia::intl::PropertyProviderPtr property_provider;
375
376static zx_status_t GetLocalAndDstOffsetInSeconds(int64_t seconds_since_epoch,
377 int32_t* local_offset,
378 int32_t* dst_offset) {
379 const char* timezone_id = OS::GetTimeZoneName(seconds_since_epoch);
380 std::unique_ptr<icu::TimeZone> timezone(
381 icu::TimeZone::createTimeZone(timezone_id));
382 UErrorCode error = U_ZERO_ERROR;
383 const auto ms_since_epoch =
384 static_cast<UDate>(kMsPerSec * seconds_since_epoch);
385 // The units of time that local_offset and dst_offset are returned from this
386 // function is, usefully, not documented, but it seems that the units are
387 // milliseconds. Add these variables here for clarity.
388 int32_t local_offset_ms = 0;
389 int32_t dst_offset_ms = 0;
390 timezone->getOffset(ms_since_epoch, /*local_time=*/0, local_offset_ms,
391 dst_offset_ms, error);
392 metrics->SetDSTOffsetStatus(error);
393 if (error != U_ZERO_ERROR) {
394 icu::ErrorCode icu_error;
395 icu_error.set(error);
396 Syslog::PrintErr("could not get DST offset: %s\n", icu_error.errorName());
397 return ZX_ERR_INTERNAL;
398 }
399 // We must return offset in seconds, so convert.
400 *local_offset = local_offset_ms / kMsPerSec;
401 *dst_offset = dst_offset_ms / kMsPerSec;
402 return ZX_OK;
403}
404
405// Returns a C string with the time zone name. This module retains the
406// ownership of the pointer.
407const char* OS::GetTimeZoneName(int64_t seconds_since_epoch) {
408 ASSERT(timezone_name != nullptr);
409
410 // Sadly, since we do not know how long the timezone name will be needed, we
411 // can not ever deallocate it. So instead, we put it into a a set that will
412 // not move it around in memory and return a pointer to it. Since the number
413 // of timezones is finite, this ensures that the memory taken up by timezones
414 // does not grow indefinitely, even if we end up retaining all the timezones
415 // there are.
416 const auto i = timezone_names.insert(timezone_name->Get());
417 ASSERT(i.first != timezone_names.end());
418 return i.first->c_str();
419}
420
421int OS::GetTimeZoneOffsetInSeconds(int64_t seconds_since_epoch) {
422 int32_t local_offset = 0;
423 int32_t dst_offset = 0;
424 const zx_status_t status = GetLocalAndDstOffsetInSeconds(
425 seconds_since_epoch, &local_offset, &dst_offset);
426 return status == ZX_OK ? local_offset + dst_offset : 0;
427}
428
429int64_t OS::GetCurrentTimeMillis() {
430 return GetCurrentTimeNanos() / ZX_MSEC(1);
431}
432
433int64_t OS::GetCurrentTimeMicros() {
434 return GetCurrentTimeNanos() / ZX_USEC(1);
435}
436
438 return zx_clock_get_monotonic();
439}
440
443}
444
446 const int64_t ticks = GetCurrentMonotonicTicks();
448 return ticks / kNanosecondsPerMicrosecond;
449}
450
452 zx_info_thread_stats_t info = {};
453 zx_status_t status = zx_object_get_info(thrd_get_zx_handle(thrd_current()),
454 ZX_INFO_THREAD_STATS, &info,
455 sizeof(info), nullptr, nullptr);
456 return status == ZX_OK ? info.total_runtime / kNanosecondsPerMicrosecond : 0;
457}
458
460#if defined(SUPPORT_TIMELINE)
462#else
463 return -1;
464#endif
465}
466
467// TODO(5411554): May need to hoist these architecture dependent code
468// into a architecture specific file e.g: os_ia32_fuchsia.cc
470#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) || \
471 defined(TARGET_ARCH_ARM64)
472 const int kMinimumAlignment = 16;
473#elif defined(TARGET_ARCH_ARM)
474 const int kMinimumAlignment = 8;
475#else
476#error Unsupported architecture.
477#endif
478 intptr_t alignment = kMinimumAlignment;
479 // TODO(5411554): Allow overriding default stack alignment for
480 // testing purposes.
481 // Flags::DebugIsInt("stackalign", &alignment);
482 ASSERT(Utils::IsPowerOfTwo(alignment));
483 ASSERT(alignment >= kMinimumAlignment);
484 return alignment;
485}
486
488 return sysconf(_SC_NPROCESSORS_CONF);
489}
490
491void OS::Sleep(int64_t millis) {
493}
494
495void OS::SleepMicros(int64_t micros) {
496 zx_nanosleep(zx_deadline_after(micros * kNanosecondsPerMicrosecond));
497}
498
499void OS::DebugBreak() {
501}
502
503DART_NOINLINE uintptr_t OS::GetProgramCounter() {
504 return reinterpret_cast<uintptr_t>(
505 __builtin_extract_return_addr(__builtin_return_address(0)));
506}
507
508void OS::Print(const char* format, ...) {
509 va_list args;
511 VFPrint(stdout, format, args);
512 va_end(args);
513}
514
515void OS::VFPrint(FILE* stream, const char* format, va_list args) {
516 vfprintf(stream, format, args);
517 fflush(stream);
518}
519
520char* OS::SCreate(Zone* zone, const char* format, ...) {
521 va_list args;
523 char* buffer = VSCreate(zone, format, args);
524 va_end(args);
525 return buffer;
526}
527
528char* OS::VSCreate(Zone* zone, const char* format, va_list args) {
529 // Measure.
530 va_list measure_args;
531 va_copy(measure_args, args);
532 intptr_t len = Utils::VSNPrint(nullptr, 0, format, measure_args);
533 va_end(measure_args);
534
535 char* buffer;
536 if (zone != nullptr) {
537 buffer = zone->Alloc<char>(len + 1);
538 } else {
539 buffer = reinterpret_cast<char*>(malloc(len + 1));
540 }
541 ASSERT(buffer != nullptr);
542
543 // Print.
544 va_list print_args;
545 va_copy(print_args, args);
546 Utils::VSNPrint(buffer, len + 1, format, print_args);
547 va_end(print_args);
548 return buffer;
549}
550
551bool OS::StringToInt64(const char* str, int64_t* value) {
552 ASSERT(str != nullptr && strlen(str) > 0 && value != nullptr);
553 int32_t base = 10;
554 char* endptr;
555 int i = 0;
556 if (str[0] == '-') {
557 i = 1;
558 } else if (str[0] == '+') {
559 i = 1;
560 }
561 if ((str[i] == '0') && (str[i + 1] == 'x' || str[i + 1] == 'X') &&
562 (str[i + 2] != '\0')) {
563 base = 16;
564 }
565 errno = 0;
566 if (base == 16) {
567 // Unsigned 64-bit hexadecimal integer literals are allowed but
568 // immediately interpreted as signed 64-bit integers.
569 *value = static_cast<int64_t>(strtoull(str, &endptr, base));
570 } else {
571 *value = strtoll(str, &endptr, base);
572 }
573 return ((errno == 0) && (endptr != str) && (*endptr == 0));
574}
575
577#ifndef PRODUCT
578 if (FLAG_generate_perf_events_symbols) {
580 }
581#endif // !PRODUCT
582}
583
584void OS::PrintErr(const char* format, ...) {
585 va_list args;
587 VFPrint(stderr, format, args);
588 va_end(args);
589}
590
591void OS::Init() {
592 if (async_get_default_dispatcher() == nullptr) {
593 async_loop_create(&kAsyncLoopConfigAttachToCurrentThread, &message_loop);
594 async_set_default_dispatcher(async_loop_get_dispatcher(message_loop));
595 async_loop_start_thread(message_loop, "Fuchsia async loop", nullptr);
596 }
597
598 auto vm_node = dart::TakeDartVmNode();
599
600 // TODO(fxbug.dev/69558) allow vm_node to be null and not crash
601 ASSERT(vm_node != nullptr);
602 metrics = std::make_shared<InspectMetrics>(std::move(vm_node));
603
604 InitializeTZData();
605 auto services = sys::ServiceDirectory::CreateFromNamespace();
606 services->Connect(property_provider.NewRequest());
607
608 timezone_name = TimezoneName::New(std::move(property_provider), metrics);
609}
610
611void OS::Cleanup() {
612 if (message_loop != nullptr) {
613 async_loop_shutdown(message_loop);
614 }
615 timezone_name.reset();
616 metrics.reset();
617
618 if (message_loop != nullptr) {
619 // Check message_loop is still the default dispatcher before clearing it.
620 if (async_get_default_dispatcher() ==
621 async_loop_get_dispatcher(message_loop)) {
622 async_set_default_dispatcher(nullptr);
623 }
624 async_loop_destroy(message_loop);
625 message_loop = nullptr;
626 }
627}
628
629void OS::PrepareToAbort() {}
630
631void OS::Abort() {
633 abort();
634}
635
636void OS::Exit(int code) {
637 exit(code);
638}
639
640// Used to choose between Elf32/Elf64 types based on host archotecture bitsize.
641#if defined(ARCH_IS_64_BIT)
642#define ElfW(Type) Elf64_##Type
643#else
644#define ElfW(Type) Elf32_##Type
645#endif
646
647OS::BuildId OS::GetAppBuildId(const uint8_t* snapshot_instructions) {
648 // First return the build ID information from the instructions image if
649 // available.
650 const Image instructions_image(snapshot_instructions);
651 if (auto* const image_build_id = instructions_image.build_id()) {
652 return {instructions_image.build_id_length(), image_build_id};
653 }
654 const uint8_t* dso_base = GetAppDSOBase(snapshot_instructions);
655 const ElfW(Ehdr)& elf_header = *reinterpret_cast<const ElfW(Ehdr)*>(dso_base);
656 const ElfW(Phdr)* const phdr_array =
657 reinterpret_cast<const ElfW(Phdr)*>(dso_base + elf_header.e_phoff);
658 for (intptr_t i = 0; i < elf_header.e_phnum; i++) {
659 const ElfW(Phdr)& header = phdr_array[i];
660 if (header.p_type != PT_NOTE) continue;
661 if ((header.p_flags & PF_R) != PF_R) continue;
662 const uint8_t* const note_addr = dso_base + header.p_vaddr;
663 const Elf32_Nhdr& note_header =
664 *reinterpret_cast<const Elf32_Nhdr*>(note_addr);
665 if (note_header.n_type != NT_GNU_BUILD_ID) continue;
666 const char* const note_contents =
667 reinterpret_cast<const char*>(note_addr + sizeof(Elf32_Nhdr));
668 // The note name contains the null terminator as well.
669 if (note_header.n_namesz != strlen(ELF_NOTE_GNU) + 1) continue;
670 if (strncmp(ELF_NOTE_GNU, note_contents, note_header.n_namesz) == 0) {
671 return {static_cast<intptr_t>(note_header.n_descsz),
672 reinterpret_cast<const uint8_t*>(note_contents +
673 note_header.n_namesz)};
674 }
675 }
676 return {0, nullptr};
677}
678
679} // namespace dart
680
681#endif // defined(DART_HOST_OS_FUCHSIA)
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
static DART_NORETURN void Exit(int code)
static int NumberOfAvailableProcessors()
static const char * GetTimeZoneName(int64_t seconds_since_epoch)
static void SleepMicros(int64_t micros)
static int64_t GetCurrentTimeMillis()
static void RegisterCodeObservers()
static int64_t GetCurrentMonotonicMicros()
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static void Sleep(int64_t millis)
static void Print(const char *format,...) PRINTF_ATTRIBUTE(1
static bool StringToInt64(const char *str, int64_t *value)
static BuildId GetAppBuildId(const uint8_t *snapshot_instructions)
static const uint8_t * GetAppDSOBase(const uint8_t *snapshot_instructions)
Definition: os.cc:13
static void Init()
static int64_t GetCurrentTimeMicros()
static intptr_t ActivationFrameAlignment()
static void static void static void VFPrint(FILE *stream, const char *format, va_list args)
static void Cleanup()
static void DebugBreak()
static DART_NORETURN void Abort()
static char static char * VSCreate(Zone *zone, const char *format, va_list args)
static int64_t GetCurrentThreadCPUMicros()
static uintptr_t GetProgramCounter()
static intptr_t ProcessId()
static void PrepareToAbort()
static int64_t GetCurrentMonotonicFrequency()
static char * SCreate(Zone *zone, const char *format,...) PRINTF_ATTRIBUTE(2
static int64_t GetCurrentMonotonicTicks()
static int64_t GetCurrentMonotonicMicrosForTimeline()
static int GetTimeZoneOffsetInSeconds(int64_t seconds_since_epoch)
static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static int static int VSNPrint(char *str, size_t size, const char *format, va_list args)
static constexpr bool IsPowerOfTwo(T x)
Definition: utils.h:76
#define UNIMPLEMENTED
#define ASSERT(E)
#define FATAL(error)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const uint8_t uint32_t uint32_t GError ** error
uint8_t value
uint32_t uint32_t * format
Dart_NativeFunction function
Definition: fuchsia.cc:51
const GrXPFactory * Get(SkBlendMode mode)
va_start(args, format)
exit(kErrorExitCode)
va_end(args)
static constexpr intptr_t PF_R
Definition: elf.h:181
static constexpr const char ELF_NOTE_GNU[]
Definition: elf.h:199
Definition: dart_vm.cc:33
constexpr intptr_t kMicrosecondsPerMillisecond
Definition: globals.h:561
constexpr intptr_t kNanosecondsPerMicrosecond
Definition: globals.h:564
void * malloc(size_t size)
Definition: allocation.cc:19
constexpr intptr_t kNanosecondsPerSecond
Definition: globals.h:567
DEFINE_FLAG(bool, print_cluster_information, false, "Print information about clusters written to snapshot")
std::unique_ptr< inspect::Node > TakeDartVmNode()
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
CanvasImage Image
Definition: dart_ui.cc:55
Definition: ref_ptr.h:256
static const char header[]
Definition: skpbench.cpp:88