1// Copyright 2016 The Fuchsia Authors
2// Copyright (c) 2013 Google, Inc.
3//
4// Use of this source code is governed by a MIT-style
5// license that can be found in the LICENSE file or at
6// https://opensource.org/licenses/MIT
7
8#include <lib/version.h>
9
10#include <debug.h>
11#include <lk/init.h>
12#include <stdint.h>
13#include <stdio.h>
14#include <string.h>
15
16/* generated for us */
17#include <config-buildid.h>
18
19/* ARCH, PLATFORM, TARGET, PROJECT should be defined by the build system */
20
21/* BUILDID is optional, and may be defined anywhere */
22#ifndef BUILDID
23#define BUILDID ""
24#endif
25
26// If the build ID were SHA256, it would be 32 bytes.
27// (The algorithms used for build IDs today actually produce fewer than that.)
28// This string needs 2 bytes to print each byte in hex, plus a NUL terminator.
29static char elf_build_id_string[65];
30
31const lk_version_t version = {
32    .struct_version = VERSION_STRUCT_VERSION,
33    .arch = ARCH,
34    .platform = PLATFORM,
35    .target = TARGET,
36    .project = PROJECT,
37    .buildid = BUILDID,
38    .elf_build_id = elf_build_id_string,
39};
40
41void print_version(void) {
42    printf("version:\n");
43    printf("\tarch:     %s\n", version.arch);
44    printf("\tplatform: %s\n", version.platform);
45    printf("\ttarget:   %s\n", version.target);
46    printf("\tproject:  %s\n", version.project);
47    printf("\tbuildid:  %s\n", version.buildid);
48    printf("\tELF build ID: %s\n", version.elf_build_id);
49}
50
51// Standard ELF note layout (Elf{32,64}_Nhdr in <elf.h>).
52// The name and type fields' values are what GNU and GNU-compatible
53// tools (i.e. everything in the Unix-like world in recent years)
54// specify for build ID notes.
55struct build_id_note {
56    uint32_t namesz;
57    uint32_t descsz;
58    uint32_t type;
59#define NT_GNU_BUILD_ID 3
60#define NOTE_NAME "GNU"
61    char name[(sizeof(NOTE_NAME) + 3) & -4];
62    uint8_t id[];
63};
64
65extern const struct build_id_note __build_id_note_start;
66extern const uint8_t __build_id_note_end[];
67
68static void init_build_id(uint level) {
69    const struct build_id_note* const note = &__build_id_note_start;
70    if (note->type != NT_GNU_BUILD_ID ||
71        note->namesz != sizeof(NOTE_NAME) ||
72        memcmp(note->name, NOTE_NAME, sizeof(NOTE_NAME)) != 0 ||
73        &note->id[note->descsz] != __build_id_note_end) {
74        panic("ELF build ID note has bad format!\n");
75    }
76    if (note->descsz * 2 >= sizeof(elf_build_id_string)) {
77        panic("ELF build ID is %u bytes, expected %u or fewer\n",
78              note->descsz, (uint32_t)(sizeof(elf_build_id_string) / 2));
79    }
80    for (uint32_t i = 0; i < note->descsz; ++i) {
81        snprintf(&elf_build_id_string[i * 2], 3, "%02x", note->id[i]);
82    }
83}
84
85// This must happen before print_version, below.
86LK_INIT_HOOK(elf_build_id, &init_build_id, LK_INIT_LEVEL_HEAP - 2);
87
88#include <debug.h>
89#include <lib/console.h>
90
91static int cmd_version(int argc, const cmd_args* argv, uint32_t flags) {
92    print_version();
93    return 0;
94}
95
96STATIC_COMMAND_START
97STATIC_COMMAND("version", "print version", &cmd_version)
98STATIC_COMMAND_END(version);
99
100#if LK_DEBUGLEVEL > 0
101static void print_version_init(uint) {
102    print_version();
103}
104
105// print the version string if any level of debug is set
106LK_INIT_HOOK(version, print_version_init, LK_INIT_LEVEL_HEAP - 1);
107#endif
108