xref: /llvm-project/lldb/test/API/macosx/lc-note/kern-ver-str/create-empty-corefile.cpp (revision e9264b746b81a63323d884ea07b2ebfbb660d004)
199451b44SJordan Rupprecht #include <stdio.h>
299451b44SJordan Rupprecht #include <stdlib.h>
399451b44SJordan Rupprecht #include <mach-o/loader.h>
499451b44SJordan Rupprecht #include <vector>
599451b44SJordan Rupprecht #include <string>
699451b44SJordan Rupprecht #include <mach/thread_status.h>
799451b44SJordan Rupprecht #include <string.h>
899451b44SJordan Rupprecht #include <uuid/uuid.h>
999451b44SJordan Rupprecht 
1099451b44SJordan Rupprecht // Create an empty corefile with a "kern ver str" LC_NOTE.
1199451b44SJordan Rupprecht // If an existing binary is given as an optional 2nd argument on the cmd line,
1299451b44SJordan Rupprecht // the UUID from that binary will be encoded in the corefile.
1399451b44SJordan Rupprecht // Otherwise a pre-set UUID will be put in the corefile that
1499451b44SJordan Rupprecht // is created.
1599451b44SJordan Rupprecht 
1699451b44SJordan Rupprecht 
1799451b44SJordan Rupprecht union uint32_buf {
1899451b44SJordan Rupprecht     uint8_t bytebuf[4];
1999451b44SJordan Rupprecht     uint32_t val;
2099451b44SJordan Rupprecht };
2199451b44SJordan Rupprecht 
2299451b44SJordan Rupprecht union uint64_buf {
2399451b44SJordan Rupprecht     uint8_t bytebuf[8];
2499451b44SJordan Rupprecht     uint64_t val;
2599451b44SJordan Rupprecht };
2699451b44SJordan Rupprecht 
2799451b44SJordan Rupprecht void
add_uint64(std::vector<uint8_t> & buf,uint64_t val)2899451b44SJordan Rupprecht add_uint64(std::vector<uint8_t> &buf, uint64_t val)
2999451b44SJordan Rupprecht {
3099451b44SJordan Rupprecht     uint64_buf conv;
3199451b44SJordan Rupprecht     conv.val = val;
3299451b44SJordan Rupprecht     for (int i = 0; i < 8; i++)
3399451b44SJordan Rupprecht         buf.push_back(conv.bytebuf[i]);
3499451b44SJordan Rupprecht }
3599451b44SJordan Rupprecht 
3699451b44SJordan Rupprecht void
add_uint32(std::vector<uint8_t> & buf,uint32_t val)3799451b44SJordan Rupprecht add_uint32(std::vector<uint8_t> &buf, uint32_t val)
3899451b44SJordan Rupprecht {
3999451b44SJordan Rupprecht     uint32_buf conv;
4099451b44SJordan Rupprecht     conv.val = val;
4199451b44SJordan Rupprecht     for (int i = 0; i < 4; i++)
4299451b44SJordan Rupprecht         buf.push_back(conv.bytebuf[i]);
4399451b44SJordan Rupprecht }
4499451b44SJordan Rupprecht 
4599451b44SJordan Rupprecht std::vector<uint8_t>
x86_lc_thread_load_command()4699451b44SJordan Rupprecht x86_lc_thread_load_command ()
4799451b44SJordan Rupprecht {
4899451b44SJordan Rupprecht     std::vector<uint8_t> data;
4999451b44SJordan Rupprecht     add_uint32 (data, LC_THREAD);                // thread_command.cmd
5099451b44SJordan Rupprecht     add_uint32 (data, 184);                      // thread_command.cmdsize
5199451b44SJordan Rupprecht     add_uint32 (data, x86_THREAD_STATE64);       // thread_command.flavor
5299451b44SJordan Rupprecht     add_uint32 (data, x86_THREAD_STATE64_COUNT); // thread_command.count
5399451b44SJordan Rupprecht     add_uint64 (data, 0x0000000000000000);       // rax
5499451b44SJordan Rupprecht     add_uint64 (data, 0x0000000000000400);       // rbx
5599451b44SJordan Rupprecht     add_uint64 (data, 0x0000000000000000);       // rcx
5699451b44SJordan Rupprecht     add_uint64 (data, 0x0000000000000000);       // rdx
5799451b44SJordan Rupprecht     add_uint64 (data, 0x0000000000000000);       // rdi
5899451b44SJordan Rupprecht     add_uint64 (data, 0x0000000000000000);       // rsi
5999451b44SJordan Rupprecht     add_uint64 (data, 0xffffff9246e2ba20);       // rbp
6099451b44SJordan Rupprecht     add_uint64 (data, 0xffffff9246e2ba10);       // rsp
6199451b44SJordan Rupprecht     add_uint64 (data, 0x0000000000000000);       // r8
6299451b44SJordan Rupprecht     add_uint64 (data, 0x0000000000000000);       // r9
6399451b44SJordan Rupprecht     add_uint64 (data, 0x0000000000000000);       // r10
6499451b44SJordan Rupprecht     add_uint64 (data, 0x0000000000000000);       // r11
6599451b44SJordan Rupprecht     add_uint64 (data, 0xffffff7f96ce5fe1);       // r12
6699451b44SJordan Rupprecht     add_uint64 (data, 0x0000000000000000);       // r13
6799451b44SJordan Rupprecht     add_uint64 (data, 0x0000000000000000);       // r14
6899451b44SJordan Rupprecht     add_uint64 (data, 0xffffff9246e2bac0);       // r15
6999451b44SJordan Rupprecht     add_uint64 (data, 0xffffff8015a8f6d0);       // rip
7099451b44SJordan Rupprecht     add_uint64 (data, 0x0000000000011111);       // rflags
7199451b44SJordan Rupprecht     add_uint64 (data, 0x0000000000022222);       // cs
7299451b44SJordan Rupprecht     add_uint64 (data, 0x0000000000033333);       // fs
7399451b44SJordan Rupprecht     add_uint64 (data, 0x0000000000044444);       // gs
7499451b44SJordan Rupprecht     return data;
7599451b44SJordan Rupprecht }
7699451b44SJordan Rupprecht 
7799451b44SJordan Rupprecht void
add_lc_note_kern_ver_str_load_command(std::vector<std::vector<uint8_t>> & loadcmds,std::vector<uint8_t> & payload,int payload_file_offset,std::string ident)7899451b44SJordan Rupprecht add_lc_note_kern_ver_str_load_command (std::vector<std::vector<uint8_t> > &loadcmds,
7999451b44SJordan Rupprecht                                        std::vector<uint8_t> &payload,
8099451b44SJordan Rupprecht                                        int payload_file_offset,
8199451b44SJordan Rupprecht                                        std::string ident)
8299451b44SJordan Rupprecht {
8399451b44SJordan Rupprecht     std::vector<uint8_t> loadcmd_data;
8499451b44SJordan Rupprecht 
8599451b44SJordan Rupprecht     add_uint32 (loadcmd_data, LC_NOTE);          // note_command.cmd
8699451b44SJordan Rupprecht     add_uint32 (loadcmd_data, 40);               // note_command.cmdsize
8799451b44SJordan Rupprecht     char lc_note_name[16];
8899451b44SJordan Rupprecht     memset (lc_note_name, 0, 16);
8999451b44SJordan Rupprecht     strcpy (lc_note_name, "kern ver str");
9099451b44SJordan Rupprecht 
9199451b44SJordan Rupprecht     // lc_note.data_owner
9299451b44SJordan Rupprecht     for (int i = 0; i < 16; i++)
9399451b44SJordan Rupprecht         loadcmd_data.push_back (lc_note_name[i]);
9499451b44SJordan Rupprecht 
9599451b44SJordan Rupprecht     // we start writing the payload at payload_file_offset to leave
9699451b44SJordan Rupprecht     // room at the start for the header & the load commands.
9799451b44SJordan Rupprecht     uint64_t current_payload_offset = payload.size() + payload_file_offset;
9899451b44SJordan Rupprecht 
9999451b44SJordan Rupprecht     add_uint64 (loadcmd_data, current_payload_offset);   // note_command.offset
10099451b44SJordan Rupprecht     add_uint64 (loadcmd_data, 4 + ident.size() + 1);       // note_command.size
10199451b44SJordan Rupprecht 
10299451b44SJordan Rupprecht     loadcmds.push_back (loadcmd_data);
10399451b44SJordan Rupprecht 
10499451b44SJordan Rupprecht     add_uint32 (payload, 1);                 // kerneL_version_string.version
10599451b44SJordan Rupprecht     for (int i = 0; i < ident.size() + 1; i++)
10699451b44SJordan Rupprecht     {
10799451b44SJordan Rupprecht         payload.push_back (ident[i]);
10899451b44SJordan Rupprecht     }
10999451b44SJordan Rupprecht }
11099451b44SJordan Rupprecht 
11199451b44SJordan Rupprecht void
add_lc_segment(std::vector<std::vector<uint8_t>> & loadcmds,std::vector<uint8_t> & payload,int payload_file_offset)11299451b44SJordan Rupprecht add_lc_segment (std::vector<std::vector<uint8_t> > &loadcmds,
11399451b44SJordan Rupprecht                 std::vector<uint8_t> &payload,
11499451b44SJordan Rupprecht                 int payload_file_offset)
11599451b44SJordan Rupprecht {
11699451b44SJordan Rupprecht     std::vector<uint8_t> loadcmd_data;
11799451b44SJordan Rupprecht     struct segment_command_64 seg;
11899451b44SJordan Rupprecht     seg.cmd = LC_SEGMENT_64;
11999451b44SJordan Rupprecht     seg.cmdsize = sizeof (struct segment_command_64);  // no sections
12099451b44SJordan Rupprecht     memset (seg.segname, 0, 16);
12199451b44SJordan Rupprecht     seg.vmaddr = 0xffffff7f96400000;
12299451b44SJordan Rupprecht     seg.vmsize = 4096;
12399451b44SJordan Rupprecht     seg.fileoff = payload.size() + payload_file_offset;
12499451b44SJordan Rupprecht     seg.filesize = 0;
12599451b44SJordan Rupprecht     seg.maxprot = 1;
12699451b44SJordan Rupprecht     seg.initprot = 1;
12799451b44SJordan Rupprecht     seg.nsects = 0;
12899451b44SJordan Rupprecht     seg.flags = 0;
12999451b44SJordan Rupprecht 
13099451b44SJordan Rupprecht     uint8_t *p = (uint8_t*) &seg;
13199451b44SJordan Rupprecht     for (int i = 0; i < sizeof (struct segment_command_64); i++)
13299451b44SJordan Rupprecht     {
13399451b44SJordan Rupprecht         loadcmd_data.push_back (*(p + i));
13499451b44SJordan Rupprecht     }
13599451b44SJordan Rupprecht     loadcmds.push_back (loadcmd_data);
13699451b44SJordan Rupprecht }
13799451b44SJordan Rupprecht 
13899451b44SJordan Rupprecht std::string
get_uuid_from_binary(const char * fn)13999451b44SJordan Rupprecht get_uuid_from_binary (const char *fn)
14099451b44SJordan Rupprecht {
14199451b44SJordan Rupprecht     FILE *f = fopen(fn, "r");
14299451b44SJordan Rupprecht     if (f == nullptr)
14399451b44SJordan Rupprecht     {
14499451b44SJordan Rupprecht         fprintf (stderr, "Unable to open binary '%s' to get uuid\n", fn);
14599451b44SJordan Rupprecht         exit(1);
14699451b44SJordan Rupprecht     }
14799451b44SJordan Rupprecht 		uint32_t num_of_load_cmds = 0;
14899451b44SJordan Rupprecht 		uint32_t size_of_load_cmds = 0;
14999451b44SJordan Rupprecht 		std::string uuid;
15099451b44SJordan Rupprecht     off_t file_offset = 0;
15199451b44SJordan Rupprecht 
15299451b44SJordan Rupprecht     uint8_t magic[4];
15399451b44SJordan Rupprecht     if (::fread (magic, 1, 4, f) != 4)
15499451b44SJordan Rupprecht     {
15599451b44SJordan Rupprecht         fprintf (stderr, "Failed to read magic number from input file %s\n", fn);
15699451b44SJordan Rupprecht         exit (1);
15799451b44SJordan Rupprecht     }
15899451b44SJordan Rupprecht     uint8_t magic_32_be[] = {0xfe, 0xed, 0xfa, 0xce};
15999451b44SJordan Rupprecht     uint8_t magic_32_le[] = {0xce, 0xfa, 0xed, 0xfe};
16099451b44SJordan Rupprecht     uint8_t magic_64_be[] = {0xfe, 0xed, 0xfa, 0xcf};
16199451b44SJordan Rupprecht     uint8_t magic_64_le[] = {0xcf, 0xfa, 0xed, 0xfe};
16299451b44SJordan Rupprecht 
16399451b44SJordan Rupprecht     if (memcmp (magic, magic_32_be, 4) == 0 || memcmp (magic, magic_64_be, 4) == 0)
16499451b44SJordan Rupprecht     {
16599451b44SJordan Rupprecht         fprintf (stderr, "big endian corefiles not supported\n");
16699451b44SJordan Rupprecht         exit (1);
16799451b44SJordan Rupprecht     }
16899451b44SJordan Rupprecht 
16999451b44SJordan Rupprecht     ::fseeko (f, 0, SEEK_SET);
17099451b44SJordan Rupprecht     if (memcmp (magic, magic_32_le, 4) == 0)
17199451b44SJordan Rupprecht     {
17299451b44SJordan Rupprecht         struct mach_header mh;
17399451b44SJordan Rupprecht         if (::fread (&mh, 1, sizeof (mh), f) != sizeof (mh))
17499451b44SJordan Rupprecht         {
17599451b44SJordan Rupprecht             fprintf (stderr, "error reading mach header from input file\n");
17699451b44SJordan Rupprecht             exit (1);
17799451b44SJordan Rupprecht         }
17899451b44SJordan Rupprecht         if (mh.cputype != CPU_TYPE_X86_64)
17999451b44SJordan Rupprecht         {
18099451b44SJordan Rupprecht             fprintf (stderr, "This tool creates an x86_64 corefile but "
18199451b44SJordan Rupprecht                      "the supplied binary '%s' is cputype 0x%x\n",
18299451b44SJordan Rupprecht                      fn, (uint32_t) mh.cputype);
18399451b44SJordan Rupprecht             exit (1);
18499451b44SJordan Rupprecht         }
18599451b44SJordan Rupprecht 				num_of_load_cmds = mh.ncmds;
18699451b44SJordan Rupprecht 				size_of_load_cmds = mh.sizeofcmds;
18799451b44SJordan Rupprecht         file_offset += sizeof (struct mach_header);
18899451b44SJordan Rupprecht     }
18999451b44SJordan Rupprecht     else
19099451b44SJordan Rupprecht     {
19199451b44SJordan Rupprecht         struct mach_header_64 mh;
19299451b44SJordan Rupprecht         if (::fread (&mh, 1, sizeof (mh), f) != sizeof (mh))
19399451b44SJordan Rupprecht         {
19499451b44SJordan Rupprecht             fprintf (stderr, "error reading mach header from input file\n");
19599451b44SJordan Rupprecht             exit (1);
19699451b44SJordan Rupprecht         }
19799451b44SJordan Rupprecht         if (mh.cputype != CPU_TYPE_X86_64)
19899451b44SJordan Rupprecht         {
19999451b44SJordan Rupprecht             fprintf (stderr, "This tool creates an x86_64 corefile but "
20099451b44SJordan Rupprecht                      "the supplied binary '%s' is cputype 0x%x\n",
20199451b44SJordan Rupprecht                      fn, (uint32_t) mh.cputype);
20299451b44SJordan Rupprecht             exit (1);
20399451b44SJordan Rupprecht         }
20499451b44SJordan Rupprecht 				num_of_load_cmds = mh.ncmds;
20599451b44SJordan Rupprecht 				size_of_load_cmds = mh.sizeofcmds;
20699451b44SJordan Rupprecht         file_offset += sizeof (struct mach_header_64);
20799451b44SJordan Rupprecht     }
20899451b44SJordan Rupprecht 
20999451b44SJordan Rupprecht     off_t load_cmds_offset = file_offset;
21099451b44SJordan Rupprecht 
21199451b44SJordan Rupprecht     for (int i = 0; i < num_of_load_cmds && (file_offset - load_cmds_offset) < size_of_load_cmds; i++)
21299451b44SJordan Rupprecht     {
21399451b44SJordan Rupprecht         ::fseeko (f, file_offset, SEEK_SET);
21499451b44SJordan Rupprecht         uint32_t cmd;
21599451b44SJordan Rupprecht         uint32_t cmdsize;
21699451b44SJordan Rupprecht         ::fread (&cmd, sizeof (uint32_t), 1, f);
21799451b44SJordan Rupprecht         ::fread (&cmdsize, sizeof (uint32_t), 1, f);
21899451b44SJordan Rupprecht         if (cmd == LC_UUID)
21999451b44SJordan Rupprecht         {
22099451b44SJordan Rupprecht             struct uuid_command uuidcmd;
22199451b44SJordan Rupprecht             ::fseeko (f, file_offset, SEEK_SET);
22299451b44SJordan Rupprecht             if (::fread (&uuidcmd, 1, sizeof (uuidcmd), f) != sizeof (uuidcmd))
22399451b44SJordan Rupprecht             {
22499451b44SJordan Rupprecht                 fprintf (stderr, "Unable to read LC_UUID load command.\n");
22599451b44SJordan Rupprecht                 exit (1);
22699451b44SJordan Rupprecht             }
22799451b44SJordan Rupprecht             uuid_string_t uuidstr;
22899451b44SJordan Rupprecht             uuid_unparse (uuidcmd.uuid, uuidstr);
22999451b44SJordan Rupprecht             uuid = uuidstr;
23099451b44SJordan Rupprecht             break;
23199451b44SJordan Rupprecht         }
23299451b44SJordan Rupprecht         file_offset += cmdsize;
23399451b44SJordan Rupprecht     }
23499451b44SJordan Rupprecht     return uuid;
23599451b44SJordan Rupprecht }
23699451b44SJordan Rupprecht 
main(int argc,char ** argv)23799451b44SJordan Rupprecht int main (int argc, char **argv)
23899451b44SJordan Rupprecht {
23999451b44SJordan Rupprecht     if (argc != 2 && argc != 3)
24099451b44SJordan Rupprecht     {
24199451b44SJordan Rupprecht         fprintf (stderr, "usage: create-empty-corefile <output-core-name> [binary-to-copy-uuid-from]\n");
24299451b44SJordan Rupprecht         fprintf (stderr, "Create a Mach-O corefile with an LC_NOTE 'kern ver str' load command/payload\n");
24399451b44SJordan Rupprecht         fprintf (stderr, "If a binary is given as a second argument, the Mach-O UUID of that file will\n");
24499451b44SJordan Rupprecht         fprintf (stderr, "be read and used in the corefile's LC_NOTE payload.\n");
24599451b44SJordan Rupprecht         exit (1);
24699451b44SJordan Rupprecht     }
24799451b44SJordan Rupprecht 
24899451b44SJordan Rupprecht     std::string ident = "EFI UUID=3F9BA21F-55EA-356A-A349-BBA6F51FE8B1";
24999451b44SJordan Rupprecht     if (argc == 3)
25099451b44SJordan Rupprecht     {
25199451b44SJordan Rupprecht         std::string uuid_from_file = get_uuid_from_binary (argv[2]);
25299451b44SJordan Rupprecht         if (!uuid_from_file.empty())
25399451b44SJordan Rupprecht         {
25499451b44SJordan Rupprecht             ident = "EFI UUID=";
25599451b44SJordan Rupprecht             ident += uuid_from_file;
25699451b44SJordan Rupprecht         }
25799451b44SJordan Rupprecht     }
25899451b44SJordan Rupprecht 
25999451b44SJordan Rupprecht     // An array of load commands (in the form of byte arrays)
26099451b44SJordan Rupprecht     std::vector<std::vector<uint8_t> > load_commands;
26199451b44SJordan Rupprecht 
26299451b44SJordan Rupprecht     // An array of corefile contents (page data, lc_note data, etc)
26399451b44SJordan Rupprecht     std::vector<uint8_t> payload;
26499451b44SJordan Rupprecht 
26599451b44SJordan Rupprecht     // First add all the load commands / payload so we can figure out how large
26699451b44SJordan Rupprecht     // the load commands will actually be.
26799451b44SJordan Rupprecht     load_commands.push_back (x86_lc_thread_load_command());
26899451b44SJordan Rupprecht     add_lc_note_kern_ver_str_load_command (load_commands, payload, 0, ident);
26999451b44SJordan Rupprecht     add_lc_segment (load_commands, payload, 0);
27099451b44SJordan Rupprecht 
27199451b44SJordan Rupprecht     int size_of_load_commands = 0;
27299451b44SJordan Rupprecht     for (const auto &lc : load_commands)
27399451b44SJordan Rupprecht         size_of_load_commands += lc.size();
27499451b44SJordan Rupprecht 
27599451b44SJordan Rupprecht     int header_and_load_cmd_room = sizeof (struct mach_header_64) + size_of_load_commands;
27699451b44SJordan Rupprecht 
277*e9264b74SKazuaki Ishizaki     // Erase the load commands / payload now that we know how much space is needed,
27899451b44SJordan Rupprecht     // redo it.
27999451b44SJordan Rupprecht     load_commands.clear();
28099451b44SJordan Rupprecht     payload.clear();
28199451b44SJordan Rupprecht 
28299451b44SJordan Rupprecht     load_commands.push_back (x86_lc_thread_load_command());
28399451b44SJordan Rupprecht     add_lc_note_kern_ver_str_load_command (load_commands, payload, header_and_load_cmd_room, ident);
28499451b44SJordan Rupprecht     add_lc_segment (load_commands, payload, header_and_load_cmd_room);
28599451b44SJordan Rupprecht 
28699451b44SJordan Rupprecht     struct mach_header_64 mh;
28799451b44SJordan Rupprecht     mh.magic = MH_MAGIC_64;
28899451b44SJordan Rupprecht     mh.cputype = CPU_TYPE_X86_64;
28999451b44SJordan Rupprecht     mh.cpusubtype = CPU_SUBTYPE_X86_64_ALL;
29099451b44SJordan Rupprecht     mh.filetype = MH_CORE;
29199451b44SJordan Rupprecht     mh.ncmds = load_commands.size();
29299451b44SJordan Rupprecht     mh.sizeofcmds = size_of_load_commands;
29399451b44SJordan Rupprecht     mh.flags = 0;
29499451b44SJordan Rupprecht     mh.reserved = 0;
29599451b44SJordan Rupprecht 
29699451b44SJordan Rupprecht 
29799451b44SJordan Rupprecht     FILE *f = fopen (argv[1], "w");
29899451b44SJordan Rupprecht 
29999451b44SJordan Rupprecht     if (f == nullptr)
30099451b44SJordan Rupprecht     {
30199451b44SJordan Rupprecht         fprintf (stderr, "Unable to open file %s for writing\n", argv[1]);
30299451b44SJordan Rupprecht         exit (1);
30399451b44SJordan Rupprecht     }
30499451b44SJordan Rupprecht 
30599451b44SJordan Rupprecht     fwrite (&mh, sizeof (struct mach_header_64), 1, f);
30699451b44SJordan Rupprecht 
30799451b44SJordan Rupprecht     for (const auto &lc : load_commands)
30899451b44SJordan Rupprecht         fwrite (lc.data(), lc.size(), 1, f);
30999451b44SJordan Rupprecht 
31099451b44SJordan Rupprecht     fseek (f, header_and_load_cmd_room, SEEK_SET);
31199451b44SJordan Rupprecht 
31299451b44SJordan Rupprecht     fwrite (payload.data(), payload.size(), 1, f);
31399451b44SJordan Rupprecht 
31499451b44SJordan Rupprecht     fclose (f);
31599451b44SJordan Rupprecht }
316