SceError: Difference between revisions

From Vita Development Wiki
Jump to navigation Jump to search
No edit summary
 
(25 intermediate revisions by 3 users not shown)
Line 1: Line 1:
== Module ==
== Module ==


=== Known NIDs ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! Name !! World !! Privilege !! NID
! Version !! World !! Privilege
|-
|-
| 1.69 || SceError || Non-secure || Kernel || 0x802086B7
| 1.69-3.60 || Non-secure || Kernel
|}
|}


Line 19: Line 18:
| 1.69 || [[SceError#SceErrorForDriver|SceErrorForDriver]] || Non-secure || Kernel || 0xBA576248
| 1.69 || [[SceError#SceErrorForDriver|SceErrorForDriver]] || Non-secure || Kernel || 0xBA576248
|-
|-
| 1.69 || [[SceError#SceError|SceError]] || Non-secure || User || 0x5CD2CAD1
| 1.69-3.60 || [[SceError#SceError|SceError]] || Non-secure || User || 0x5CD2CAD1
|}
|}


== SceErrorForDriver ==
= Types =
<source lang="C">
typedef struct SceErrorDefaultFormat {
int data1;
int data2;
} SceErrorDefaultFormat;
 
typedef struct SceErrorStrings {
char s[0x10];
} SceErrorStrings;
 
typedef struct SceErrorHistoryPostInfo { // size is 0x180
char error_message[0x100];
char data_0x100[0x40]; // unknown
int error_code_hex;
int data_0x174;
SceUInt version; // from SceKernelFwInfo
int data_0x17C;
char titleid[0xC];
int data_0x15C; // from SceKernelFwInfo->unk_24
char data_0x160[0x20];
} SceErrorHistoryPostInfo;
 
typedef struct SceErrorHistoryInfo {
int data_0x00;
int data_0x04;
SceInt64 time;
SceErrorStrings error_code;
char data_0x20[0x10];
SceErrorHistoryPostInfo post;
} SceErrorHistoryInfo;
 
typedef struct SceErrorSequenceInfo { // size is 0x20
int data[8];
} SceErrorSequenceInfo;
</source>
 
= SceErrorForDriver =


== SceError ==
= SceError =


=== _sceErrorHistoryUpdateSequenceInfo ===
=== _sceErrorHistoryUpdateSequenceInfo ===
Line 31: Line 67:
! Version !! NID
! Version !! NID
|-
|-
| 1.69 || 0x6FBE4BDC
| 1.69-3.60 || 0x6FBE4BDC
|-
| 3.60 || 0x6FBE4BDC
|}
|}
<source lang="c">int _sceErrorHistoryUpdateSequenceInfo(const SceErrorSequenceInfo *info, int a2);</source>
=== _sceErrorHistoryPostError ===
=== _sceErrorHistoryPostError ===
{| class="wikitable"
{| class="wikitable"
Line 40: Line 77:
! Version !! NID
! Version !! NID
|-
|-
| 1.69 || 0x70F9D872
| 1.69-3.60 || 0x70F9D872
|-
| 3.60 || 0x70F9D872
|}
|}


<source lang="c">
<source lang="c">int _sceErrorHistoryPostError(const SceErrorHistoryPostInfo *info);</source>
//src_user is of size 0x180
int _sceErrorHistoryPostError(char* src_user)
</source>


=== _sceErrorGetExternalString ===
=== _sceErrorGetExternalString ===
Line 55: Line 87:
! Version !! NID
! Version !! NID
|-
|-
| 1.69 || 0x85747003
| 1.69-3.60 || 0x85747003
|-
| 3.60 || 0x85747003
|}
|}


<source lang="C">
<source lang="C">int _sceErrorGetExternalString(SceErrorStrings *error_strings, int error_code);</source>
//dest is of size 0x10
int _sceErrorGetExternalString(char* dest_user, int unk)
</source>


=== _sceErrorHistorySetDefaultFormat ===
=== _sceErrorHistorySetDefaultFormat ===
Line 70: Line 97:
! Version !! NID
! Version !! NID
|-
|-
| 1.69 || 0xB94DAA2F
| 1.69-3.60 || 0xB94DAA2F
|-
| 3.60 || 0xB94DAA2F
|}
|}
<source lang="c">int _sceErrorHistorySetDefaultFormat(const SceErrorDefaultFormat *a1);</source>
=== _sceErrorHistoryClearError ===
=== _sceErrorHistoryClearError ===
{| class="wikitable"
{| class="wikitable"
Line 79: Line 107:
! Version !! NID
! Version !! NID
|-
|-
| 1.69 || 0xC88F479E
| 1.69-3.60 || 0xC88F479E
|-
| 3.60 || 0xC88F479E
|}
|}


<source lang="c">
<source lang="c">
//argument can be only 0, or SCE_ERROR_ERRNO_EINVAL error will be returned
// argument can be only 0, or SCE_ERROR_ERRNO_EINVAL error will be returned
int _sceErrorHistoryClearError(int zero)
int _sceErrorHistoryClearError(int ch);
</source>
</source>


Line 94: Line 120:
! Version !! NID
! Version !! NID
|-
|-
| 1.69 || 0xF16DF981
| 1.69-3.60 || 0xF16DF981
|-
| 3.60 || 0xF16DF981
|}
|}


<source lang="c">int _sceErrorHistoryGetError (int unk0, char *dest_user)</source>
<source lang="c">int _sceErrorHistoryGetError(SceUInt32 error_idx, SceErrorHistoryInfo *info);</source>
 
= Error table translation =
 
In various places PSVita may display errors translated into their string representation. The code below also does this, provided you feed it with a copy of <code>os0:kd/error_table.bin</code>.


== Error translation ==
In various places Vita may display errors translated into their string representation. The code below also does this, provided you feed it with a copy of <code>os0:kd/error_table.bin</code>.
<source lang="c">
<source lang="c">
#include <stdlib.h>
#include <stdlib.h>
Line 111: Line 137:
#endif
#endif


int read_error_table(const char *path, void *buf)
int read_error_table(const char *path, void *buf) {
{
   unsigned int v6; // r1@6
   unsigned int v6; // r1@6
   unsigned int v7; // r1@10
   unsigned int v7; // r1@10


   FILE *f = fopen(path, "rb");
   FILE *f = fopen(path, "rb");
   if ( f )
   if ( f ) {
  {
     if ( fread(buf, 1, 8, f) == 8 ) {
     if ( fread(buf, 1, 8, f) == 8 )
    {
       v6 = *((short *)buf + 2);
       v6 = *((short *)buf + 2);
       if ( v6 <= 0x20 )
       if ( v6 <= 0x20 )
       {
       {
         if ( fread(*((int *)buf + 2), 1, 8 * v6, f) == 8 * v6
         if ( fread(*((int *)buf + 2), 1, 8 * v6, f) == 8 * v6
           && fread((char *)buf + 12, 1, 4, f) == 4 )
           && fread((char *)buf + 12, 1, 4, f) == 4 ) {
        {
           v7 = *((short *)buf + 7);
           v7 = *((short *)buf + 7);
           if ( v7 <= 0x36B0 )
           if ( v7 <= 0x36B0 ) {
          {
             if ( fread(*((int *)buf + 4), 1, 4 * v7, f) == 4 * v7 ) {
             if ( fread(*((int *)buf + 4), 1, 4 * v7, f) == 4 * v7 )
            {
               fclose(f);
               fclose(f);
               return 0;
               return 0;
Line 137: Line 157:
           }
           }
           else
           else
          {
             fprintf(stderr, "[SceError] error_table_num = %d\n", v7);
             fprintf(stderr, "[SceError] error_table_num = %d\n", v7);
          }
         }
         }
       }
       }
       else
       else
      {
         fprintf(stderr, "[SceError] facility_group_num = %d\n", v6);
         fprintf(stderr, "[SceError] facility_group_num = %d\n", v6);
      }
     }
     }
     fclose(f);
     fclose(f);
Line 162: Line 178:
#define _BYTE char
#define _BYTE char


int error_code_to_string(int error_table, char *output, unsigned int error_code)
int error_code_to_string(int error_table, char *output, unsigned int error_code) {
{
     signed int v4; // r7@2
     signed int v4; // r7@2
     int v5; // r4@2
     int v5; // r4@2
Line 205: Line 220:
     if (!*(_WORD *)(error_table + 14))
     if (!*(_WORD *)(error_table + 14))
         goto LABEL_46;
         goto LABEL_46;
     if (*(_DWORD *)v5 == error_code)
     if (*(_DWORD *)v5 == error_code) {
    {
         v6 = 0;
         v6 = 0;
         goto LABEL_17;
         goto LABEL_17;
Line 215: Line 229:
         goto LABEL_11;
         goto LABEL_11;
     v6 = 1;
     v6 = 1;
     if (v4 <= 1)
     if (v4 <= 1) {
    {
     LABEL_46:
     LABEL_46:
         snprintf(output, 16, "E-%08x", error_code);
         snprintf(output, 16, "E-%08x", error_code);
Line 223: Line 236:
     v8 = *(_DWORD *)(v5 + 4);
     v8 = *(_DWORD *)(v5 + 4);
     v5 += 4;
     v5 += 4;
     if (v8 != error_code)
     if (v8 != error_code) {
    {
         if (v7 == 1
         if (v7 == 1
             || (v7 == 2 || (v9 = *(_DWORD *)(v5 + 4), v5 += 4, v6 = 2, v9 != error_code))
             || (v7 == 2 || (v9 = *(_DWORD *)(v5 + 4), v5 += 4, v6 = 2, v9 != error_code))
             && (v10 = *(_DWORD *)(v5 + 4), v5 += 4, ++v6, v10 != error_code))
             && (v10 = *(_DWORD *)(v5 + 4), v5 += 4, ++v6, v10 != error_code)) {
        {
         LABEL_11:
         LABEL_11:
             while (1)
             while (1) {
            {
                 ++v6;
                 ++v6;
                 v11 = v5;
                 v11 = v5;
Line 241: Line 251:
                 v15 = *(_DWORD *)(v11 + 4);
                 v15 = *(_DWORD *)(v11 + 4);
                 v14 = v11 + 4;
                 v14 = v11 + 4;
                 if (v15 != error_code)
                 if (v15 != error_code) {
                {
                     v17 = *(_DWORD *)(v14 + 4);
                     v17 = *(_DWORD *)(v14 + 4);
                     v16 = v14 + 4;
                     v16 = v14 + 4;
                     ++v6;
                     ++v6;
                     if (v17 != error_code)
                     if (v17 != error_code) {
                    {
                         v6 = v13 + 2;
                         v6 = v13 + 2;
                         if (*(_DWORD *)(v16 + 4) != error_code)
                         if (*(_DWORD *)(v16 + 4) != error_code) {
                        {
                             v6 = v13 + 3;
                             v6 = v13 + 3;
                             if (*(_DWORD *)(v12 + 4) != error_code)
                             if (*(_DWORD *)(v12 + 4) != error_code)
Line 261: Line 268:
         }
         }
     }
     }
     if (*(_WORD *)(error_table + 6) < v6)
     if (*(_WORD *)(error_table + 6) < v6) {
    {
         snprintf(output, 16, "*-%08x", error_code);
         snprintf(output, 16, "*-%08x", error_code);
         return 0;
         return 0;
Line 270: Line 276:
     v19 = (error_code >> 16) & 0xFFF;
     v19 = (error_code >> 16) & 0xFFF;
     v20 = *(_DWORD *)(error_table + 8);
     v20 = *(_DWORD *)(error_table + 8);
     if (*(_WORD *)(error_table + 4))
     if (*(_WORD *)(error_table + 4)) {
    {
         v21 = 0;
         v21 = 0;
         v22 = ((_BYTE)v18 - 1) & 3;
         v22 = ((_BYTE)v18 - 1) & 3;
         if (!(((_BYTE)v18 - 1) & 3))
         if (!(((_BYTE)v18 - 1) & 3)) {
        {
         LABEL_35:
         LABEL_35:
             while (1)
             while (1) {
            {
                 v30 = *(_WORD *)v20;
                 v30 = *(_WORD *)v20;
                 if ((signed int)v19 >= v30 && (signed int)v19 < *(_WORD *)(v20 + 2) + v30)
                 if ((signed int)v19 >= v30 && (signed int)v19 < *(_WORD *)(v20 + 2) + v30)
Line 303: Line 306:
         }
         }
         v23 = *(_WORD *)v20;
         v23 = *(_WORD *)v20;
         if ((signed int)v19 >= v23 && (signed int)v19 < *(_WORD *)(v20 + 2) + v23)
         if ((signed int)v19 >= v23 && (signed int)v19 < *(_WORD *)(v20 + 2) + v23) {
        {
         LABEL_48:
         LABEL_48:
             v32 = v20 + 4;
             v32 = v20 + 4;
Line 310: Line 312:
         }
         }
         v21 = 1;
         v21 = 1;
         if (v18 > 1)
         if (v18 > 1) {
        {
             v20 += 8;
             v20 += 8;
             if (v22 == 1)
             if (v22 == 1)
                 goto LABEL_35;
                 goto LABEL_35;
             if (v22 != 2)
             if (v22 != 2) {
            {
                 v24 = *(_WORD *)v20;
                 v24 = *(_WORD *)v20;
                 if ((signed int)v19 >= v24 && (signed int)v19 < *(_WORD *)(v20 + 2) + v24)
                 if ((signed int)v19 >= v24 && (signed int)v19 < *(_WORD *)(v20 + 2) + v24) {
                {
                     v32 = v20 + 4;
                     v32 = v20 + 4;
                     goto LABEL_39;
                     goto LABEL_39;
Line 327: Line 326:
             }
             }
             v25 = *(_WORD *)v20;
             v25 = *(_WORD *)v20;
             if ((signed int)v19 < v25 || (signed int)v19 >= *(_WORD *)(v20 + 2) + v25)
             if ((signed int)v19 < v25 || (signed int)v19 >= *(_WORD *)(v20 + 2) + v25) {
            {
                 ++v21;
                 ++v21;
                 v20 += 8;
                 v20 += 8;
Line 340: Line 338:
LABEL_39:
LABEL_39:
     v33 = v6 + *(_WORD *)(error_table + 12);
     v33 = v6 + *(_WORD *)(error_table + 12);
     if (v33)
     if (v33) {
    {
         v35 = v6 + *(_WORD *)(error_table + 12);
         v35 = v6 + *(_WORD *)(error_table + 12);
         v36 = 0;
         v36 = 0;
         do
         do {
        {
             v37 = v35 % 10;
             v37 = v35 % 10;
             v35 /= 10;
             v35 /= 10;
Line 353: Line 349:
     }
     }
     else
     else
    {
         v34 = 0;
         v34 = 0;
    }
     snprintf(output, 16, "%s-%d-%1d", v32, v33, v34);
     snprintf(output, 16, "%s-%d-%1d", v32, v33, v34);
     return 0;
     return 0;
Line 383: Line 377:
</source>
</source>


[[Category:ARM]]
[[Category:Kernel]]
[[Category:Modules]]
[[Category:Modules]]
[[Category:Kernel]]
[[Category:Library]]

Latest revision as of 21:01, 1 May 2023

Module

Version World Privilege
1.69-3.60 Non-secure Kernel

Libraries

Known NIDs

Version Name World Visibility NID
1.69 SceErrorForDriver Non-secure Kernel 0xBA576248
1.69-3.60 SceError Non-secure User 0x5CD2CAD1

Types

typedef struct SceErrorDefaultFormat {
	int data1;
	int data2;
} SceErrorDefaultFormat;

typedef struct SceErrorStrings {
	char s[0x10];
} SceErrorStrings;

typedef struct SceErrorHistoryPostInfo { // size is 0x180
	char error_message[0x100];
	char data_0x100[0x40]; // unknown
	int error_code_hex;
	int data_0x174;
	SceUInt version;	// from SceKernelFwInfo
	int data_0x17C;
	char titleid[0xC];
	int data_0x15C;		// from SceKernelFwInfo->unk_24
	char data_0x160[0x20];
} SceErrorHistoryPostInfo;

typedef struct SceErrorHistoryInfo {
	int data_0x00;
	int data_0x04;
	SceInt64 time;
	SceErrorStrings error_code;
	char data_0x20[0x10];
	SceErrorHistoryPostInfo post;
} SceErrorHistoryInfo;

typedef struct SceErrorSequenceInfo { // size is 0x20
	int data[8];
} SceErrorSequenceInfo;

SceErrorForDriver

SceError

_sceErrorHistoryUpdateSequenceInfo

Version NID
1.69-3.60 0x6FBE4BDC
int _sceErrorHistoryUpdateSequenceInfo(const SceErrorSequenceInfo *info, int a2);

_sceErrorHistoryPostError

Version NID
1.69-3.60 0x70F9D872
int _sceErrorHistoryPostError(const SceErrorHistoryPostInfo *info);

_sceErrorGetExternalString

Version NID
1.69-3.60 0x85747003
int _sceErrorGetExternalString(SceErrorStrings *error_strings, int error_code);

_sceErrorHistorySetDefaultFormat

Version NID
1.69-3.60 0xB94DAA2F
int _sceErrorHistorySetDefaultFormat(const SceErrorDefaultFormat *a1);

_sceErrorHistoryClearError

Version NID
1.69-3.60 0xC88F479E
// argument can be only 0, or SCE_ERROR_ERRNO_EINVAL error will be returned
int _sceErrorHistoryClearError(int ch);

_sceErrorHistoryGetError

Version NID
1.69-3.60 0xF16DF981
int _sceErrorHistoryGetError(SceUInt32 error_idx, SceErrorHistoryInfo *info);

Error table translation

In various places PSVita may display errors translated into their string representation. The code below also does this, provided you feed it with a copy of os0:kd/error_table.bin.

#include <stdlib.h>
#include <stdio.h>

#ifdef _MSC_VER
#define snprintf _snprintf
#endif

int read_error_table(const char *path, void *buf) {
  unsigned int v6; // r1@6
  unsigned int v7; // r1@10

  FILE *f = fopen(path, "rb");
  if ( f ) {
    if ( fread(buf, 1, 8, f) == 8 ) {
      v6 = *((short *)buf + 2);
      if ( v6 <= 0x20 )
      {
        if ( fread(*((int *)buf + 2), 1, 8 * v6, f) == 8 * v6
          && fread((char *)buf + 12, 1, 4, f) == 4 ) {
          v7 = *((short *)buf + 7);
          if ( v7 <= 0x36B0 ) {
            if ( fread(*((int *)buf + 4), 1, 4 * v7, f) == 4 * v7 ) {
              fclose(f);
              return 0;
            }
          }
          else
            fprintf(stderr, "[SceError] error_table_num = %d\n", v7);
        }
      }
      else
        fprintf(stderr, "[SceError] facility_group_num = %d\n", v6);
    }
    fclose(f);
  }
  *(int *)buf = 0;
  *((int *)buf + 1) = 0;
  *((int *)buf + 2) = 0;
  *((int *)buf + 3) = 0;
  *((int *)buf + 4) = 0;
  *((int *)buf + 5) = 0;
  return 0;
}

#define _WORD short
#define _DWORD int
#define _BYTE char

int error_code_to_string(int error_table, char *output, unsigned int error_code) {
    signed int v4; // r7@2
    int v5; // r4@2
    int v6; // r2@4
    int v7; // r5@4
    int v8; // t1@6
    int v9; // t1@9
    int v10; // t1@10
    int v11; // r5@11
    int v12; // r12@11
    int v13; // r6@11
    int v14; // r5@12
    int v15; // t1@12
    int v16; // r5@13
    int v17; // t1@13
    signed int v18; // lr@17
    unsigned int v19; // r3@17
    int v20; // r4@17
    int v21; // r6@18
    int v22; // r5@18
    signed int v23; // r6@19
    signed int v24; // r5@23
    signed int v25; // r5@25
    signed int v26; // r7@28
    int v27; // r5@28
    signed int v28; // r7@30
    signed int v29; // r7@32
    signed int v30; // r5@35
    int v31; // r6@37
    int v32; // r3@38
    int v33; // r4@39
    int v34; // r5@40
    signed int v35; // r2@41
    signed int v36; // r6@41
    int v37; // r7@42

    if (!output)
        return 0;
    v4 = *(_WORD *)(error_table + 14);
    v5 = *(_DWORD *)(error_table + 16);
    if (!*(_WORD *)(error_table + 14))
        goto LABEL_46;
    if (*(_DWORD *)v5 == error_code) {
        v6 = 0;
        goto LABEL_17;
    }
    v6 = 0;
    v7 = ((_BYTE)v4 - 1) & 3;
    if (!(((_BYTE)v4 - 1) & 3))
        goto LABEL_11;
    v6 = 1;
    if (v4 <= 1) {
    LABEL_46:
        snprintf(output, 16, "E-%08x", error_code);
        return 0;
    }
    v8 = *(_DWORD *)(v5 + 4);
    v5 += 4;
    if (v8 != error_code) {
        if (v7 == 1
            || (v7 == 2 || (v9 = *(_DWORD *)(v5 + 4), v5 += 4, v6 = 2, v9 != error_code))
            && (v10 = *(_DWORD *)(v5 + 4), v5 += 4, ++v6, v10 != error_code)) {
        LABEL_11:
            while (1) {
                ++v6;
                v11 = v5;
                v12 = v5 + 12;
                v13 = v6;
                v5 += 16;
                if (v6 >= v4)
                    goto LABEL_46;
                v15 = *(_DWORD *)(v11 + 4);
                v14 = v11 + 4;
                if (v15 != error_code) {
                    v17 = *(_DWORD *)(v14 + 4);
                    v16 = v14 + 4;
                    ++v6;
                    if (v17 != error_code) {
                        v6 = v13 + 2;
                        if (*(_DWORD *)(v16 + 4) != error_code) {
                            v6 = v13 + 3;
                            if (*(_DWORD *)(v12 + 4) != error_code)
                                continue;
                        }
                    }
                }
                break;
            }
        }
    }
    if (*(_WORD *)(error_table + 6) < v6) {
        snprintf(output, 16, "*-%08x", error_code);
        return 0;
    }
LABEL_17:
    v18 = *(_WORD *)(error_table + 4);
    v19 = (error_code >> 16) & 0xFFF;
    v20 = *(_DWORD *)(error_table + 8);
    if (*(_WORD *)(error_table + 4)) {
        v21 = 0;
        v22 = ((_BYTE)v18 - 1) & 3;
        if (!(((_BYTE)v18 - 1) & 3)) {
        LABEL_35:
            while (1) {
                v30 = *(_WORD *)v20;
                if ((signed int)v19 >= v30 && (signed int)v19 < *(_WORD *)(v20 + 2) + v30)
                    goto LABEL_48;
                v31 = v21 + 1;
                if (v31 >= v18)
                    goto LABEL_38;
                v20 += 8;
                v26 = *(_WORD *)v20;
                v27 = v20;
                if ((signed int)v19 >= v26 && (signed int)v19 < v26 + *(_WORD *)(v20 + 2))
                    goto LABEL_48;
                v28 = *(_WORD *)(v20 + 8);
                v20 += 8;
                if ((signed int)v19 >= v28 && (signed int)v19 < v28 + *(_WORD *)(v27 + 10))
                    goto LABEL_48;
                v29 = *(_WORD *)(v27 + 16);
                v20 = v27 + 16;
                if ((signed int)v19 >= v29 && (signed int)v19 < v29 + *(_WORD *)(v27 + 18))
                    goto LABEL_48;
                v21 = v31 + 3;
                v20 = v27 + 24;
            }
        }
        v23 = *(_WORD *)v20;
        if ((signed int)v19 >= v23 && (signed int)v19 < *(_WORD *)(v20 + 2) + v23) {
        LABEL_48:
            v32 = v20 + 4;
            goto LABEL_39;
        }
        v21 = 1;
        if (v18 > 1) {
            v20 += 8;
            if (v22 == 1)
                goto LABEL_35;
            if (v22 != 2) {
                v24 = *(_WORD *)v20;
                if ((signed int)v19 >= v24 && (signed int)v19 < *(_WORD *)(v20 + 2) + v24) {
                    v32 = v20 + 4;
                    goto LABEL_39;
                }
                v21 = 2;
                v20 += 8;
            }
            v25 = *(_WORD *)v20;
            if ((signed int)v19 < v25 || (signed int)v19 >= *(_WORD *)(v20 + 2) + v25) {
                ++v21;
                v20 += 8;
                goto LABEL_35;
            }
            goto LABEL_48;
        }
    }
LABEL_38:
    v32 = error_table;
LABEL_39:
    v33 = v6 + *(_WORD *)(error_table + 12);
    if (v33) {
        v35 = v6 + *(_WORD *)(error_table + 12);
        v36 = 0;
        do {
            v37 = v35 % 10;
            v35 /= 10;
            v36 += v37;
        } while (v35);
        v34 = v36 % 10;
    }
    else
        v34 = 0;
    snprintf(output, 16, "%s-%d-%1d", v32, v33, v34);
    return 0;
}

int main(int argc, char *argv[]) {
    if (argc != 3) {
        fprintf(stderr, "Usage: ./error error_table.bin 0xC0DE");
        return 1;
    }
    int *error_table = calloc(1, 1024 * 1024);
    error_table[2] = calloc(1, 1024 * 1024);
    error_table[4] = calloc(1, 1024 * 1024);
    read_error_table(argv[1], error_table);

    char *str = calloc(1, 500);
    error_code_to_string(error_table, str, strtoul(argv[2], NULL, 0));
    printf("%s\n", str);

    free(str);
    free(error_table[2]);
    free(error_table[4]);
    free(error_table);

    return 0;
}