#include "amduat/asl/asl_store_fs.h" #include "amduat/asl/asl_store_fs_meta.h" #include "amduat/asl/io.h" #include "amduat/asl/parse.h" #include "amduat/asl/ref_text.h" #include "amduat/asl/store.h" #include "amduat/enc/asl1_core_codec.h" #include "amduat/enc/pel1_result.h" #include "amduat/enc/pel_program_dag.h" #include "amduat/enc/pel_trace_dag.h" #include "amduat/hash/asl1.h" #include "amduat/pel/opreg_kernel.h" #include "amduat/pel/opreg_kernel_params.h" #include "amduat/pel/program_dag_desc.h" #include "amduat/pel/surf.h" #include "amduat/util/hex.h" #include #include #include #include #include #include #include enum { AMDUAT_PEL_CLI_EXIT_OK = 0, AMDUAT_PEL_CLI_EXIT_USAGE = 2, AMDUAT_PEL_CLI_EXIT_IO = 3, AMDUAT_PEL_CLI_EXIT_NOT_FOUND = 4, AMDUAT_PEL_CLI_EXIT_STORE = 5, AMDUAT_PEL_CLI_EXIT_UNSUPPORTED = 6, AMDUAT_PEL_CLI_EXIT_CODEC = 7, AMDUAT_PEL_CLI_EXIT_CONFIG = 8 }; static const char *const AMDUAT_PEL_CLI_DEFAULT_ROOT = ".amduat-asl"; typedef enum { AMDUAT_PEL_CLI_REF_HEX = 0, AMDUAT_PEL_CLI_REF_BYTES = 1 } amduat_pel_cli_ref_format_t; typedef enum { AMDUAT_PEL_CLI_FORMAT_TEXT = 0, AMDUAT_PEL_CLI_FORMAT_JSON = 1 } amduat_pel_cli_output_format_t; typedef enum { AMDUAT_PEL_CLI_IO_RAW = 0, AMDUAT_PEL_CLI_IO_ARTIFACT = 1 } amduat_pel_cli_io_format_t; typedef struct { const char *root; amduat_pel_cli_ref_format_t ref_format; amduat_pel_cli_output_format_t format; bool quiet; } amduat_pel_cli_global_opts_t; static void amduat_pel_cli_print_usage(FILE *stream) { fprintf(stream, "usage:\n" " amduat-pel [--root PATH] [--ref-format hex|bytes] [--format text|json]\n" " [--quiet] [args]\n" "\n" "commands:\n" " run Execute a PEL/PROGRAM-DAG/1 program via PEL/1-SURF (store-backed).\n" " exec Execute a PEL/PROGRAM-DAG/1 program in-memory (no store writes).\n" " validate Validate a Program artifact (decode + DAG checks + params).\n" " program Program DAG tools (decode, normalize).\n" " trace Trace DAG tools (decode, from-result).\n" " result Surface result tools (decode).\n" " op Kernel op registry tools.\n" " scheme Scheme refs, type tags, profile IDs.\n" " help Show help for a command.\n" "\n" "global options:\n" " --root PATH ASL store root (default .amduat-asl)\n" " --ref-format hex|bytes Reference I/O format (default hex)\n" " --format text|json Structured output format (default text)\n" " --quiet Only print machine output\n" "\n" "run:\n" " amduat-pel run --program-ref REF [--scheme-ref REF|dag]\n" " [--input-ref REF ...] [--inputs-file PATH]\n" " [--params-ref REF]\n" " [--format text|json] [--ref-format hex|bytes]\n" " Output: result_ref, trace_ref, output_refs (formatted per --format).\n" "\n" "exec:\n" " amduat-pel exec --program PATH|-\n" " [--input PATH ...] [--input-format raw|artifact]\n" " [--output-dir DIR] [--output-format raw|artifact]\n" " [--result-out PATH|-] [--format text|json]\n" "\n" "validate:\n" " amduat-pel validate [--input PATH|- | --program-ref REF]\n" " [--input-format raw|artifact]\n" " [--expect-type-tag TAG]\n" " [--format text|json]\n" "\n" "program:\n" " amduat-pel program decode [--input PATH|- | --program-ref REF]\n" " [--input-format raw|artifact]\n" " [--expect-type-tag TAG]\n" " [--format text|json]\n" " amduat-pel program normalize --input PATH|- [--input-format raw|artifact]\n" " [--output PATH|-] [--output-format raw|artifact]\n" " [--type-tag TAG]\n" "\n" "trace:\n" " amduat-pel trace decode [--input PATH|- | --trace-ref REF]\n" " [--input-format raw|artifact]\n" " [--expect-type-tag TAG]\n" " [--format text|json]\n" " amduat-pel trace from-result --result-ref REF [--root PATH]\n" " [--format text|json]\n" "\n" "result:\n" " amduat-pel result decode [--input PATH|- | --result-ref REF]\n" " [--input-format raw|artifact]\n" " [--expect-type-tag TAG]\n" " [--format text|json]\n" "\n" "op:\n" " amduat-pel op list [--format text|json]\n" " amduat-pel op describe NAME[=VERSION] [--format text|json]\n" " amduat-pel op params-decode --op NAME[=VERSION]\n" " --input PATH|- [--format text|json]\n" "\n" "scheme:\n" " amduat-pel scheme show [--format text|json]\n" " amduat-pel scheme dag-ref [--format hex|bytes]\n" "\n" "defaults:\n" " --root .amduat-asl\n" " --ref-format hex\n" " --input -\n" " --output -\n" " --input-format raw\n" " --output-format raw\n" " --scheme-ref dag\n" "\n" "notes:\n" " - Only PEL/PROGRAM-DAG/1 is supported; other scheme refs yield SCHEME_UNSUPPORTED.\n" " - Expected type tags: program 0x00000101, trace 0x00000102, result 0x00000103.\n" " - Encoding profile IDs: program 0x0101, trace 0x0102, result 0x0103.\n" " - Kernel ops: pel.bytes.concat, pel.bytes.slice, pel.bytes.const, pel.bytes.hash.asl1.\n" " - --ref-format bytes expects --ref to be a path or '-' (raw reference bytes).\n"); } static bool amduat_pel_cli_parse_ref_format( const char *text, amduat_pel_cli_ref_format_t *out_fmt) { if (text == NULL || out_fmt == NULL) { return false; } if (strcmp(text, "hex") == 0) { *out_fmt = AMDUAT_PEL_CLI_REF_HEX; return true; } if (strcmp(text, "bytes") == 0) { *out_fmt = AMDUAT_PEL_CLI_REF_BYTES; return true; } return false; } static bool amduat_pel_cli_parse_output_format( const char *text, amduat_pel_cli_output_format_t *out_fmt) { if (text == NULL || out_fmt == NULL) { return false; } if (strcmp(text, "text") == 0) { *out_fmt = AMDUAT_PEL_CLI_FORMAT_TEXT; return true; } if (strcmp(text, "json") == 0) { *out_fmt = AMDUAT_PEL_CLI_FORMAT_JSON; return true; } return false; } static bool amduat_pel_cli_parse_io_format( const char *text, amduat_pel_cli_io_format_t *out_fmt) { if (text == NULL || out_fmt == NULL) { return false; } if (strcmp(text, "raw") == 0) { *out_fmt = AMDUAT_PEL_CLI_IO_RAW; return true; } if (strcmp(text, "artifact") == 0) { *out_fmt = AMDUAT_PEL_CLI_IO_ARTIFACT; return true; } return false; } static const char *amduat_pel_cli_status_name( amduat_pel_execution_status_t status) { switch (status) { case AMDUAT_PEL_EXEC_STATUS_OK: return "OK"; case AMDUAT_PEL_EXEC_STATUS_SCHEME_UNSUPPORTED: return "SCHEME_UNSUPPORTED"; case AMDUAT_PEL_EXEC_STATUS_INVALID_PROGRAM: return "INVALID_PROGRAM"; case AMDUAT_PEL_EXEC_STATUS_INVALID_INPUTS: return "INVALID_INPUTS"; case AMDUAT_PEL_EXEC_STATUS_RUNTIME_FAILED: return "RUNTIME_FAILED"; default: return "UNKNOWN"; } } static const char *amduat_pel_cli_error_kind_name( amduat_pel_execution_error_kind_t kind) { switch (kind) { case AMDUAT_PEL_EXEC_ERROR_NONE: return "NONE"; case AMDUAT_PEL_EXEC_ERROR_SCHEME: return "SCHEME"; case AMDUAT_PEL_EXEC_ERROR_PROGRAM: return "PROGRAM"; case AMDUAT_PEL_EXEC_ERROR_INPUTS: return "INPUTS"; case AMDUAT_PEL_EXEC_ERROR_RUNTIME: return "RUNTIME"; default: return "UNKNOWN"; } } static const char *amduat_pel_cli_node_status_name( amduat_pel_node_trace_status_t status) { switch (status) { case AMDUAT_PEL_NODE_TRACE_OK: return "NODE_OK"; case AMDUAT_PEL_NODE_TRACE_FAILED: return "NODE_FAILED"; case AMDUAT_PEL_NODE_TRACE_SKIPPED: return "NODE_SKIPPED"; default: return "NODE_UNKNOWN"; } } static const char *amduat_pel_cli_store_phase_name( amduat_pel_store_failure_phase_t phase) { switch (phase) { case AMDUAT_PEL_STORE_FAILURE_PROGRAM: return "PROGRAM"; case AMDUAT_PEL_STORE_FAILURE_INPUT: return "INPUT"; default: return "UNKNOWN"; } } static const char *amduat_pel_cli_store_error_name( amduat_pel_store_error_code_t code) { switch (code) { case AMDUAT_PEL_STORE_ERROR_NOT_FOUND: return "NOT_FOUND"; case AMDUAT_PEL_STORE_ERROR_INTEGRITY: return "INTEGRITY"; case AMDUAT_PEL_STORE_ERROR_UNSUPPORTED: return "UNSUPPORTED"; default: return "UNKNOWN"; } } static const char *amduat_pel_cli_store_error_str( amduat_asl_store_error_t err) { switch (err) { case AMDUAT_ASL_STORE_ERR_NOT_FOUND: return "not found"; case AMDUAT_ASL_STORE_ERR_UNSUPPORTED: return "unsupported"; case AMDUAT_ASL_STORE_ERR_INTEGRITY: return "integrity"; case AMDUAT_ASL_STORE_OK: return "ok"; default: return "unknown"; } } static int amduat_pel_cli_map_store_error(amduat_asl_store_error_t err) { switch (err) { case AMDUAT_ASL_STORE_ERR_NOT_FOUND: return AMDUAT_PEL_CLI_EXIT_NOT_FOUND; case AMDUAT_ASL_STORE_ERR_UNSUPPORTED: return AMDUAT_PEL_CLI_EXIT_UNSUPPORTED; case AMDUAT_ASL_STORE_ERR_INTEGRITY: return AMDUAT_PEL_CLI_EXIT_STORE; case AMDUAT_ASL_STORE_OK: default: return AMDUAT_PEL_CLI_EXIT_STORE; } } static void amduat_pel_cli_free_reference(amduat_reference_t *ref) { if (ref == NULL) { return; } free((void *)ref->digest.data); ref->digest.data = NULL; ref->digest.len = 0u; } static void amduat_pel_cli_free_artifact(amduat_artifact_t *artifact) { if (artifact == NULL) { return; } free((void *)artifact->bytes.data); artifact->bytes.data = NULL; artifact->bytes.len = 0u; } static void amduat_pel_cli_free_refs(amduat_reference_t *refs, size_t refs_len) { size_t i; if (refs == NULL) { return; } for (i = 0; i < refs_len; ++i) { amduat_pel_cli_free_reference(&refs[i]); } free(refs); } static bool amduat_pel_cli_read_path_once(const char *path, bool *stdin_used, uint8_t **out_bytes, size_t *out_len) { if (path == NULL || out_bytes == NULL || out_len == NULL) { return false; } if (strcmp(path, "-") == 0 && stdin_used != NULL) { if (*stdin_used) { return false; } *stdin_used = true; } return amduat_asl_read_path(path, out_bytes, out_len); } static char *amduat_pel_cli_hex_encode(amduat_octets_t bytes) { size_t out_len; char *out; out_len = amduat_hex_encoded_size(bytes.len); out = (char *)malloc(out_len); if (out == NULL) { return NULL; } if (!amduat_hex_encode_lower(bytes.data, bytes.len, out, out_len)) { free(out); return NULL; } return out; } static bool amduat_pel_cli_ref_to_text(amduat_reference_t ref, amduat_pel_cli_ref_format_t fmt, char **out_text) { if (out_text == NULL) { return false; } *out_text = NULL; if (fmt == AMDUAT_PEL_CLI_REF_HEX) { return amduat_asl_ref_encode_hex(ref, out_text); } { amduat_octets_t encoded; char *hex; if (!amduat_enc_asl1_core_encode_reference_v1(ref, &encoded)) { return false; } hex = amduat_pel_cli_hex_encode(encoded); free((void *)encoded.data); if (hex == NULL) { return false; } *out_text = hex; return true; } } static bool amduat_pel_cli_ref_from_text(const char *text, amduat_pel_cli_ref_format_t fmt, bool *stdin_used, amduat_reference_t *out_ref) { if (text == NULL || out_ref == NULL) { return false; } memset(out_ref, 0, sizeof(*out_ref)); if (fmt == AMDUAT_PEL_CLI_REF_HEX) { return amduat_asl_ref_decode_hex(text, out_ref); } { uint8_t *bytes = NULL; size_t len = 0; if (!amduat_pel_cli_read_path_once(text, stdin_used, &bytes, &len)) { return false; } if (!amduat_asl_ref_decode_bytes(bytes, len, out_ref)) { free(bytes); return false; } free(bytes); } return true; } static bool amduat_pel_cli_append_ref(amduat_reference_t **refs, size_t *refs_len, amduat_reference_t ref) { amduat_reference_t *next; if (refs == NULL || refs_len == NULL) { return false; } next = (amduat_reference_t *)realloc( *refs, (*refs_len + 1u) * sizeof(**refs)); if (next == NULL) { return false; } next[*refs_len] = ref; *refs = next; *refs_len += 1u; return true; } static bool amduat_pel_cli_append_refs_from_file( const char *path, amduat_pel_cli_ref_format_t fmt, bool *stdin_used, amduat_reference_t **refs, size_t *refs_len) { uint8_t *bytes = NULL; size_t len = 0; size_t i = 0; if (!amduat_pel_cli_read_path_once(path, stdin_used, &bytes, &len)) { return false; } while (i < len) { size_t start; size_t token_len; char *token; amduat_reference_t ref; while (i < len && isspace((unsigned char)bytes[i])) { ++i; } if (i >= len) { break; } start = i; while (i < len && !isspace((unsigned char)bytes[i])) { ++i; } token_len = i - start; token = (char *)malloc(token_len + 1u); if (token == NULL) { free(bytes); return false; } memcpy(token, bytes + start, token_len); token[token_len] = '\0'; if (!amduat_pel_cli_ref_from_text(token, fmt, stdin_used, &ref)) { free(token); free(bytes); return false; } free(token); if (!amduat_pel_cli_append_ref(refs, refs_len, ref)) { amduat_pel_cli_free_reference(&ref); free(bytes); return false; } } free(bytes); return true; } static void amduat_pel_cli_json_escape(FILE *stream, const uint8_t *data, size_t len) { size_t i; fputc('"', stream); for (i = 0; i < len; ++i) { uint8_t c = data[i]; switch (c) { case '"': fputs("\\\"", stream); break; case '\\': fputs("\\\\", stream); break; case '\b': fputs("\\b", stream); break; case '\f': fputs("\\f", stream); break; case '\n': fputs("\\n", stream); break; case '\r': fputs("\\r", stream); break; case '\t': fputs("\\t", stream); break; default: if (c < 0x20) { fprintf(stream, "\\u%04x", (unsigned int)c); } else { fputc((int)c, stream); } break; } } fputc('"', stream); } static bool amduat_pel_cli_print_ref_text(FILE *stream, amduat_reference_t ref, amduat_pel_cli_ref_format_t fmt) { char *ref_text = NULL; if (!amduat_pel_cli_ref_to_text(ref, fmt, &ref_text)) { return false; } fputs(ref_text, stream); free(ref_text); return true; } static bool amduat_pel_cli_print_ref_json(FILE *stream, amduat_reference_t ref, amduat_pel_cli_ref_format_t fmt) { char *ref_text = NULL; if (!amduat_pel_cli_ref_to_text(ref, fmt, &ref_text)) { return false; } amduat_pel_cli_json_escape(stream, (const uint8_t *)ref_text, strlen(ref_text)); free(ref_text); return true; } static bool amduat_pel_cli_parse_op_name(const char *text, const char **out_name, uint32_t *out_version) { const char *eq; if (text == NULL || out_name == NULL || out_version == NULL) { return false; } eq = strchr(text, '='); if (eq == NULL) { *out_name = text; *out_version = 1; return true; } { size_t name_len = (size_t)(eq - text); char *name; uint32_t version; if (name_len == 0) { return false; } if (!amduat_asl_parse_u32(eq + 1, &version)) { return false; } name = (char *)malloc(name_len + 1u); if (name == NULL) { return false; } memcpy(name, text, name_len); name[name_len] = '\0'; *out_name = name; *out_version = version; return true; } } static void amduat_pel_cli_free_op_name(const char *name, const char *original) { if (name != NULL && name != original) { free((void *)name); } } static bool amduat_pel_cli_print_program_text( FILE *stream, const amduat_pel_program_t *program) { size_t i; if (program == NULL) { return false; } fprintf(stream, "nodes_len=%zu\n", program->nodes_len); fprintf(stream, "roots_len=%zu\n", program->roots_len); for (i = 0; i < program->nodes_len; ++i) { const amduat_pel_node_t *node = &program->nodes[i]; size_t j; char *params_hex; fprintf(stream, "node[%zu].id=%u\n", i, node->id); fprintf(stream, "node[%zu].op.name=%.*s\n", i, (int)node->op.name.len, node->op.name.data ? (const char *)node->op.name.data : ""); fprintf(stream, "node[%zu].op.version=%u\n", i, node->op.version); fprintf(stream, "node[%zu].inputs_len=%zu\n", i, node->inputs_len); for (j = 0; j < node->inputs_len; ++j) { const amduat_pel_dag_input_t *input = &node->inputs[j]; if (input->kind == AMDUAT_PEL_DAG_INPUT_EXTERNAL) { fprintf(stream, "node[%zu].input[%zu].kind=external\n", i, j); fprintf(stream, "node[%zu].input[%zu].external.input_index=%u\n", i, j, input->value.external.input_index); } else { fprintf(stream, "node[%zu].input[%zu].kind=node\n", i, j); fprintf(stream, "node[%zu].input[%zu].node.node_id=%u\n", i, j, input->value.node.node_id); fprintf(stream, "node[%zu].input[%zu].node.output_index=%u\n", i, j, input->value.node.output_index); } } params_hex = amduat_pel_cli_hex_encode(node->params); if (params_hex == NULL) { return false; } fprintf(stream, "node[%zu].params_len=%zu\n", i, node->params.len); fprintf(stream, "node[%zu].params_hex=%s\n", i, params_hex); free(params_hex); } for (i = 0; i < program->roots_len; ++i) { fprintf(stream, "root[%zu].node_id=%u\n", i, program->roots[i].node_id); fprintf(stream, "root[%zu].output_index=%u\n", i, program->roots[i].output_index); } return true; } static bool amduat_pel_cli_print_program_json( FILE *stream, const amduat_pel_program_t *program) { size_t i; if (program == NULL) { return false; } fputs("{\"nodes\":[", stream); for (i = 0; i < program->nodes_len; ++i) { const amduat_pel_node_t *node = &program->nodes[i]; size_t j; char *params_hex; if (i != 0) { fputc(',', stream); } fputs("{\"id\":", stream); fprintf(stream, "%u", node->id); fputs(",\"op\":{\"name\":", stream); amduat_pel_cli_json_escape(stream, node->op.name.data, node->op.name.len); fprintf(stream, ",\"version\":%u}", node->op.version); fputs(",\"inputs\":[", stream); for (j = 0; j < node->inputs_len; ++j) { const amduat_pel_dag_input_t *input = &node->inputs[j]; if (j != 0) { fputc(',', stream); } if (input->kind == AMDUAT_PEL_DAG_INPUT_EXTERNAL) { fprintf(stream, "{\"kind\":\"external\",\"input_index\":%u}", input->value.external.input_index); } else { fprintf(stream, "{\"kind\":\"node\",\"node_id\":%u,\"output_index\":%u}", input->value.node.node_id, input->value.node.output_index); } } fputs("]", stream); params_hex = amduat_pel_cli_hex_encode(node->params); if (params_hex == NULL) { return false; } fputs(",\"params_hex\":", stream); amduat_pel_cli_json_escape(stream, (const uint8_t *)params_hex, strlen(params_hex)); free(params_hex); fputs("}", stream); } fputs("],\"roots\":[", stream); for (i = 0; i < program->roots_len; ++i) { if (i != 0) { fputc(',', stream); } fprintf(stream, "{\"node_id\":%u,\"output_index\":%u}", program->roots[i].node_id, program->roots[i].output_index); } fputs("]}", stream); return true; } static bool amduat_pel_cli_print_diagnostics_text( FILE *stream, const char *prefix, const amduat_pel_diagnostic_entry_t *diags, size_t diags_len) { size_t i; if (diags_len == 0) { return true; } if (prefix == NULL) { prefix = ""; } for (i = 0; i < diags_len; ++i) { char *msg_hex = amduat_pel_cli_hex_encode(diags[i].message); if (msg_hex == NULL) { return false; } fprintf(stream, "%sdiagnostic[%zu].code=%u\n", prefix, i, diags[i].code); fprintf(stream, "%sdiagnostic[%zu].message_hex=%s\n", prefix, i, msg_hex); free(msg_hex); } return true; } static bool amduat_pel_cli_print_diagnostics_json( FILE *stream, const amduat_pel_diagnostic_entry_t *diags, size_t diags_len) { size_t i; fputs("[", stream); for (i = 0; i < diags_len; ++i) { char *msg_hex = amduat_pel_cli_hex_encode(diags[i].message); if (msg_hex == NULL) { return false; } if (i != 0) { fputc(',', stream); } fprintf(stream, "{\"code\":%u,\"message_hex\":", diags[i].code); amduat_pel_cli_json_escape(stream, (const uint8_t *)msg_hex, strlen(msg_hex)); fputs("}", stream); free(msg_hex); } fputs("]", stream); return true; } static bool amduat_pel_cli_print_trace_text( FILE *stream, const amduat_pel_trace_dag_value_t *trace, amduat_pel_cli_ref_format_t ref_format) { size_t i; if (trace == NULL) { return false; } fprintf(stream, "pel1_version=%u\n", trace->pel1_version); fprintf(stream, "scheme_ref="); if (!amduat_pel_cli_print_ref_text(stream, trace->scheme_ref, ref_format)) { return false; } fputc('\n', stream); fprintf(stream, "program_ref="); if (!amduat_pel_cli_print_ref_text(stream, trace->program_ref, ref_format)) { return false; } fputc('\n', stream); fprintf(stream, "status=%s(%u)\n", amduat_pel_cli_status_name(trace->status), (unsigned int)trace->status); fprintf(stream, "error_kind=%s(%u)\n", amduat_pel_cli_error_kind_name(trace->summary.kind), (unsigned int)trace->summary.kind); fprintf(stream, "status_code=%u\n", (unsigned int)trace->summary.status_code); fprintf(stream, "has_exec_result_ref=%s\n", trace->has_exec_result_ref ? "true" : "false"); if (trace->has_exec_result_ref) { fprintf(stream, "exec_result_ref="); if (!amduat_pel_cli_print_ref_text(stream, trace->exec_result_ref, ref_format)) { return false; } fputc('\n', stream); } fprintf(stream, "input_refs_len=%zu\n", trace->input_refs_len); for (i = 0; i < trace->input_refs_len; ++i) { fprintf(stream, "input_ref[%zu]=", i); if (!amduat_pel_cli_print_ref_text(stream, trace->input_refs[i], ref_format)) { return false; } fputc('\n', stream); } fprintf(stream, "has_params_ref=%s\n", trace->has_params_ref ? "true" : "false"); if (trace->has_params_ref) { fprintf(stream, "params_ref="); if (!amduat_pel_cli_print_ref_text(stream, trace->params_ref, ref_format)) { return false; } fputc('\n', stream); } fprintf(stream, "node_traces_len=%zu\n", trace->node_traces_len); for (i = 0; i < trace->node_traces_len; ++i) { const amduat_pel_node_trace_dag_t *node = &trace->node_traces[i]; size_t j; fprintf(stream, "node_trace[%zu].node_id=%u\n", i, node->node_id); fprintf(stream, "node_trace[%zu].op.name=%.*s\n", i, (int)node->op_name.len, node->op_name.data ? (const char *)node->op_name.data : ""); fprintf(stream, "node_trace[%zu].op.version=%u\n", i, node->op_version); fprintf(stream, "node_trace[%zu].status=%s(%u)\n", i, amduat_pel_cli_node_status_name(node->status), (unsigned int)node->status); fprintf(stream, "node_trace[%zu].status_code=%u\n", i, node->status_code); fprintf(stream, "node_trace[%zu].output_refs_len=%zu\n", i, node->output_refs_len); for (j = 0; j < node->output_refs_len; ++j) { fprintf(stream, "node_trace[%zu].output_ref[%zu]=", i, j); if (!amduat_pel_cli_print_ref_text(stream, node->output_refs[j], ref_format)) { return false; } fputc('\n', stream); } { char prefix[64]; fprintf(stream, "node_trace[%zu].diagnostics_len=%zu\n", i, node->diagnostics_len); snprintf(prefix, sizeof(prefix), "node_trace[%zu].", i); if (!amduat_pel_cli_print_diagnostics_text( stream, prefix, node->diagnostics, node->diagnostics_len)) { return false; } } } return true; } static bool amduat_pel_cli_print_trace_json( FILE *stream, const amduat_pel_trace_dag_value_t *trace, amduat_pel_cli_ref_format_t ref_format) { size_t i; if (trace == NULL) { return false; } fputs("{\"pel1_version\":", stream); fprintf(stream, "%u", trace->pel1_version); fputs(",\"scheme_ref\":", stream); if (!amduat_pel_cli_print_ref_json(stream, trace->scheme_ref, ref_format)) { return false; } fputs(",\"program_ref\":", stream); if (!amduat_pel_cli_print_ref_json(stream, trace->program_ref, ref_format)) { return false; } fputs(",\"status\":", stream); amduat_pel_cli_json_escape( stream, (const uint8_t *)amduat_pel_cli_status_name(trace->status), strlen(amduat_pel_cli_status_name(trace->status))); fprintf(stream, ",\"status_code\":%u", (unsigned int)trace->summary.status_code); fputs(",\"error_kind\":", stream); amduat_pel_cli_json_escape( stream, (const uint8_t *)amduat_pel_cli_error_kind_name(trace->summary.kind), strlen(amduat_pel_cli_error_kind_name(trace->summary.kind))); fprintf(stream, ",\"error_kind_code\":%u", (unsigned int)trace->summary.kind); fputs(",\"has_exec_result_ref\":", stream); fputs(trace->has_exec_result_ref ? "true" : "false", stream); fputs(",\"exec_result_ref\":", stream); if (trace->has_exec_result_ref) { if (!amduat_pel_cli_print_ref_json(stream, trace->exec_result_ref, ref_format)) { return false; } } else { fputs("null", stream); } fputs(",\"input_refs\":[", stream); for (i = 0; i < trace->input_refs_len; ++i) { if (i != 0) { fputc(',', stream); } if (!amduat_pel_cli_print_ref_json(stream, trace->input_refs[i], ref_format)) { return false; } } fputs("]", stream); fputs(",\"has_params_ref\":", stream); fputs(trace->has_params_ref ? "true" : "false", stream); fputs(",\"params_ref\":", stream); if (trace->has_params_ref) { if (!amduat_pel_cli_print_ref_json(stream, trace->params_ref, ref_format)) { return false; } } else { fputs("null", stream); } fputs(",\"node_traces\":[", stream); for (i = 0; i < trace->node_traces_len; ++i) { const amduat_pel_node_trace_dag_t *node = &trace->node_traces[i]; size_t j; if (i != 0) { fputc(',', stream); } fprintf(stream, "{\"node_id\":%u,", node->node_id); fputs("\"op\":{\"name\":", stream); amduat_pel_cli_json_escape(stream, node->op_name.data, node->op_name.len); fprintf(stream, ",\"version\":%u},", node->op_version); fputs("\"status\":", stream); amduat_pel_cli_json_escape( stream, (const uint8_t *)amduat_pel_cli_node_status_name(node->status), strlen(amduat_pel_cli_node_status_name(node->status))); fprintf(stream, ",\"status_code\":%u", node->status_code); fputs(",\"output_refs\":[", stream); for (j = 0; j < node->output_refs_len; ++j) { if (j != 0) { fputc(',', stream); } if (!amduat_pel_cli_print_ref_json(stream, node->output_refs[j], ref_format)) { return false; } } fputs("],\"diagnostics\":", stream); if (!amduat_pel_cli_print_diagnostics_json(stream, node->diagnostics, node->diagnostics_len)) { return false; } fputs("}", stream); } fputs("]}", stream); return true; } static bool amduat_pel_cli_print_result_text( FILE *stream, const amduat_pel_surface_execution_result_t *result, amduat_pel_cli_ref_format_t ref_format) { size_t i; if (result == NULL) { return false; } fprintf(stream, "pel1_version=%u\n", result->pel1_version); fprintf(stream, "scheme_ref="); if (!amduat_pel_cli_print_ref_text(stream, result->scheme_ref, ref_format)) { return false; } fputc('\n', stream); fprintf(stream, "program_ref="); if (!amduat_pel_cli_print_ref_text(stream, result->program_ref, ref_format)) { return false; } fputc('\n', stream); fprintf(stream, "status=%s(%u)\n", amduat_pel_cli_status_name(result->core_result.status), (unsigned int)result->core_result.status); fprintf(stream, "error_kind=%s(%u)\n", amduat_pel_cli_error_kind_name(result->core_result.summary.kind), (unsigned int)result->core_result.summary.kind); fprintf(stream, "status_code=%u\n", (unsigned int)result->core_result.summary.status_code); if (!amduat_pel_cli_print_diagnostics_text( stream, "", result->core_result.diagnostics, result->core_result.diagnostics_len)) { return false; } fprintf(stream, "input_refs_len=%zu\n", result->input_refs_len); for (i = 0; i < result->input_refs_len; ++i) { fprintf(stream, "input_ref[%zu]=", i); if (!amduat_pel_cli_print_ref_text(stream, result->input_refs[i], ref_format)) { return false; } fputc('\n', stream); } fprintf(stream, "output_refs_len=%zu\n", result->output_refs_len); for (i = 0; i < result->output_refs_len; ++i) { fprintf(stream, "output_ref[%zu]=", i); if (!amduat_pel_cli_print_ref_text(stream, result->output_refs[i], ref_format)) { return false; } fputc('\n', stream); } fprintf(stream, "has_params_ref=%s\n", result->has_params_ref ? "true" : "false"); if (result->has_params_ref) { fprintf(stream, "params_ref="); if (!amduat_pel_cli_print_ref_text(stream, result->params_ref, ref_format)) { return false; } fputc('\n', stream); } fprintf(stream, "has_trace_ref=%s\n", result->has_trace_ref ? "true" : "false"); if (result->has_trace_ref) { fprintf(stream, "trace_ref="); if (!amduat_pel_cli_print_ref_text(stream, result->trace_ref, ref_format)) { return false; } fputc('\n', stream); } fprintf(stream, "has_store_failure=%s\n", result->has_store_failure ? "true" : "false"); if (result->has_store_failure) { fprintf(stream, "store_failure.phase=%s(%u)\n", amduat_pel_cli_store_phase_name(result->store_failure.phase), (unsigned int)result->store_failure.phase); fprintf(stream, "store_failure.error_code=%s(%u)\n", amduat_pel_cli_store_error_name(result->store_failure.error_code), (unsigned int)result->store_failure.error_code); fprintf(stream, "store_failure.failing_ref="); if (!amduat_pel_cli_print_ref_text( stream, result->store_failure.failing_ref, ref_format)) { return false; } fputc('\n', stream); } return true; } static bool amduat_pel_cli_print_result_json( FILE *stream, const amduat_pel_surface_execution_result_t *result, amduat_pel_cli_ref_format_t ref_format) { size_t i; if (result == NULL) { return false; } fputs("{\"pel1_version\":", stream); fprintf(stream, "%u", result->pel1_version); fputs(",\"scheme_ref\":", stream); if (!amduat_pel_cli_print_ref_json(stream, result->scheme_ref, ref_format)) { return false; } fputs(",\"program_ref\":", stream); if (!amduat_pel_cli_print_ref_json(stream, result->program_ref, ref_format)) { return false; } fputs(",\"status\":", stream); amduat_pel_cli_json_escape( stream, (const uint8_t *)amduat_pel_cli_status_name(result->core_result.status), strlen(amduat_pel_cli_status_name(result->core_result.status))); fprintf(stream, ",\"status_code\":%u", (unsigned int)result->core_result.summary.status_code); fputs(",\"error_kind\":", stream); amduat_pel_cli_json_escape( stream, (const uint8_t *)amduat_pel_cli_error_kind_name( result->core_result.summary.kind), strlen(amduat_pel_cli_error_kind_name( result->core_result.summary.kind))); fprintf(stream, ",\"error_kind_code\":%u", (unsigned int)result->core_result.summary.kind); fputs(",\"diagnostics\":", stream); if (!amduat_pel_cli_print_diagnostics_json( stream, result->core_result.diagnostics, result->core_result.diagnostics_len)) { return false; } fputs(",\"input_refs\":[", stream); for (i = 0; i < result->input_refs_len; ++i) { if (i != 0) { fputc(',', stream); } if (!amduat_pel_cli_print_ref_json(stream, result->input_refs[i], ref_format)) { return false; } } fputs("]", stream); fputs(",\"output_refs\":[", stream); for (i = 0; i < result->output_refs_len; ++i) { if (i != 0) { fputc(',', stream); } if (!amduat_pel_cli_print_ref_json(stream, result->output_refs[i], ref_format)) { return false; } } fputs("]", stream); fputs(",\"has_params_ref\":", stream); fputs(result->has_params_ref ? "true" : "false", stream); fputs(",\"params_ref\":", stream); if (result->has_params_ref) { if (!amduat_pel_cli_print_ref_json(stream, result->params_ref, ref_format)) { return false; } } else { fputs("null", stream); } fputs(",\"has_trace_ref\":", stream); fputs(result->has_trace_ref ? "true" : "false", stream); fputs(",\"trace_ref\":", stream); if (result->has_trace_ref) { if (!amduat_pel_cli_print_ref_json(stream, result->trace_ref, ref_format)) { return false; } } else { fputs("null", stream); } fputs(",\"has_store_failure\":", stream); fputs(result->has_store_failure ? "true" : "false", stream); fputs(",\"store_failure\":", stream); if (result->has_store_failure) { fputs("{\"phase\":", stream); amduat_pel_cli_json_escape( stream, (const uint8_t *)amduat_pel_cli_store_phase_name( result->store_failure.phase), strlen(amduat_pel_cli_store_phase_name(result->store_failure.phase))); fprintf(stream, ",\"phase_code\":%u", (unsigned int)result->store_failure.phase); fputs(",\"error_code\":", stream); amduat_pel_cli_json_escape( stream, (const uint8_t *)amduat_pel_cli_store_error_name( result->store_failure.error_code), strlen(amduat_pel_cli_store_error_name( result->store_failure.error_code))); fprintf(stream, ",\"error_code_id\":%u", (unsigned int)result->store_failure.error_code); fputs(",\"failing_ref\":", stream); if (!amduat_pel_cli_print_ref_json(stream, result->store_failure.failing_ref, ref_format)) { return false; } fputs("}", stream); } else { fputs("null", stream); } fputs("}", stream); return true; } static int amduat_pel_cli_cmd_run(int argc, char **argv, const amduat_pel_cli_global_opts_t *global) { const char *program_ref_text = NULL; const char *scheme_ref_text = "dag"; const char *params_ref_text = NULL; const char *inputs_file = NULL; const char **input_ref_texts = NULL; size_t input_ref_texts_len = 0; amduat_pel_cli_ref_format_t ref_format; amduat_pel_cli_output_format_t format; const char *root; bool quiet; bool has_params_ref = false; amduat_reference_t program_ref; amduat_reference_t scheme_ref; amduat_reference_t params_ref; amduat_reference_t *input_refs = NULL; size_t input_refs_len = 0; amduat_reference_t *output_refs = NULL; size_t output_refs_len = 0; amduat_reference_t result_ref; amduat_reference_t trace_ref; amduat_artifact_t result_artifact; amduat_pel_surface_execution_result_t result_value; bool has_result_value = false; bool has_trace_ref = false; amduat_asl_store_fs_config_t cfg; amduat_asl_store_fs_t fs; amduat_asl_store_t store; bool stdin_used = false; int exit_code = AMDUAT_PEL_CLI_EXIT_OK; int i; if (global == NULL) { return AMDUAT_PEL_CLI_EXIT_USAGE; } root = global->root; ref_format = global->ref_format; format = global->format; quiet = global->quiet; for (i = 0; i < argc; ++i) { if (strcmp(argv[i], "--program-ref") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --program-ref requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } program_ref_text = argv[++i]; } else if (strcmp(argv[i], "--scheme-ref") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --scheme-ref requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } scheme_ref_text = argv[++i]; } else if (strcmp(argv[i], "--input-ref") == 0) { const char **next; if (i + 1 >= argc) { fprintf(stderr, "error: --input-ref requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } next = (const char **)realloc( input_ref_texts, (input_ref_texts_len + 1u) * sizeof(*input_ref_texts)); if (next == NULL) { fprintf(stderr, "error: out of memory\n"); return AMDUAT_PEL_CLI_EXIT_STORE; } input_ref_texts = next; input_ref_texts[input_ref_texts_len++] = argv[++i]; } else if (strcmp(argv[i], "--inputs-file") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --inputs-file requires a path\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } inputs_file = argv[++i]; } else if (strcmp(argv[i], "--params-ref") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --params-ref requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } params_ref_text = argv[++i]; has_params_ref = true; } else if (strcmp(argv[i], "--format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_output_format(argv[++i], &format)) { fprintf(stderr, "error: invalid format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--ref-format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --ref-format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_ref_format(argv[++i], &ref_format)) { fprintf(stderr, "error: invalid ref-format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--root") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --root requires a path\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } root = argv[++i]; } else if (strcmp(argv[i], "--quiet") == 0) { quiet = true; } else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { amduat_pel_cli_print_usage(stdout); return AMDUAT_PEL_CLI_EXIT_OK; } else { fprintf(stderr, "error: unknown option: %s\n", argv[i]); return AMDUAT_PEL_CLI_EXIT_USAGE; } } if (program_ref_text == NULL) { fprintf(stderr, "error: --program-ref is required\n"); free(input_ref_texts); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_asl_store_fs_load_config(root, &cfg)) { fprintf(stderr, "error: failed to load store config: %s\n", root); free(input_ref_texts); return AMDUAT_PEL_CLI_EXIT_CONFIG; } if (!amduat_asl_store_fs_init(&fs, cfg.config, root)) { fprintf(stderr, "error: failed to initialize store\n"); free(input_ref_texts); return AMDUAT_PEL_CLI_EXIT_CONFIG; } amduat_asl_store_init(&store, cfg.config, amduat_asl_store_fs_ops(), &fs); if (!amduat_pel_cli_ref_from_text(program_ref_text, ref_format, &stdin_used, &program_ref)) { fprintf(stderr, "error: invalid --program-ref\n"); free(input_ref_texts); return AMDUAT_PEL_CLI_EXIT_CODEC; } if (strcmp(scheme_ref_text, "dag") == 0) { scheme_ref = amduat_pel_program_dag_scheme_ref(); } else if (!amduat_pel_cli_ref_from_text(scheme_ref_text, ref_format, &stdin_used, &scheme_ref)) { amduat_pel_cli_free_reference(&program_ref); free(input_ref_texts); fprintf(stderr, "error: invalid --scheme-ref\n"); return AMDUAT_PEL_CLI_EXIT_CODEC; } if (has_params_ref) { if (!amduat_pel_cli_ref_from_text(params_ref_text, ref_format, &stdin_used, ¶ms_ref)) { amduat_pel_cli_free_reference(&program_ref); if (strcmp(scheme_ref_text, "dag") != 0) { amduat_pel_cli_free_reference(&scheme_ref); } free(input_ref_texts); fprintf(stderr, "error: invalid --params-ref\n"); return AMDUAT_PEL_CLI_EXIT_CODEC; } } else { memset(¶ms_ref, 0, sizeof(params_ref)); } for (i = 0; i < (int)input_ref_texts_len; ++i) { amduat_reference_t ref; if (!amduat_pel_cli_ref_from_text(input_ref_texts[i], ref_format, &stdin_used, &ref)) { fprintf(stderr, "error: invalid --input-ref\n"); exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; goto run_cleanup; } if (!amduat_pel_cli_append_ref(&input_refs, &input_refs_len, ref)) { amduat_pel_cli_free_reference(&ref); fprintf(stderr, "error: out of memory\n"); exit_code = AMDUAT_PEL_CLI_EXIT_STORE; goto run_cleanup; } } if (inputs_file != NULL) { if (!amduat_pel_cli_append_refs_from_file(inputs_file, ref_format, &stdin_used, &input_refs, &input_refs_len)) { fprintf(stderr, "error: failed to read inputs file\n"); exit_code = AMDUAT_PEL_CLI_EXIT_IO; goto run_cleanup; } } memset(&result_ref, 0, sizeof(result_ref)); if (!amduat_pel_surf_run(&store, scheme_ref, program_ref, input_refs, input_refs_len, has_params_ref, params_ref, &output_refs, &output_refs_len, &result_ref)) { fprintf(stderr, "error: PEL surface execution failed\n"); exit_code = AMDUAT_PEL_CLI_EXIT_STORE; goto run_cleanup; } memset(&trace_ref, 0, sizeof(trace_ref)); memset(&result_artifact, 0, sizeof(result_artifact)); if (amduat_asl_store_get(&store, result_ref, &result_artifact) == AMDUAT_ASL_STORE_OK) { if (amduat_enc_pel1_result_decode_v1(result_artifact.bytes, &result_value)) { has_result_value = true; if (result_value.has_trace_ref) { trace_ref = result_value.trace_ref; has_trace_ref = true; } } } if (!quiet) { fprintf(stderr, "root=%s\n", root); fprintf(stderr, "program_ref="); if (!amduat_pel_cli_print_ref_text(stderr, program_ref, ref_format)) { fprintf(stderr, "\n"); } else { fputc('\n', stderr); } if (has_params_ref) { fprintf(stderr, "params_ref="); if (!amduat_pel_cli_print_ref_text(stderr, params_ref, ref_format)) { fprintf(stderr, "\n"); } else { fputc('\n', stderr); } } if (has_result_value) { fprintf(stderr, "status=%s(%u)\n", amduat_pel_cli_status_name(result_value.core_result.status), (unsigned int)result_value.core_result.status); fprintf(stderr, "error_kind=%s(%u)\n", amduat_pel_cli_error_kind_name( result_value.core_result.summary.kind), (unsigned int)result_value.core_result.summary.kind); fprintf(stderr, "status_code=%u\n", (unsigned int)result_value.core_result.summary.status_code); } } if (format == AMDUAT_PEL_CLI_FORMAT_TEXT) { fprintf(stdout, "result_ref="); if (!amduat_pel_cli_print_ref_text(stdout, result_ref, ref_format)) { fprintf(stderr, "error: failed to encode result ref\n"); exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; goto run_cleanup; } fputc('\n', stdout); if (has_trace_ref) { fprintf(stdout, "trace_ref="); if (!amduat_pel_cli_print_ref_text(stdout, trace_ref, ref_format)) { fprintf(stderr, "error: failed to encode trace ref\n"); exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; goto run_cleanup; } fputc('\n', stdout); } for (i = 0; i < (int)output_refs_len; ++i) { fprintf(stdout, "output_ref[%d]=", i); if (!amduat_pel_cli_print_ref_text(stdout, output_refs[i], ref_format)) { fprintf(stderr, "error: failed to encode output ref\n"); exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; goto run_cleanup; } fputc('\n', stdout); } } else { fputs("{\"ref_format\":\"", stdout); fputs(ref_format == AMDUAT_PEL_CLI_REF_HEX ? "hex" : "bytes", stdout); fputs("\",\"result_ref\":", stdout); if (!amduat_pel_cli_print_ref_json(stdout, result_ref, ref_format)) { fprintf(stderr, "error: failed to encode result ref\n"); exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; goto run_cleanup; } fputs(",\"trace_ref\":", stdout); if (has_trace_ref) { if (!amduat_pel_cli_print_ref_json(stdout, trace_ref, ref_format)) { fprintf(stderr, "error: failed to encode trace ref\n"); exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; goto run_cleanup; } } else { fputs("null", stdout); } fputs(",\"output_refs\":[", stdout); for (i = 0; i < (int)output_refs_len; ++i) { if (i != 0) { fputc(',', stdout); } if (!amduat_pel_cli_print_ref_json(stdout, output_refs[i], ref_format)) { fprintf(stderr, "error: failed to encode output ref\n"); exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; goto run_cleanup; } } fputs("]}\n", stdout); } run_cleanup: if (has_result_value) { amduat_enc_pel1_result_free(&result_value); } if (output_refs != NULL) { amduat_pel_surf_free_refs(output_refs, output_refs_len); } amduat_pel_surf_free_ref(&result_ref); amduat_pel_cli_free_artifact(&result_artifact); if (input_refs != NULL) { amduat_pel_cli_free_refs(input_refs, input_refs_len); } if (has_params_ref) { amduat_pel_cli_free_reference(¶ms_ref); } amduat_pel_cli_free_reference(&program_ref); if (strcmp(scheme_ref_text, "dag") != 0) { amduat_pel_cli_free_reference(&scheme_ref); } free(input_ref_texts); return exit_code; } static int amduat_pel_cli_cmd_exec(int argc, char **argv, const amduat_pel_cli_global_opts_t *global) { const char *program_path = NULL; const char **input_paths = NULL; size_t input_paths_len = 0; amduat_pel_cli_io_format_t input_format = AMDUAT_PEL_CLI_IO_RAW; amduat_pel_cli_io_format_t output_format = AMDUAT_PEL_CLI_IO_RAW; amduat_pel_cli_output_format_t format; const char *output_dir = "."; const char *result_out = "-"; amduat_pel_program_t program; amduat_artifact_t *inputs = NULL; amduat_artifact_t *outputs = NULL; size_t outputs_len = 0; amduat_pel_execution_result_value_t result; uint8_t *program_bytes = NULL; size_t program_len = 0; bool stdin_used = false; int exit_code = AMDUAT_PEL_CLI_EXIT_OK; FILE *out_stream = NULL; int i; if (global == NULL) { return AMDUAT_PEL_CLI_EXIT_USAGE; } format = global->format; for (i = 0; i < argc; ++i) { if (strcmp(argv[i], "--program") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --program requires a path\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } program_path = argv[++i]; } else if (strcmp(argv[i], "--input") == 0) { const char **next; if (i + 1 >= argc) { fprintf(stderr, "error: --input requires a path\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } next = (const char **)realloc( input_paths, (input_paths_len + 1u) * sizeof(*input_paths)); if (next == NULL) { fprintf(stderr, "error: out of memory\n"); return AMDUAT_PEL_CLI_EXIT_STORE; } input_paths = next; input_paths[input_paths_len++] = argv[++i]; } else if (strcmp(argv[i], "--input-format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --input-format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_io_format(argv[++i], &input_format)) { fprintf(stderr, "error: invalid input-format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--output-dir") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --output-dir requires a path\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } output_dir = argv[++i]; } else if (strcmp(argv[i], "--output-format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --output-format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_io_format(argv[++i], &output_format)) { fprintf(stderr, "error: invalid output-format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--result-out") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --result-out requires a path\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } result_out = argv[++i]; } else if (strcmp(argv[i], "--format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_output_format(argv[++i], &format)) { fprintf(stderr, "error: invalid format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { amduat_pel_cli_print_usage(stdout); free(input_paths); return AMDUAT_PEL_CLI_EXIT_OK; } else { fprintf(stderr, "error: unknown option: %s\n", argv[i]); free(input_paths); return AMDUAT_PEL_CLI_EXIT_USAGE; } } if (program_path == NULL) { fprintf(stderr, "error: --program is required\n"); free(input_paths); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_read_path_once(program_path, &stdin_used, &program_bytes, &program_len)) { fprintf(stderr, "error: failed to read program\n"); free(input_paths); return AMDUAT_PEL_CLI_EXIT_IO; } memset(&program, 0, sizeof(program)); if (!amduat_enc_pel_program_dag_decode_v1( amduat_octets(program_bytes, program_len), &program)) { fprintf(stderr, "error: invalid program encoding\n"); free(program_bytes); free(input_paths); return AMDUAT_PEL_CLI_EXIT_CODEC; } free(program_bytes); if (input_paths_len > 0) { inputs = (amduat_artifact_t *)calloc( input_paths_len, sizeof(*inputs)); if (inputs == NULL) { fprintf(stderr, "error: out of memory\n"); amduat_enc_pel_program_dag_free(&program); free(input_paths); return AMDUAT_PEL_CLI_EXIT_STORE; } } for (i = 0; i < (int)input_paths_len; ++i) { uint8_t *bytes = NULL; size_t len = 0; if (!amduat_pel_cli_read_path_once(input_paths[i], &stdin_used, &bytes, &len)) { fprintf(stderr, "error: failed to read input: %s\n", input_paths[i]); exit_code = AMDUAT_PEL_CLI_EXIT_IO; goto exec_cleanup; } if (input_format == AMDUAT_PEL_CLI_IO_ARTIFACT) { if (!amduat_enc_asl1_core_decode_artifact_v1( amduat_octets(bytes, len), &inputs[i])) { free(bytes); fprintf(stderr, "error: invalid input artifact\n"); exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; goto exec_cleanup; } free(bytes); } else { inputs[i] = amduat_artifact(amduat_octets(bytes, len)); } } if (!amduat_pel_program_dag_exec(&program, inputs, input_paths_len, &outputs, &outputs_len, &result)) { fprintf(stderr, "error: exec failed\n"); exit_code = AMDUAT_PEL_CLI_EXIT_STORE; goto exec_cleanup; } for (i = 0; i < (int)outputs_len; ++i) { char path_buf[4096]; if (snprintf(path_buf, sizeof(path_buf), "%s/output-%d", output_dir, i) < 0) { fprintf(stderr, "error: failed to build output path\n"); exit_code = AMDUAT_PEL_CLI_EXIT_IO; goto exec_cleanup; } if (output_format == AMDUAT_PEL_CLI_IO_RAW) { if (!amduat_asl_write_path(path_buf, outputs[i].bytes.data, outputs[i].bytes.len)) { fprintf(stderr, "error: failed to write output: %s\n", path_buf); exit_code = AMDUAT_PEL_CLI_EXIT_IO; goto exec_cleanup; } } else { amduat_octets_t encoded; if (!amduat_enc_asl1_core_encode_artifact_v1(outputs[i], &encoded)) { fprintf(stderr, "error: failed to encode output artifact\n"); exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; goto exec_cleanup; } if (!amduat_asl_write_path(path_buf, encoded.data, encoded.len)) { fprintf(stderr, "error: failed to write output: %s\n", path_buf); free((void *)encoded.data); exit_code = AMDUAT_PEL_CLI_EXIT_IO; goto exec_cleanup; } free((void *)encoded.data); } } if (strcmp(result_out, "-") == 0) { out_stream = stdout; } else { out_stream = fopen(result_out, "wb"); if (out_stream == NULL) { fprintf(stderr, "error: failed to open result-out: %s\n", result_out); exit_code = AMDUAT_PEL_CLI_EXIT_IO; goto exec_cleanup; } } if (format == AMDUAT_PEL_CLI_FORMAT_TEXT) { fprintf(out_stream, "status=%s(%u)\n", amduat_pel_cli_status_name(result.status), (unsigned int)result.status); fprintf(out_stream, "error_kind=%s(%u)\n", amduat_pel_cli_error_kind_name(result.summary.kind), (unsigned int)result.summary.kind); fprintf(out_stream, "status_code=%u\n", (unsigned int)result.summary.status_code); fprintf(out_stream, "outputs_len=%zu\n", outputs_len); for (i = 0; i < (int)outputs_len; ++i) { fprintf(out_stream, "output_path[%d]=%s/output-%d\n", i, output_dir, i); } } else { fputs("{\"status\":", out_stream); amduat_pel_cli_json_escape( out_stream, (const uint8_t *)amduat_pel_cli_status_name(result.status), strlen(amduat_pel_cli_status_name(result.status))); fprintf(out_stream, ",\"status_code\":%u", (unsigned int)result.summary.status_code); fputs(",\"error_kind\":", out_stream); amduat_pel_cli_json_escape( out_stream, (const uint8_t *)amduat_pel_cli_error_kind_name(result.summary.kind), strlen(amduat_pel_cli_error_kind_name(result.summary.kind))); fprintf(out_stream, ",\"error_kind_code\":%u", (unsigned int)result.summary.kind); fputs(",\"output_paths\":[", out_stream); for (i = 0; i < (int)outputs_len; ++i) { if (i != 0) { fputc(',', out_stream); } { char path_buf[4096]; if (snprintf(path_buf, sizeof(path_buf), "%s/output-%d", output_dir, i) < 0) { fprintf(stderr, "error: failed to build output path\n"); exit_code = AMDUAT_PEL_CLI_EXIT_IO; goto exec_cleanup; } amduat_pel_cli_json_escape(out_stream, (const uint8_t *)path_buf, strlen(path_buf)); } } fputs("]}\n", out_stream); } exec_cleanup: if (out_stream != NULL && out_stream != stdout) { fclose(out_stream); } if (outputs != NULL) { amduat_pel_program_dag_free_outputs(outputs, outputs_len); } if (inputs != NULL) { for (i = 0; i < (int)input_paths_len; ++i) { amduat_pel_cli_free_artifact(&inputs[i]); } free(inputs); } amduat_enc_pel_program_dag_free(&program); free(input_paths); return exit_code; } static int amduat_pel_cli_cmd_validate( int argc, char **argv, const amduat_pel_cli_global_opts_t *global) { const char *input_path = "-"; const char *program_ref_text = NULL; bool input_path_set = false; amduat_pel_cli_io_format_t input_format = AMDUAT_PEL_CLI_IO_RAW; amduat_pel_cli_output_format_t format; amduat_pel_cli_ref_format_t ref_format; const char *root; bool has_expect_type_tag = false; amduat_type_tag_t expect_type_tag; amduat_asl_store_fs_config_t cfg; amduat_asl_store_fs_t fs; amduat_asl_store_t store; amduat_reference_t program_ref; amduat_artifact_t artifact; amduat_pel_program_t program; bool stdin_used = false; bool ok; int exit_code = AMDUAT_PEL_CLI_EXIT_OK; int i; if (global == NULL) { return AMDUAT_PEL_CLI_EXIT_USAGE; } format = global->format; ref_format = global->ref_format; root = global->root; for (i = 0; i < argc; ++i) { if (strcmp(argv[i], "--input") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --input requires a path\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } input_path = argv[++i]; input_path_set = true; } else if (strcmp(argv[i], "--program-ref") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --program-ref requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } program_ref_text = argv[++i]; } else if (strcmp(argv[i], "--input-format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --input-format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_io_format(argv[++i], &input_format)) { fprintf(stderr, "error: invalid input-format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--expect-type-tag") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --expect-type-tag requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_asl_parse_type_tag(argv[++i], &expect_type_tag)) { fprintf(stderr, "error: invalid expect-type-tag\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } has_expect_type_tag = true; } else if (strcmp(argv[i], "--format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_output_format(argv[++i], &format)) { fprintf(stderr, "error: invalid format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--ref-format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --ref-format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_ref_format(argv[++i], &ref_format)) { fprintf(stderr, "error: invalid ref-format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--root") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --root requires a path\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } root = argv[++i]; } else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { amduat_pel_cli_print_usage(stdout); return AMDUAT_PEL_CLI_EXIT_OK; } else { fprintf(stderr, "error: unknown option: %s\n", argv[i]); return AMDUAT_PEL_CLI_EXIT_USAGE; } } if (program_ref_text != NULL && input_path_set) { fprintf(stderr, "error: use --input or --program-ref\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } memset(&artifact, 0, sizeof(artifact)); if (program_ref_text != NULL) { if (!amduat_asl_store_fs_load_config(root, &cfg)) { fprintf(stderr, "error: failed to load store config: %s\n", root); return AMDUAT_PEL_CLI_EXIT_CONFIG; } if (!amduat_asl_store_fs_init(&fs, cfg.config, root)) { fprintf(stderr, "error: failed to initialize store\n"); return AMDUAT_PEL_CLI_EXIT_CONFIG; } amduat_asl_store_init(&store, cfg.config, amduat_asl_store_fs_ops(), &fs); if (!amduat_pel_cli_ref_from_text(program_ref_text, ref_format, &stdin_used, &program_ref)) { fprintf(stderr, "error: invalid program-ref\n"); return AMDUAT_PEL_CLI_EXIT_CODEC; } { amduat_asl_store_error_t err = amduat_asl_store_get(&store, program_ref, &artifact); if (err != AMDUAT_ASL_STORE_OK) { fprintf(stderr, "error: store get failed: %s\n", amduat_pel_cli_store_error_str(err)); amduat_pel_cli_free_reference(&program_ref); return amduat_pel_cli_map_store_error(err); } } amduat_pel_cli_free_reference(&program_ref); } else { uint8_t *bytes = NULL; size_t len = 0; if (!amduat_pel_cli_read_path_once(input_path, &stdin_used, &bytes, &len)) { fprintf(stderr, "error: failed to read input\n"); return AMDUAT_PEL_CLI_EXIT_IO; } if (input_format == AMDUAT_PEL_CLI_IO_ARTIFACT) { if (!amduat_enc_asl1_core_decode_artifact_v1( amduat_octets(bytes, len), &artifact)) { free(bytes); fprintf(stderr, "error: invalid artifact encoding\n"); return AMDUAT_PEL_CLI_EXIT_CODEC; } free(bytes); } else { artifact = amduat_artifact(amduat_octets(bytes, len)); } } if (has_expect_type_tag) { if (!artifact.has_type_tag || artifact.type_tag.tag_id != expect_type_tag.tag_id) { fprintf(stderr, "error: type-tag mismatch\n"); amduat_pel_cli_free_artifact(&artifact); return AMDUAT_PEL_CLI_EXIT_UNSUPPORTED; } } memset(&program, 0, sizeof(program)); ok = amduat_enc_pel_program_dag_decode_v1(artifact.bytes, &program); if (!ok) { fprintf(stderr, "error: invalid program encoding\n"); amduat_pel_cli_free_artifact(&artifact); return AMDUAT_PEL_CLI_EXIT_CODEC; } ok = amduat_pel_program_dag_validate(&program); amduat_enc_pel_program_dag_free(&program); amduat_pel_cli_free_artifact(&artifact); if (format == AMDUAT_PEL_CLI_FORMAT_TEXT) { fprintf(stdout, "valid=%s\n", ok ? "true" : "false"); } else { fprintf(stdout, "{\"valid\":%s}\n", ok ? "true" : "false"); } if (!ok) { exit_code = AMDUAT_PEL_CLI_EXIT_UNSUPPORTED; } return exit_code; } static int amduat_pel_cli_cmd_program_decode( int argc, char **argv, const amduat_pel_cli_global_opts_t *global) { const char *input_path = "-"; const char *program_ref_text = NULL; bool input_path_set = false; amduat_pel_cli_io_format_t input_format = AMDUAT_PEL_CLI_IO_RAW; amduat_pel_cli_output_format_t format; amduat_pel_cli_ref_format_t ref_format; const char *root; bool has_expect_type_tag = false; amduat_type_tag_t expect_type_tag; amduat_asl_store_fs_config_t cfg; amduat_asl_store_fs_t fs; amduat_asl_store_t store; amduat_reference_t program_ref; amduat_artifact_t artifact; amduat_pel_program_t program; bool stdin_used = false; int exit_code = AMDUAT_PEL_CLI_EXIT_OK; int i; if (global == NULL) { return AMDUAT_PEL_CLI_EXIT_USAGE; } format = global->format; ref_format = global->ref_format; root = global->root; for (i = 0; i < argc; ++i) { if (strcmp(argv[i], "--input") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --input requires a path\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } input_path = argv[++i]; input_path_set = true; } else if (strcmp(argv[i], "--program-ref") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --program-ref requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } program_ref_text = argv[++i]; } else if (strcmp(argv[i], "--input-format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --input-format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_io_format(argv[++i], &input_format)) { fprintf(stderr, "error: invalid input-format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--expect-type-tag") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --expect-type-tag requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_asl_parse_type_tag(argv[++i], &expect_type_tag)) { fprintf(stderr, "error: invalid expect-type-tag\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } has_expect_type_tag = true; } else if (strcmp(argv[i], "--format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_output_format(argv[++i], &format)) { fprintf(stderr, "error: invalid format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--ref-format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --ref-format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_ref_format(argv[++i], &ref_format)) { fprintf(stderr, "error: invalid ref-format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--root") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --root requires a path\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } root = argv[++i]; } else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { amduat_pel_cli_print_usage(stdout); return AMDUAT_PEL_CLI_EXIT_OK; } else { fprintf(stderr, "error: unknown option: %s\n", argv[i]); return AMDUAT_PEL_CLI_EXIT_USAGE; } } if (program_ref_text != NULL && input_path_set) { fprintf(stderr, "error: use --input or --program-ref\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } memset(&artifact, 0, sizeof(artifact)); if (program_ref_text != NULL) { if (!amduat_asl_store_fs_load_config(root, &cfg)) { fprintf(stderr, "error: failed to load store config: %s\n", root); return AMDUAT_PEL_CLI_EXIT_CONFIG; } if (!amduat_asl_store_fs_init(&fs, cfg.config, root)) { fprintf(stderr, "error: failed to initialize store\n"); return AMDUAT_PEL_CLI_EXIT_CONFIG; } amduat_asl_store_init(&store, cfg.config, amduat_asl_store_fs_ops(), &fs); if (!amduat_pel_cli_ref_from_text(program_ref_text, ref_format, &stdin_used, &program_ref)) { fprintf(stderr, "error: invalid program-ref\n"); return AMDUAT_PEL_CLI_EXIT_CODEC; } { amduat_asl_store_error_t err = amduat_asl_store_get(&store, program_ref, &artifact); if (err != AMDUAT_ASL_STORE_OK) { fprintf(stderr, "error: store get failed: %s\n", amduat_pel_cli_store_error_str(err)); amduat_pel_cli_free_reference(&program_ref); return amduat_pel_cli_map_store_error(err); } } amduat_pel_cli_free_reference(&program_ref); } else { uint8_t *bytes = NULL; size_t len = 0; if (!amduat_pel_cli_read_path_once(input_path, &stdin_used, &bytes, &len)) { fprintf(stderr, "error: failed to read input\n"); return AMDUAT_PEL_CLI_EXIT_IO; } if (input_format == AMDUAT_PEL_CLI_IO_ARTIFACT) { if (!amduat_enc_asl1_core_decode_artifact_v1( amduat_octets(bytes, len), &artifact)) { free(bytes); fprintf(stderr, "error: invalid artifact encoding\n"); return AMDUAT_PEL_CLI_EXIT_CODEC; } free(bytes); } else { artifact = amduat_artifact(amduat_octets(bytes, len)); } } if (has_expect_type_tag) { if (!artifact.has_type_tag || artifact.type_tag.tag_id != expect_type_tag.tag_id) { fprintf(stderr, "error: type-tag mismatch\n"); amduat_pel_cli_free_artifact(&artifact); return AMDUAT_PEL_CLI_EXIT_UNSUPPORTED; } } memset(&program, 0, sizeof(program)); if (!amduat_enc_pel_program_dag_decode_v1(artifact.bytes, &program)) { fprintf(stderr, "error: invalid program encoding\n"); amduat_pel_cli_free_artifact(&artifact); return AMDUAT_PEL_CLI_EXIT_CODEC; } if (format == AMDUAT_PEL_CLI_FORMAT_TEXT) { if (!amduat_pel_cli_print_program_text(stdout, &program)) { fprintf(stderr, "error: failed to format program\n"); exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; } } else { if (!amduat_pel_cli_print_program_json(stdout, &program)) { fprintf(stderr, "error: failed to format program\n"); exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; } fputc('\n', stdout); } amduat_enc_pel_program_dag_free(&program); amduat_pel_cli_free_artifact(&artifact); return exit_code; } static int amduat_pel_cli_cmd_program_normalize( int argc, char **argv, const amduat_pel_cli_global_opts_t *global) { const char *input_path = "-"; const char *output_path = "-"; amduat_pel_cli_io_format_t input_format = AMDUAT_PEL_CLI_IO_RAW; amduat_pel_cli_io_format_t output_format = AMDUAT_PEL_CLI_IO_RAW; bool has_type_tag = false; amduat_type_tag_t type_tag; amduat_artifact_t artifact; amduat_pel_program_t program; amduat_octets_t normalized; bool stdin_used = false; int exit_code = AMDUAT_PEL_CLI_EXIT_OK; int i; (void)global; for (i = 0; i < argc; ++i) { if (strcmp(argv[i], "--input") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --input requires a path\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } input_path = argv[++i]; } else if (strcmp(argv[i], "--input-format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --input-format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_io_format(argv[++i], &input_format)) { fprintf(stderr, "error: invalid input-format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--output") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --output requires a path\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } output_path = argv[++i]; } else if (strcmp(argv[i], "--output-format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --output-format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_io_format(argv[++i], &output_format)) { fprintf(stderr, "error: invalid output-format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--type-tag") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --type-tag requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_asl_parse_type_tag(argv[++i], &type_tag)) { fprintf(stderr, "error: invalid type-tag\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } has_type_tag = true; } else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { amduat_pel_cli_print_usage(stdout); return AMDUAT_PEL_CLI_EXIT_OK; } else { fprintf(stderr, "error: unknown option: %s\n", argv[i]); return AMDUAT_PEL_CLI_EXIT_USAGE; } } memset(&artifact, 0, sizeof(artifact)); { uint8_t *bytes = NULL; size_t len = 0; if (!amduat_pel_cli_read_path_once(input_path, &stdin_used, &bytes, &len)) { fprintf(stderr, "error: failed to read input\n"); return AMDUAT_PEL_CLI_EXIT_IO; } if (input_format == AMDUAT_PEL_CLI_IO_ARTIFACT) { if (!amduat_enc_asl1_core_decode_artifact_v1( amduat_octets(bytes, len), &artifact)) { free(bytes); fprintf(stderr, "error: invalid artifact encoding\n"); return AMDUAT_PEL_CLI_EXIT_CODEC; } free(bytes); } else { artifact = amduat_artifact(amduat_octets(bytes, len)); } } memset(&program, 0, sizeof(program)); if (!amduat_enc_pel_program_dag_decode_v1(artifact.bytes, &program)) { fprintf(stderr, "error: invalid program encoding\n"); amduat_pel_cli_free_artifact(&artifact); return AMDUAT_PEL_CLI_EXIT_CODEC; } normalized = amduat_octets(NULL, 0); if (!amduat_enc_pel_program_dag_encode_v1(&program, &normalized)) { fprintf(stderr, "error: failed to normalize program\n"); amduat_enc_pel_program_dag_free(&program); amduat_pel_cli_free_artifact(&artifact); return AMDUAT_PEL_CLI_EXIT_CODEC; } if (output_format == AMDUAT_PEL_CLI_IO_RAW) { if (!amduat_asl_write_path(output_path, normalized.data, normalized.len)) { fprintf(stderr, "error: failed to write output\n"); exit_code = AMDUAT_PEL_CLI_EXIT_IO; } } else { amduat_type_tag_t tag = has_type_tag ? type_tag : (artifact.has_type_tag ? artifact.type_tag : amduat_type_tag(AMDUAT_PEL_TYPE_TAG_PROGRAM_DAG_1)); amduat_artifact_t out_artifact = amduat_artifact_with_type(normalized, tag); amduat_octets_t encoded; if (!amduat_enc_asl1_core_encode_artifact_v1(out_artifact, &encoded)) { fprintf(stderr, "error: failed to encode output artifact\n"); exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; } else { if (!amduat_asl_write_path(output_path, encoded.data, encoded.len)) { fprintf(stderr, "error: failed to write output\n"); exit_code = AMDUAT_PEL_CLI_EXIT_IO; } free((void *)encoded.data); } } free((void *)normalized.data); amduat_enc_pel_program_dag_free(&program); amduat_pel_cli_free_artifact(&artifact); return exit_code; } static int amduat_pel_cli_cmd_program( int argc, char **argv, const amduat_pel_cli_global_opts_t *global) { if (argc < 1) { fprintf(stderr, "error: program requires a subcommand\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (strcmp(argv[0], "decode") == 0) { return amduat_pel_cli_cmd_program_decode(argc - 1, argv + 1, global); } if (strcmp(argv[0], "normalize") == 0) { return amduat_pel_cli_cmd_program_normalize(argc - 1, argv + 1, global); } fprintf(stderr, "error: unknown program subcommand: %s\n", argv[0]); return AMDUAT_PEL_CLI_EXIT_USAGE; } static int amduat_pel_cli_cmd_trace_decode( int argc, char **argv, const amduat_pel_cli_global_opts_t *global) { const char *input_path = "-"; const char *trace_ref_text = NULL; bool input_path_set = false; amduat_pel_cli_io_format_t input_format = AMDUAT_PEL_CLI_IO_RAW; amduat_pel_cli_output_format_t format; amduat_pel_cli_ref_format_t ref_format; const char *root; bool has_expect_type_tag = false; amduat_type_tag_t expect_type_tag; amduat_asl_store_fs_config_t cfg; amduat_asl_store_fs_t fs; amduat_asl_store_t store; amduat_reference_t trace_ref; amduat_artifact_t artifact; amduat_pel_trace_dag_value_t trace; bool stdin_used = false; int exit_code = AMDUAT_PEL_CLI_EXIT_OK; int i; if (global == NULL) { return AMDUAT_PEL_CLI_EXIT_USAGE; } format = global->format; ref_format = global->ref_format; root = global->root; for (i = 0; i < argc; ++i) { if (strcmp(argv[i], "--input") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --input requires a path\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } input_path = argv[++i]; input_path_set = true; } else if (strcmp(argv[i], "--trace-ref") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --trace-ref requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } trace_ref_text = argv[++i]; } else if (strcmp(argv[i], "--input-format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --input-format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_io_format(argv[++i], &input_format)) { fprintf(stderr, "error: invalid input-format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--expect-type-tag") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --expect-type-tag requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_asl_parse_type_tag(argv[++i], &expect_type_tag)) { fprintf(stderr, "error: invalid expect-type-tag\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } has_expect_type_tag = true; } else if (strcmp(argv[i], "--format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_output_format(argv[++i], &format)) { fprintf(stderr, "error: invalid format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--ref-format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --ref-format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_ref_format(argv[++i], &ref_format)) { fprintf(stderr, "error: invalid ref-format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--root") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --root requires a path\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } root = argv[++i]; } else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { amduat_pel_cli_print_usage(stdout); return AMDUAT_PEL_CLI_EXIT_OK; } else { fprintf(stderr, "error: unknown option: %s\n", argv[i]); return AMDUAT_PEL_CLI_EXIT_USAGE; } } if (trace_ref_text != NULL && input_path_set) { fprintf(stderr, "error: use --input or --trace-ref\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } memset(&artifact, 0, sizeof(artifact)); if (trace_ref_text != NULL) { if (!amduat_asl_store_fs_load_config(root, &cfg)) { fprintf(stderr, "error: failed to load store config: %s\n", root); return AMDUAT_PEL_CLI_EXIT_CONFIG; } if (!amduat_asl_store_fs_init(&fs, cfg.config, root)) { fprintf(stderr, "error: failed to initialize store\n"); return AMDUAT_PEL_CLI_EXIT_CONFIG; } amduat_asl_store_init(&store, cfg.config, amduat_asl_store_fs_ops(), &fs); if (!amduat_pel_cli_ref_from_text(trace_ref_text, ref_format, &stdin_used, &trace_ref)) { fprintf(stderr, "error: invalid trace-ref\n"); return AMDUAT_PEL_CLI_EXIT_CODEC; } { amduat_asl_store_error_t err = amduat_asl_store_get(&store, trace_ref, &artifact); if (err != AMDUAT_ASL_STORE_OK) { fprintf(stderr, "error: store get failed: %s\n", amduat_pel_cli_store_error_str(err)); amduat_pel_cli_free_reference(&trace_ref); return amduat_pel_cli_map_store_error(err); } } amduat_pel_cli_free_reference(&trace_ref); } else { uint8_t *bytes = NULL; size_t len = 0; if (!amduat_pel_cli_read_path_once(input_path, &stdin_used, &bytes, &len)) { fprintf(stderr, "error: failed to read input\n"); return AMDUAT_PEL_CLI_EXIT_IO; } if (input_format == AMDUAT_PEL_CLI_IO_ARTIFACT) { if (!amduat_enc_asl1_core_decode_artifact_v1( amduat_octets(bytes, len), &artifact)) { free(bytes); fprintf(stderr, "error: invalid artifact encoding\n"); return AMDUAT_PEL_CLI_EXIT_CODEC; } free(bytes); } else { artifact = amduat_artifact(amduat_octets(bytes, len)); } } if (has_expect_type_tag) { if (!artifact.has_type_tag || artifact.type_tag.tag_id != expect_type_tag.tag_id) { fprintf(stderr, "error: type-tag mismatch\n"); amduat_pel_cli_free_artifact(&artifact); return AMDUAT_PEL_CLI_EXIT_UNSUPPORTED; } } memset(&trace, 0, sizeof(trace)); if (!amduat_enc_pel_trace_dag_decode_v1(artifact.bytes, &trace)) { fprintf(stderr, "error: invalid trace encoding\n"); amduat_pel_cli_free_artifact(&artifact); return AMDUAT_PEL_CLI_EXIT_CODEC; } if (format == AMDUAT_PEL_CLI_FORMAT_TEXT) { if (!amduat_pel_cli_print_trace_text(stdout, &trace, ref_format)) { fprintf(stderr, "error: failed to format trace\n"); exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; } } else { if (!amduat_pel_cli_print_trace_json(stdout, &trace, ref_format)) { fprintf(stderr, "error: failed to format trace\n"); exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; } fputc('\n', stdout); } amduat_enc_pel_trace_dag_free(&trace); amduat_pel_cli_free_artifact(&artifact); return exit_code; } static int amduat_pel_cli_cmd_trace_from_result( int argc, char **argv, const amduat_pel_cli_global_opts_t *global) { const char *result_ref_text = NULL; amduat_pel_cli_output_format_t format; amduat_pel_cli_ref_format_t ref_format; const char *root; amduat_asl_store_fs_config_t cfg; amduat_asl_store_fs_t fs; amduat_asl_store_t store; amduat_reference_t result_ref; amduat_artifact_t artifact; amduat_pel_surface_execution_result_t result; bool stdin_used = false; int exit_code = AMDUAT_PEL_CLI_EXIT_OK; int i; if (global == NULL) { return AMDUAT_PEL_CLI_EXIT_USAGE; } format = global->format; ref_format = global->ref_format; root = global->root; for (i = 0; i < argc; ++i) { if (strcmp(argv[i], "--result-ref") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --result-ref requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } result_ref_text = argv[++i]; } else if (strcmp(argv[i], "--format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_output_format(argv[++i], &format)) { fprintf(stderr, "error: invalid format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--ref-format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --ref-format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_ref_format(argv[++i], &ref_format)) { fprintf(stderr, "error: invalid ref-format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--root") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --root requires a path\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } root = argv[++i]; } else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { amduat_pel_cli_print_usage(stdout); return AMDUAT_PEL_CLI_EXIT_OK; } else { fprintf(stderr, "error: unknown option: %s\n", argv[i]); return AMDUAT_PEL_CLI_EXIT_USAGE; } } if (result_ref_text == NULL) { fprintf(stderr, "error: --result-ref is required\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_asl_store_fs_load_config(root, &cfg)) { fprintf(stderr, "error: failed to load store config: %s\n", root); return AMDUAT_PEL_CLI_EXIT_CONFIG; } if (!amduat_asl_store_fs_init(&fs, cfg.config, root)) { fprintf(stderr, "error: failed to initialize store\n"); return AMDUAT_PEL_CLI_EXIT_CONFIG; } amduat_asl_store_init(&store, cfg.config, amduat_asl_store_fs_ops(), &fs); if (!amduat_pel_cli_ref_from_text(result_ref_text, ref_format, &stdin_used, &result_ref)) { fprintf(stderr, "error: invalid result-ref\n"); return AMDUAT_PEL_CLI_EXIT_CODEC; } memset(&artifact, 0, sizeof(artifact)); { amduat_asl_store_error_t err = amduat_asl_store_get(&store, result_ref, &artifact); if (err != AMDUAT_ASL_STORE_OK) { fprintf(stderr, "error: store get failed: %s\n", amduat_pel_cli_store_error_str(err)); amduat_pel_cli_free_reference(&result_ref); return amduat_pel_cli_map_store_error(err); } } memset(&result, 0, sizeof(result)); if (!amduat_enc_pel1_result_decode_v1(artifact.bytes, &result)) { fprintf(stderr, "error: invalid result encoding\n"); amduat_pel_cli_free_reference(&result_ref); amduat_pel_cli_free_artifact(&artifact); return AMDUAT_PEL_CLI_EXIT_CODEC; } if (format == AMDUAT_PEL_CLI_FORMAT_TEXT) { fprintf(stdout, "has_trace_ref=%s\n", result.has_trace_ref ? "true" : "false"); fprintf(stdout, "trace_ref="); if (result.has_trace_ref) { if (!amduat_pel_cli_print_ref_text(stdout, result.trace_ref, ref_format)) { fprintf(stderr, "error: failed to encode trace ref\n"); exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; } } fputc('\n', stdout); } else { fputs("{\"has_trace_ref\":", stdout); fputs(result.has_trace_ref ? "true" : "false", stdout); fputs(",\"trace_ref\":", stdout); if (result.has_trace_ref) { if (!amduat_pel_cli_print_ref_json(stdout, result.trace_ref, ref_format)) { fprintf(stderr, "error: failed to encode trace ref\n"); exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; } } else { fputs("null", stdout); } fputs("}\n", stdout); } amduat_enc_pel1_result_free(&result); amduat_pel_cli_free_reference(&result_ref); amduat_pel_cli_free_artifact(&artifact); return exit_code; } static int amduat_pel_cli_cmd_trace( int argc, char **argv, const amduat_pel_cli_global_opts_t *global) { if (argc < 1) { fprintf(stderr, "error: trace requires a subcommand\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (strcmp(argv[0], "decode") == 0) { return amduat_pel_cli_cmd_trace_decode(argc - 1, argv + 1, global); } if (strcmp(argv[0], "from-result") == 0) { return amduat_pel_cli_cmd_trace_from_result(argc - 1, argv + 1, global); } fprintf(stderr, "error: unknown trace subcommand: %s\n", argv[0]); return AMDUAT_PEL_CLI_EXIT_USAGE; } static int amduat_pel_cli_cmd_result_decode( int argc, char **argv, const amduat_pel_cli_global_opts_t *global) { const char *input_path = "-"; const char *result_ref_text = NULL; bool input_path_set = false; amduat_pel_cli_io_format_t input_format = AMDUAT_PEL_CLI_IO_RAW; amduat_pel_cli_output_format_t format; amduat_pel_cli_ref_format_t ref_format; const char *root; bool has_expect_type_tag = false; amduat_type_tag_t expect_type_tag; amduat_asl_store_fs_config_t cfg; amduat_asl_store_fs_t fs; amduat_asl_store_t store; amduat_reference_t result_ref; amduat_artifact_t artifact; amduat_pel_surface_execution_result_t result; bool stdin_used = false; int exit_code = AMDUAT_PEL_CLI_EXIT_OK; int i; if (global == NULL) { return AMDUAT_PEL_CLI_EXIT_USAGE; } format = global->format; ref_format = global->ref_format; root = global->root; for (i = 0; i < argc; ++i) { if (strcmp(argv[i], "--input") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --input requires a path\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } input_path = argv[++i]; input_path_set = true; } else if (strcmp(argv[i], "--result-ref") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --result-ref requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } result_ref_text = argv[++i]; } else if (strcmp(argv[i], "--input-format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --input-format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_io_format(argv[++i], &input_format)) { fprintf(stderr, "error: invalid input-format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--expect-type-tag") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --expect-type-tag requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_asl_parse_type_tag(argv[++i], &expect_type_tag)) { fprintf(stderr, "error: invalid expect-type-tag\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } has_expect_type_tag = true; } else if (strcmp(argv[i], "--format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_output_format(argv[++i], &format)) { fprintf(stderr, "error: invalid format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--ref-format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --ref-format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_ref_format(argv[++i], &ref_format)) { fprintf(stderr, "error: invalid ref-format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--root") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --root requires a path\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } root = argv[++i]; } else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { amduat_pel_cli_print_usage(stdout); return AMDUAT_PEL_CLI_EXIT_OK; } else { fprintf(stderr, "error: unknown option: %s\n", argv[i]); return AMDUAT_PEL_CLI_EXIT_USAGE; } } if (result_ref_text != NULL && input_path_set) { fprintf(stderr, "error: use --input or --result-ref\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } memset(&artifact, 0, sizeof(artifact)); if (result_ref_text != NULL) { if (!amduat_asl_store_fs_load_config(root, &cfg)) { fprintf(stderr, "error: failed to load store config: %s\n", root); return AMDUAT_PEL_CLI_EXIT_CONFIG; } if (!amduat_asl_store_fs_init(&fs, cfg.config, root)) { fprintf(stderr, "error: failed to initialize store\n"); return AMDUAT_PEL_CLI_EXIT_CONFIG; } amduat_asl_store_init(&store, cfg.config, amduat_asl_store_fs_ops(), &fs); if (!amduat_pel_cli_ref_from_text(result_ref_text, ref_format, &stdin_used, &result_ref)) { fprintf(stderr, "error: invalid result-ref\n"); return AMDUAT_PEL_CLI_EXIT_CODEC; } { amduat_asl_store_error_t err = amduat_asl_store_get(&store, result_ref, &artifact); if (err != AMDUAT_ASL_STORE_OK) { fprintf(stderr, "error: store get failed: %s\n", amduat_pel_cli_store_error_str(err)); amduat_pel_cli_free_reference(&result_ref); return amduat_pel_cli_map_store_error(err); } } amduat_pel_cli_free_reference(&result_ref); } else { uint8_t *bytes = NULL; size_t len = 0; if (!amduat_pel_cli_read_path_once(input_path, &stdin_used, &bytes, &len)) { fprintf(stderr, "error: failed to read input\n"); return AMDUAT_PEL_CLI_EXIT_IO; } if (input_format == AMDUAT_PEL_CLI_IO_ARTIFACT) { if (!amduat_enc_asl1_core_decode_artifact_v1( amduat_octets(bytes, len), &artifact)) { free(bytes); fprintf(stderr, "error: invalid artifact encoding\n"); return AMDUAT_PEL_CLI_EXIT_CODEC; } free(bytes); } else { artifact = amduat_artifact(amduat_octets(bytes, len)); } } if (has_expect_type_tag) { if (!artifact.has_type_tag || artifact.type_tag.tag_id != expect_type_tag.tag_id) { fprintf(stderr, "error: type-tag mismatch\n"); amduat_pel_cli_free_artifact(&artifact); return AMDUAT_PEL_CLI_EXIT_UNSUPPORTED; } } memset(&result, 0, sizeof(result)); if (!amduat_enc_pel1_result_decode_v1(artifact.bytes, &result)) { fprintf(stderr, "error: invalid result encoding\n"); amduat_pel_cli_free_artifact(&artifact); return AMDUAT_PEL_CLI_EXIT_CODEC; } if (format == AMDUAT_PEL_CLI_FORMAT_TEXT) { if (!amduat_pel_cli_print_result_text(stdout, &result, ref_format)) { fprintf(stderr, "error: failed to format result\n"); exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; } } else { if (!amduat_pel_cli_print_result_json(stdout, &result, ref_format)) { fprintf(stderr, "error: failed to format result\n"); exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; } fputc('\n', stdout); } amduat_enc_pel1_result_free(&result); amduat_pel_cli_free_artifact(&artifact); return exit_code; } static int amduat_pel_cli_cmd_result( int argc, char **argv, const amduat_pel_cli_global_opts_t *global) { if (argc < 1) { fprintf(stderr, "error: result requires a subcommand\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (strcmp(argv[0], "decode") == 0) { return amduat_pel_cli_cmd_result_decode(argc - 1, argv + 1, global); } fprintf(stderr, "error: unknown result subcommand: %s\n", argv[0]); return AMDUAT_PEL_CLI_EXIT_USAGE; } static const struct { const char *name; uint32_t version; } amduat_pel_cli_ops[] = { {AMDUAT_PEL_KERNEL_OP_CONCAT_NAME, 1}, {AMDUAT_PEL_KERNEL_OP_SLICE_NAME, 1}, {AMDUAT_PEL_KERNEL_OP_CONST_NAME, 1}, {AMDUAT_PEL_KERNEL_OP_HASH_ASL1_NAME, 1} }; static const char *amduat_pel_cli_kernel_kind_name( amduat_pel_kernel_op_kind_t kind) { switch (kind) { case AMDUAT_PEL_KERNEL_OP_CONCAT: return "concat"; case AMDUAT_PEL_KERNEL_OP_SLICE: return "slice"; case AMDUAT_PEL_KERNEL_OP_CONST: return "const"; case AMDUAT_PEL_KERNEL_OP_HASH_ASL1: return "hash_asl1"; default: return "unknown"; } } static int amduat_pel_cli_cmd_op_list( int argc, char **argv, const amduat_pel_cli_global_opts_t *global) { amduat_pel_cli_output_format_t format; size_t i; if (global == NULL) { return AMDUAT_PEL_CLI_EXIT_USAGE; } format = global->format; for (i = 0; i < (size_t)argc; ++i) { if (strcmp(argv[i], "--format") == 0) { if (i + 1 >= (size_t)argc) { fprintf(stderr, "error: --format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_output_format(argv[++i], &format)) { fprintf(stderr, "error: invalid format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { amduat_pel_cli_print_usage(stdout); return AMDUAT_PEL_CLI_EXIT_OK; } else { fprintf(stderr, "error: unknown option: %s\n", argv[i]); return AMDUAT_PEL_CLI_EXIT_USAGE; } } if (format == AMDUAT_PEL_CLI_FORMAT_TEXT) { for (i = 0; i < sizeof(amduat_pel_cli_ops) / sizeof(amduat_pel_cli_ops[0]); ++i) { fprintf(stdout, "name=%s version=%u\n", amduat_pel_cli_ops[i].name, amduat_pel_cli_ops[i].version); } } else { fputs("{\"ops\":[", stdout); for (i = 0; i < sizeof(amduat_pel_cli_ops) / sizeof(amduat_pel_cli_ops[0]); ++i) { if (i != 0) { fputc(',', stdout); } fprintf(stdout, "{\"name\":"); amduat_pel_cli_json_escape( stdout, (const uint8_t *)amduat_pel_cli_ops[i].name, strlen(amduat_pel_cli_ops[i].name)); fprintf(stdout, ",\"version\":%u}", amduat_pel_cli_ops[i].version); } fputs("]}\n", stdout); } return AMDUAT_PEL_CLI_EXIT_OK; } static int amduat_pel_cli_cmd_op_describe( int argc, char **argv, const amduat_pel_cli_global_opts_t *global) { const char *op_text = NULL; const char *op_name = NULL; uint32_t op_version = 1; amduat_pel_cli_output_format_t format; const amduat_pel_kernel_op_desc_t *desc; int i; if (global == NULL) { return AMDUAT_PEL_CLI_EXIT_USAGE; } format = global->format; for (i = 0; i < argc; ++i) { if (strcmp(argv[i], "--format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_output_format(argv[++i], &format)) { fprintf(stderr, "error: invalid format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { amduat_pel_cli_print_usage(stdout); return AMDUAT_PEL_CLI_EXIT_OK; } else if (op_text == NULL) { op_text = argv[i]; } else { fprintf(stderr, "error: unexpected argument: %s\n", argv[i]); return AMDUAT_PEL_CLI_EXIT_USAGE; } } if (op_text == NULL) { fprintf(stderr, "error: NAME[=VERSION] is required\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_op_name(op_text, &op_name, &op_version)) { fprintf(stderr, "error: invalid op name\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } desc = amduat_pel_kernel_op_lookup( amduat_octets(op_name, strlen(op_name)), op_version); if (desc == NULL) { fprintf(stderr, "error: op not found\n"); amduat_pel_cli_free_op_name(op_name, op_text); return AMDUAT_PEL_CLI_EXIT_NOT_FOUND; } if (format == AMDUAT_PEL_CLI_FORMAT_TEXT) { fprintf(stdout, "name=%s\n", op_name); fprintf(stdout, "version=%u\n", op_version); fprintf(stdout, "kind=%s\n", amduat_pel_cli_kernel_kind_name(desc->kind)); fprintf(stdout, "kernel_op_code=0x%04x\n", desc->kernel_op_code); fprintf(stdout, "min_inputs=%zu\n", desc->min_inputs); fprintf(stdout, "max_inputs=%zu\n", desc->max_inputs); fprintf(stdout, "outputs_len=%zu\n", desc->outputs_len); } else { fputs("{\"name\":", stdout); amduat_pel_cli_json_escape(stdout, (const uint8_t *)op_name, strlen(op_name)); fprintf(stdout, ",\"version\":%u", op_version); fputs(",\"kind\":", stdout); amduat_pel_cli_json_escape( stdout, (const uint8_t *)amduat_pel_cli_kernel_kind_name(desc->kind), strlen(amduat_pel_cli_kernel_kind_name(desc->kind))); fprintf(stdout, ",\"kernel_op_code\":%u", desc->kernel_op_code); fprintf(stdout, ",\"min_inputs\":%zu", desc->min_inputs); fprintf(stdout, ",\"max_inputs\":%zu", desc->max_inputs); fprintf(stdout, ",\"outputs_len\":%zu}\n", desc->outputs_len); } amduat_pel_cli_free_op_name(op_name, op_text); return AMDUAT_PEL_CLI_EXIT_OK; } static int amduat_pel_cli_cmd_op_params_decode( int argc, char **argv, const amduat_pel_cli_global_opts_t *global) { const char *op_text = NULL; const char *op_name = NULL; uint32_t op_version = 1; const char *input_path = NULL; amduat_pel_cli_output_format_t format; const amduat_pel_kernel_op_desc_t *desc; amduat_pel_kernel_params_t params; uint8_t *bytes = NULL; size_t len = 0; bool stdin_used = false; int exit_code = AMDUAT_PEL_CLI_EXIT_OK; int i; if (global == NULL) { return AMDUAT_PEL_CLI_EXIT_USAGE; } format = global->format; for (i = 0; i < argc; ++i) { if (strcmp(argv[i], "--op") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --op requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } op_text = argv[++i]; } else if (strcmp(argv[i], "--input") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --input requires a path\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } input_path = argv[++i]; } else if (strcmp(argv[i], "--format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_output_format(argv[++i], &format)) { fprintf(stderr, "error: invalid format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { amduat_pel_cli_print_usage(stdout); return AMDUAT_PEL_CLI_EXIT_OK; } else { fprintf(stderr, "error: unknown option: %s\n", argv[i]); return AMDUAT_PEL_CLI_EXIT_USAGE; } } if (op_text == NULL || input_path == NULL) { fprintf(stderr, "error: --op and --input are required\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_op_name(op_text, &op_name, &op_version)) { fprintf(stderr, "error: invalid op name\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } desc = amduat_pel_kernel_op_lookup( amduat_octets(op_name, strlen(op_name)), op_version); if (desc == NULL) { fprintf(stderr, "error: op not found\n"); amduat_pel_cli_free_op_name(op_name, op_text); return AMDUAT_PEL_CLI_EXIT_NOT_FOUND; } if (!amduat_pel_cli_read_path_once(input_path, &stdin_used, &bytes, &len)) { fprintf(stderr, "error: failed to read input\n"); amduat_pel_cli_free_op_name(op_name, op_text); return AMDUAT_PEL_CLI_EXIT_IO; } if (!amduat_pel_kernel_params_decode( desc, amduat_octets(bytes, len), ¶ms)) { fprintf(stderr, "error: failed to decode params\n"); amduat_pel_cli_free_op_name(op_name, op_text); free(bytes); return AMDUAT_PEL_CLI_EXIT_CODEC; } if (format == AMDUAT_PEL_CLI_FORMAT_TEXT) { fprintf(stdout, "op=%s\n", op_name); fprintf(stdout, "version=%u\n", op_version); fprintf(stdout, "kind=%s\n", amduat_pel_cli_kernel_kind_name(params.kind)); switch (params.kind) { case AMDUAT_PEL_KERNEL_OP_CONCAT: fprintf(stdout, "params=unit\n"); break; case AMDUAT_PEL_KERNEL_OP_SLICE: fprintf(stdout, "offset=%" PRIu64 "\n", (uint64_t)params.value.slice.offset); fprintf(stdout, "length=%" PRIu64 "\n", (uint64_t)params.value.slice.length); break; case AMDUAT_PEL_KERNEL_OP_CONST: { char *hex = amduat_pel_cli_hex_encode(params.value.konst.bytes); if (hex == NULL) { exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; break; } fprintf(stdout, "has_type_tag=%s\n", params.value.konst.has_type_tag ? "true" : "false"); if (params.value.konst.has_type_tag) { fprintf(stdout, "type_tag=0x%08x\n", (unsigned int)params.value.konst.tag_id); } fprintf(stdout, "bytes_hex=%s\n", hex); free(hex); break; } case AMDUAT_PEL_KERNEL_OP_HASH_ASL1: { const amduat_hash_asl1_desc_t *desc_hash = amduat_hash_asl1_desc_lookup(params.value.hash.hash_id); fprintf(stdout, "hash_id=0x%04x\n", (unsigned int)params.value.hash.hash_id); if (desc_hash != NULL && desc_hash->name != NULL) { fprintf(stdout, "hash_name=%s\n", desc_hash->name); } break; } default: break; } } else { fputs("{\"op\":", stdout); amduat_pel_cli_json_escape(stdout, (const uint8_t *)op_name, strlen(op_name)); fprintf(stdout, ",\"version\":%u", op_version); fputs(",\"kind\":", stdout); amduat_pel_cli_json_escape( stdout, (const uint8_t *)amduat_pel_cli_kernel_kind_name(params.kind), strlen(amduat_pel_cli_kernel_kind_name(params.kind))); switch (params.kind) { case AMDUAT_PEL_KERNEL_OP_CONCAT: fputs(",\"params\":null", stdout); break; case AMDUAT_PEL_KERNEL_OP_SLICE: fprintf(stdout, ",\"offset\":%" PRIu64, (uint64_t)params.value.slice.offset); fprintf(stdout, ",\"length\":%" PRIu64, (uint64_t)params.value.slice.length); break; case AMDUAT_PEL_KERNEL_OP_CONST: { char *hex = amduat_pel_cli_hex_encode(params.value.konst.bytes); if (hex == NULL) { exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; break; } fputs(",\"has_type_tag\":", stdout); fputs(params.value.konst.has_type_tag ? "true" : "false", stdout); if (params.value.konst.has_type_tag) { fprintf(stdout, ",\"type_tag\":%u", params.value.konst.tag_id); } else { fputs(",\"type_tag\":null", stdout); } fputs(",\"bytes_hex\":", stdout); amduat_pel_cli_json_escape(stdout, (const uint8_t *)hex, strlen(hex)); free(hex); break; } case AMDUAT_PEL_KERNEL_OP_HASH_ASL1: { const amduat_hash_asl1_desc_t *desc_hash = amduat_hash_asl1_desc_lookup(params.value.hash.hash_id); fprintf(stdout, ",\"hash_id\":%u", (unsigned int)params.value.hash.hash_id); fputs(",\"hash_name\":", stdout); if (desc_hash != NULL && desc_hash->name != NULL) { amduat_pel_cli_json_escape( stdout, (const uint8_t *)desc_hash->name, strlen(desc_hash->name)); } else { fputs("null", stdout); } break; } default: break; } fputs("}\n", stdout); } free(bytes); amduat_pel_cli_free_op_name(op_name, op_text); return exit_code; } static int amduat_pel_cli_cmd_op( int argc, char **argv, const amduat_pel_cli_global_opts_t *global) { if (argc < 1) { fprintf(stderr, "error: op requires a subcommand\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (strcmp(argv[0], "list") == 0) { return amduat_pel_cli_cmd_op_list(argc - 1, argv + 1, global); } if (strcmp(argv[0], "describe") == 0) { return amduat_pel_cli_cmd_op_describe(argc - 1, argv + 1, global); } if (strcmp(argv[0], "params-decode") == 0) { return amduat_pel_cli_cmd_op_params_decode(argc - 1, argv + 1, global); } fprintf(stderr, "error: unknown op subcommand: %s\n", argv[0]); return AMDUAT_PEL_CLI_EXIT_USAGE; } static int amduat_pel_cli_cmd_scheme_show( int argc, char **argv, const amduat_pel_cli_global_opts_t *global) { amduat_pel_cli_output_format_t format; amduat_pel_cli_ref_format_t ref_format; amduat_reference_t scheme_ref; int i; if (global == NULL) { return AMDUAT_PEL_CLI_EXIT_USAGE; } format = global->format; ref_format = global->ref_format; for (i = 0; i < argc; ++i) { if (strcmp(argv[i], "--format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_output_format(argv[++i], &format)) { fprintf(stderr, "error: invalid format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--ref-format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --ref-format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_ref_format(argv[++i], &ref_format)) { fprintf(stderr, "error: invalid ref-format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { amduat_pel_cli_print_usage(stdout); return AMDUAT_PEL_CLI_EXIT_OK; } else { fprintf(stderr, "error: unknown option: %s\n", argv[i]); return AMDUAT_PEL_CLI_EXIT_USAGE; } } scheme_ref = amduat_pel_program_dag_scheme_ref(); if (format == AMDUAT_PEL_CLI_FORMAT_TEXT) { fprintf(stdout, "scheme_ref="); if (!amduat_pel_cli_print_ref_text(stdout, scheme_ref, ref_format)) { fprintf(stderr, "error: failed to encode scheme ref\n"); return AMDUAT_PEL_CLI_EXIT_CODEC; } fputc('\n', stdout); fprintf(stdout, "program_type_tag=0x%08x\n", AMDUAT_PEL_TYPE_TAG_PROGRAM_DAG_1); fprintf(stdout, "trace_type_tag=0x%08x\n", AMDUAT_TYPE_TAG_PEL_TRACE_DAG_1); fprintf(stdout, "result_type_tag=0x%08x\n", AMDUAT_TYPE_TAG_PEL1_RESULT_1); fprintf(stdout, "program_profile_id=0x%04x\n", AMDUAT_PEL_ENC_PROGRAM_DAG_V1); fprintf(stdout, "trace_profile_id=0x%04x\n", AMDUAT_PEL_ENC_TRACE_DAG_V1); fprintf(stdout, "result_profile_id=0x%04x\n", AMDUAT_PEL_ENC_EXECUTION_RESULT_V1); } else { fputs("{\"scheme_ref\":", stdout); if (!amduat_pel_cli_print_ref_json(stdout, scheme_ref, ref_format)) { fprintf(stderr, "error: failed to encode scheme ref\n"); return AMDUAT_PEL_CLI_EXIT_CODEC; } fprintf(stdout, ",\"program_type_tag\":%u", AMDUAT_PEL_TYPE_TAG_PROGRAM_DAG_1); fprintf(stdout, ",\"trace_type_tag\":%u", AMDUAT_TYPE_TAG_PEL_TRACE_DAG_1); fprintf(stdout, ",\"result_type_tag\":%u", AMDUAT_TYPE_TAG_PEL1_RESULT_1); fprintf(stdout, ",\"program_profile_id\":%u", AMDUAT_PEL_ENC_PROGRAM_DAG_V1); fprintf(stdout, ",\"trace_profile_id\":%u", AMDUAT_PEL_ENC_TRACE_DAG_V1); fprintf(stdout, ",\"result_profile_id\":%u}\n", AMDUAT_PEL_ENC_EXECUTION_RESULT_V1); } return AMDUAT_PEL_CLI_EXIT_OK; } static int amduat_pel_cli_cmd_scheme_dag_ref(int argc, char **argv) { amduat_pel_cli_ref_format_t fmt = AMDUAT_PEL_CLI_REF_HEX; amduat_reference_t scheme_ref; int i; for (i = 0; i < argc; ++i) { if (strcmp(argv[i], "--format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_ref_format(argv[++i], &fmt)) { fprintf(stderr, "error: invalid format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { amduat_pel_cli_print_usage(stdout); return AMDUAT_PEL_CLI_EXIT_OK; } else { fprintf(stderr, "error: unknown option: %s\n", argv[i]); return AMDUAT_PEL_CLI_EXIT_USAGE; } } scheme_ref = amduat_pel_program_dag_scheme_ref(); if (fmt == AMDUAT_PEL_CLI_REF_HEX) { char *text = NULL; if (!amduat_asl_ref_encode_hex(scheme_ref, &text)) { fprintf(stderr, "error: failed to encode scheme ref\n"); return AMDUAT_PEL_CLI_EXIT_CODEC; } fputs(text, stdout); fputc('\n', stdout); free(text); } else { amduat_octets_t encoded; if (!amduat_enc_asl1_core_encode_reference_v1(scheme_ref, &encoded)) { fprintf(stderr, "error: failed to encode scheme ref\n"); return AMDUAT_PEL_CLI_EXIT_CODEC; } if (!amduat_asl_write_stream(stdout, encoded.data, encoded.len)) { fprintf(stderr, "error: failed to write scheme ref\n"); free((void *)encoded.data); return AMDUAT_PEL_CLI_EXIT_IO; } free((void *)encoded.data); } return AMDUAT_PEL_CLI_EXIT_OK; } static int amduat_pel_cli_cmd_scheme( int argc, char **argv, const amduat_pel_cli_global_opts_t *global) { if (argc < 1) { fprintf(stderr, "error: scheme requires a subcommand\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (strcmp(argv[0], "show") == 0) { return amduat_pel_cli_cmd_scheme_show(argc - 1, argv + 1, global); } if (strcmp(argv[0], "dag-ref") == 0) { return amduat_pel_cli_cmd_scheme_dag_ref(argc - 1, argv + 1); } fprintf(stderr, "error: unknown scheme subcommand: %s\n", argv[0]); return AMDUAT_PEL_CLI_EXIT_USAGE; } static int amduat_pel_cli_cmd_help(int argc, char **argv) { (void)argc; (void)argv; amduat_pel_cli_print_usage(stdout); return AMDUAT_PEL_CLI_EXIT_OK; } int main(int argc, char **argv) { amduat_pel_cli_global_opts_t global; const char *command = NULL; int i; memset(&global, 0, sizeof(global)); global.root = AMDUAT_PEL_CLI_DEFAULT_ROOT; global.ref_format = AMDUAT_PEL_CLI_REF_HEX; global.format = AMDUAT_PEL_CLI_FORMAT_TEXT; global.quiet = false; for (i = 1; i < argc; ++i) { if (argv[i][0] != '-') { command = argv[i]; ++i; break; } if (strcmp(argv[i], "--root") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --root requires a path\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } global.root = argv[++i]; } else if (strcmp(argv[i], "--ref-format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --ref-format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_ref_format(argv[++i], &global.ref_format)) { fprintf(stderr, "error: invalid ref-format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --format requires a value\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (!amduat_pel_cli_parse_output_format(argv[++i], &global.format)) { fprintf(stderr, "error: invalid format\n"); return AMDUAT_PEL_CLI_EXIT_USAGE; } } else if (strcmp(argv[i], "--quiet") == 0) { global.quiet = true; } else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { amduat_pel_cli_print_usage(stdout); return AMDUAT_PEL_CLI_EXIT_OK; } else { fprintf(stderr, "error: unknown option: %s\n", argv[i]); return AMDUAT_PEL_CLI_EXIT_USAGE; } } if (command == NULL) { fprintf(stderr, "error: command required\n"); amduat_pel_cli_print_usage(stderr); return AMDUAT_PEL_CLI_EXIT_USAGE; } if (strcmp(command, "run") == 0) { return amduat_pel_cli_cmd_run(argc - i, argv + i, &global); } if (strcmp(command, "exec") == 0) { return amduat_pel_cli_cmd_exec(argc - i, argv + i, &global); } if (strcmp(command, "validate") == 0) { return amduat_pel_cli_cmd_validate(argc - i, argv + i, &global); } if (strcmp(command, "program") == 0) { return amduat_pel_cli_cmd_program(argc - i, argv + i, &global); } if (strcmp(command, "trace") == 0) { return amduat_pel_cli_cmd_trace(argc - i, argv + i, &global); } if (strcmp(command, "result") == 0) { return amduat_pel_cli_cmd_result(argc - i, argv + i, &global); } if (strcmp(command, "op") == 0) { return amduat_pel_cli_cmd_op(argc - i, argv + i, &global); } if (strcmp(command, "scheme") == 0) { return amduat_pel_cli_cmd_scheme(argc - i, argv + i, &global); } if (strcmp(command, "help") == 0) { return amduat_pel_cli_cmd_help(argc - i, argv + i); } fprintf(stderr, "error: unknown command: %s\n", command); amduat_pel_cli_print_usage(stderr); return AMDUAT_PEL_CLI_EXIT_USAGE; }