Asm
/* $Id$ */
/* Copyright (c) 2015-2018 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS Devel Asm */
/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <System.h>
#include <string.h>
#include "Asm.h"
/* MBR */
/* private */
/* types */
struct _AsmFormatPlugin
{
AsmFormatPluginHelper * helper;
};
/* constants */
static const AsmSectionId _mbr_section_id_text = 0;
static const AsmSectionId _mbr_section_id_data = 1;
static const AsmSectionId _mbr_section_id_signature = 2;
static const uint8_t _mbr_signature[2] = { 0x55, 0xaa };
static const size_t _mbr_size_text = 446;
static const size_t _mbr_size_data = 64;
static const uint8_t _mbr_zeros[512];
/* prototypes */
/* plug-in */
static AsmFormatPlugin * _mbr_init(AsmFormatPluginHelper * helper,
char const * arch);
static int _mbr_destroy(AsmFormatPlugin * format);
static char const * _mbr_guess(AsmFormatPlugin * format, char const * hint);
static int _mbr_section(AsmFormatPlugin * format, char const * section);
static char const * _mbr_detect(AsmFormatPlugin * format);
static int _mbr_decode(AsmFormatPlugin * format, int raw);
static int _mbr_decode_section(AsmFormatPlugin * format, AsmSection * section,
AsmArchInstructionCall ** calls, size_t * calls_cnt);
/* public */
/* variables */
/* plug-in */
AsmFormatPluginDefinition format_plugin =
{
"mbr",
"Master Boot Record (MBR)",
LICENSE_GNU_LGPL3_FLAGS,
NULL,
0,
_mbr_init,
_mbr_destroy,
_mbr_guess,
NULL,
NULL,
_mbr_section,
_mbr_detect,
_mbr_decode,
_mbr_decode_section
};
/* private */
/* functions */
/* plug-in */
/* mbr_init */
static AsmFormatPlugin * _mbr_init(AsmFormatPluginHelper * helper,
char const * arch)
{
AsmFormatPlugin * mbr;
(void) arch;
if((mbr = object_new(sizeof(*mbr))) == NULL)
return NULL;
mbr->helper = helper;
return mbr;
}
/* mbr_destroy */
static int _mbr_destroy(AsmFormatPlugin * format)
{
int ret = 0;
AsmFormatPluginHelper * helper = format->helper;
long offset;
ssize_t size;
/* FIXME support writing to the data section too */
if((offset = helper->seek(helper->format, 0, SEEK_CUR)) > 446)
ret = -1;
else
{
size = sizeof(_mbr_zeros) - sizeof(_mbr_signature) - offset;
if(helper->write(helper->format, _mbr_zeros, size) != size
|| helper->write(helper->format,
_mbr_signature,
sizeof(_mbr_signature))
!= sizeof(_mbr_signature))
ret = -1;
}
object_delete(format);
return ret;
}
/* mbr_guess */
static char const * _mbr_guess(AsmFormatPlugin * format, char const * hint)
{
char const * arch[] = { "amd64", "i386", "i386_real", "i486", "i586",
"i686" };
size_t i;
(void) format;
/* XXX is it possible to switch in 32-bits (or 64-bits) mode? */
if(hint == NULL)
return "i386_real";
for(i = 0; i < sizeof(arch) / sizeof(*arch); i++)
if(string_compare(hint, arch[i]) == 0)
return "i386_real";
return NULL;
}
/* mbr_section */
static int _mbr_section(AsmFormatPlugin * format, char const * section)
{
(void) format;
(void) section;
/* ignore sections */
return 0;
}
/* mbr_decode */
static int _mbr_decode(AsmFormatPlugin * format, int raw)
{
AsmFormatPluginHelper * helper = format->helper;
(void) raw;
if(helper->seek(helper->format, 0, SEEK_END) >= 512
&& helper->set_section(helper->format,
_mbr_section_id_text, 0, ".text", 0,
_mbr_size_text, 0) != NULL
&& helper->set_section(helper->format,
_mbr_section_id_data, 0, ".data",
_mbr_size_text, _mbr_size_data, 0) != NULL
&& helper->set_section(helper->format,
_mbr_section_id_signature, 0, ".signature",
_mbr_size_text + _mbr_size_data,
sizeof(_mbr_signature), 0) != NULL)
return 0;
return -1;
}
/* mbr_decode_section */
static int _mbr_decode_section(AsmFormatPlugin * format, AsmSection * section,
AsmArchInstructionCall ** calls, size_t * calls_cnt)
{
AsmFormatPluginHelper * helper = format->helper;
if(section->id == 0)
return helper->decode(helper->format, section->offset,
section->size, section->base,
calls, calls_cnt);
if(section->id == 1 || section->id == 2)
/* FIXME decode as data */
return 0;
return -1;
}
/* mbr_detect */
static char const * _mbr_detect(AsmFormatPlugin * format)
{
AsmFormatPluginHelper * helper = format->helper;
uint8_t buf[512];
if(helper->seek(helper->format, 0, SEEK_SET) != 0
|| helper->read(helper->format, buf, sizeof(buf))
!= sizeof(buf))
{
error_set_code(1, "%s: %s 0x%x", format_plugin.name,
"Could not read the bootloader image");
return NULL;
}
if(buf[510] != _mbr_signature[0] || buf[511] != _mbr_signature[1])
{
error_set_code(1, "%s: %s 0x%x", format_plugin.name,
"Could not find the MBR signature");
return NULL;
}
return "i386_real";
}