diff --git a/debug/gdbinit b/debug/gdbinit index 822e958..599d2b1 100644 --- a/debug/gdbinit +++ b/debug/gdbinit @@ -1618,3 +1618,1624 @@ python Dashboard.start() # Local Variables: # mode: python # End: +python +# MODIFIE pour gestion UTF8 par Nicolas Hordé +# GDB dashboard - Modular visual interface for GDB in Python. +# +# https://github.com/cyrus-and/gdb-dashboard +import codecs +import ast +import fcntl +import os +import re +import struct +import termios +import traceback +import math + +# -*- coding: utf-8 -*- +# Common attributes ------------------------------------------------------------ + +class R(): + + @staticmethod + def attributes(): + return { + # miscellaneous + 'ansi': { + 'doc': 'Control the ANSI output of the dashboard.', + 'default': True, + 'type': bool + }, + 'syntax_highlighting': { + 'doc': """Pygments style to use for syntax highlighting. +Using an empty string (or a name not in the list) disables this feature. +The list of all the available styles can be obtained with (from GDB itself): + + python from pygments.styles import get_all_styles as styles + python for s in styles(): print(s) +""", + 'default': 'vim', + 'type': str + }, + # prompt + 'prompt': { + 'doc': """Command prompt. +This value is parsed as a Python format string in which `{status}` is expanded +with the substitution of either `prompt_running` or `prompt_not_running` +attributes, according to the target program status. The resulting string must be +a valid GDB prompt, see the command `python print(gdb.prompt.prompt_help())`""", + 'default': '{status}' + }, + 'prompt_running': { + 'doc': """`{status}` when the target program is running. +See the `prompt` attribute. This value is parsed as a Python format string in +which `{pid}` is expanded with the process identifier of the target program.""", + 'default': '\[\e[1;35m\]>>>\[\e[0m\]' + }, + 'prompt_not_running': { + 'doc': '`{status}` when the target program is not running.', + 'default': '\[\e[1;30m\]>>>\[\e[0m\]' + }, + # divider + 'divider_fill_char_primary': { + 'doc': 'Filler around the label for primary dividers', + 'default': '─' + }, + 'divider_fill_char_secondary': { + 'doc': 'Filler around the label for secondary dividers', + 'default': '─' + }, + 'divider_fill_style_primary': { + 'doc': 'Style for `divider_fill_char_primary`', + 'default': '36' + }, + 'divider_fill_style_secondary': { + 'doc': 'Style for `divider_fill_char_secondary`', + 'default': '1;30' + }, + 'divider_label_style_on_primary': { + 'doc': 'Label style for non-empty primary dividers', + 'default': '1;33' + }, + 'divider_label_style_on_secondary': { + 'doc': 'Label style for non-empty secondary dividers', + 'default': '0' + }, + 'divider_label_style_off_primary': { + 'doc': 'Label style for empty primary dividers', + 'default': '33' + }, + 'divider_label_style_off_secondary': { + 'doc': 'Label style for empty secondary dividers', + 'default': '1;30' + }, + 'divider_label_skip': { + 'doc': 'Gap between the aligning border and the label.', + 'default': 3, + 'type': int, + 'check': check_ge_zero + }, + 'divider_label_margin': { + 'doc': 'Number of spaces around the label.', + 'default': 1, + 'type': int, + 'check': check_ge_zero + }, + 'divider_label_align_right': { + 'doc': 'Label alignment flag.', + 'default': False, + 'type': bool + }, + # common styles + 'style_selected_1': { + 'default': '1;32' + }, + 'style_selected_2': { + 'default': '32' + }, + 'style_low': { + 'default': '1;30' + }, + 'style_high': { + 'default': '1;37' + }, + 'style_error': { + 'default': '31' + } + } + +# Common ----------------------------------------------------------------------- + +def run(command): + return gdb.execute(command, to_string=True) + +def ansi(string, style): + if R.ansi: + return '\x1b[{}m{}\x1b[0m'.format(style, string) + else: + return string + +def divider(width, label='', primary=False, active=True): + if primary: + divider_fill_style = R.divider_fill_style_primary + divider_fill_char = R.divider_fill_char_primary + divider_label_style_on = R.divider_label_style_on_primary + divider_label_style_off = R.divider_label_style_off_primary + else: + divider_fill_style = R.divider_fill_style_secondary + divider_fill_char = R.divider_fill_char_secondary + divider_label_style_on = R.divider_label_style_on_secondary + divider_label_style_off = R.divider_label_style_off_secondary + if label: + if active: + divider_label_style = divider_label_style_on + else: + divider_label_style = divider_label_style_off + skip = R.divider_label_skip + margin = R.divider_label_margin + before = ansi(divider_fill_char * skip, divider_fill_style) + middle = ansi(label, divider_label_style) + after_length = width - len(label) - skip - 2 * margin + after = ansi(divider_fill_char * after_length, divider_fill_style) + if R.divider_label_align_right: + before, after = after, before + return ''.join([before, ' ' * margin, middle, ' ' * margin, after]) + else: + return ansi(divider_fill_char * width, divider_fill_style) + +def check_gt_zero(x): + return x > 0 + +def check_ge_zero(x): + return x >= 0 + +def to_unsigned(value, size=8): + # values from GDB can be used transparently but are not suitable for + # being printed as unsigned integers, so a conversion is needed + mask = (2 ** (size * 8)) - 1 + return int(value.cast(gdb.Value(mask).type)) & mask + +def to_string(value): + # attempt to convert an inferior value to string; OK when (Python 3 || + # simple ASCII); otherwise (Python 2.7 && not ASCII) encode the string as + # utf8 + try: + value_string = str(value) + except UnicodeEncodeError: + value_string = unicode(value).encode('utf8') + return value_string + +def format_address(address): + pointer_size = gdb.parse_and_eval('$pc').type.sizeof + return ('0x{{:0{}x}}').format(pointer_size * 2).format(address) + +def format_value(value): + # format references as referenced values + # (TYPE_CODE_RVALUE_REF is not supported by old GDB) + if value.type.code in (getattr(gdb, 'TYPE_CODE_REF', None), + getattr(gdb, 'TYPE_CODE_RVALUE_REF', None)): + try: + return to_string(value.referenced_value()) + except gdb.MemoryError: + return to_string(value) + else: + try: + return to_string(value) + except gdb.MemoryError as e: + return ansi(e, R.style_error) + +class Beautifier(): + def __init__(self, filename, tab_size=4): + self.tab_spaces = ' ' * tab_size + self.active = False + if not R.ansi: + return + # attempt to set up Pygments + try: + from pygments.lexers import get_lexer_for_filename + from pygments.formatters import Terminal256Formatter + self.formatter = Terminal256Formatter(style=R.syntax_highlighting) + self.lexer = get_lexer_for_filename(filename, stripnl=False) + self.active = True + except ImportError: + # Pygments not available + pass + except pygments.util.ClassNotFound: + # no lexer for this file or invalid style + pass + + def process(self, source): + # convert tabs anyway + source = source.replace('\t', self.tab_spaces) + if self.active: + import pygments + source = pygments.highlight(source, self.lexer, self.formatter) + return source.rstrip('\n') + +# Dashboard -------------------------------------------------------------------- + +class Dashboard(gdb.Command): + """Redisplay the dashboard.""" + + def __init__(self): + gdb.Command.__init__(self, 'dashboard', + gdb.COMMAND_USER, gdb.COMPLETE_NONE, True) + self.output = None # main terminal + # setup subcommands + Dashboard.ConfigurationCommand(self) + Dashboard.OutputCommand(self) + Dashboard.EnabledCommand(self) + Dashboard.LayoutCommand(self) + # setup style commands + Dashboard.StyleCommand(self, 'dashboard', R, R.attributes()) + # disabled by default + self.enabled = None + self.disable() + + def on_continue(self, _): + # try to contain the GDB messages in a specified area unless the + # dashboard is printed to a separate file (dashboard -output ...) + if self.is_running() and not self.output: + width = Dashboard.get_term_width() + gdb.write(Dashboard.clear_screen()) + gdb.write(divider(width, 'Output/messages', True)) + gdb.write('\n') + gdb.flush() + + def on_stop(self, _): + if self.is_running(): + self.render(clear_screen=False) + + def on_exit(self, _): + if not self.is_running(): + return + # collect all the outputs + outputs = set() + outputs.add(self.output) + outputs.update(module.output for module in self.modules) + outputs.remove(None) + # clean the screen and notify to avoid confusion + for output in outputs: + try: + with open(output, 'w') as fs: + fs.write(Dashboard.reset_terminal()) + fs.write(Dashboard.clear_screen()) + fs.write('--- EXITED ---') + except: + # skip cleanup for invalid outputs + pass + + def enable(self): + if self.enabled: + return + self.enabled = True + # setup events + gdb.events.cont.connect(self.on_continue) + gdb.events.stop.connect(self.on_stop) + gdb.events.exited.connect(self.on_exit) + + def disable(self): + if not self.enabled: + return + self.enabled = False + # setup events + gdb.events.cont.disconnect(self.on_continue) + gdb.events.stop.disconnect(self.on_stop) + gdb.events.exited.disconnect(self.on_exit) + + def load_modules(self, modules): + self.modules = [] + for module in modules: + info = Dashboard.ModuleInfo(self, module) + self.modules.append(info) + + def redisplay(self, style_changed=False): + # manually redisplay the dashboard + if self.is_running() and self.enabled: + self.render(True, style_changed) + + def inferior_pid(self): + return gdb.selected_inferior().pid + + def is_running(self): + return self.inferior_pid() != 0 + + def render(self, clear_screen, style_changed=False): + # fetch module content and info + all_disabled = True + display_map = dict() + for module in self.modules: + # fall back to the global value + output = module.output or self.output + # add the instance or None if disabled + if module.enabled: + all_disabled = False + instance = module.instance + else: + instance = None + display_map.setdefault(output, []).append(instance) + # notify the user if the output is empty, on the main terminal + if all_disabled: + # write the error message + width = Dashboard.get_term_width() + gdb.write(divider(width, 'Error', True)) + gdb.write('\n') + if self.modules: + gdb.write('No module to display (see `help dashboard`)') + else: + gdb.write('No module loaded') + # write the terminator + gdb.write('\n') + gdb.write(divider(width, primary=True)) + gdb.write('\n') + gdb.flush() + # continue to allow separate terminals to update + # process each display info + for output, instances in display_map.items(): + try: + fs = None + # use GDB stream by default + if output: + fs = open(output, 'w') + fd = fs.fileno() + # setup the terminal + fs.write(Dashboard.hide_cursor()) + else: + fs = gdb + fd = 1 # stdout + # get the terminal width (default main terminal if either + # the output is not a file) + try: + width = Dashboard.get_term_width(fd) + except: + width = Dashboard.get_term_width() + # clear the "screen" if requested for the main terminal, + # auxiliary terminals are always cleared + if fs is not gdb or clear_screen: + fs.write(Dashboard.clear_screen()) + # show message in separate terminals if all the modules are + # disabled + if output != self.output and not any(instances): + fs.write('--- NO MODULE TO DISPLAY ---\n') + continue + # process all the modules for that output + for n, instance in enumerate(instances, 1): + # skip disabled modules + if not instance: + continue + try: + # ask the module to generate the content + lines = instance.lines(width, style_changed) + except Exception as e: + # allow to continue on exceptions in modules + stacktrace = traceback.format_exc().strip() + lines = [ansi(stacktrace, R.style_error)] + # create the divider accordingly + div = divider(width, instance.label(), True, lines) + # write the data + fs.write('\n'.join([div] + lines)) + # write the newline for all but last unless main terminal + if n != len(instances) or fs is gdb: + fs.write('\n') + # write the final newline and the terminator only if it is the + # main terminal to allow the prompt to display correctly (unless + # there are no modules to display) + if fs is gdb and not all_disabled: + fs.write(divider(width, primary=True)) + fs.write('\n') + fs.flush() + except Exception as e: + cause = traceback.format_exc().strip() + Dashboard.err('Cannot write the dashboard\n{}'.format(cause)) + finally: + # don't close gdb stream + if fs and fs is not gdb: + fs.close() + +# Utility methods -------------------------------------------------------------- + + @staticmethod + def start(): + # initialize the dashboard + dashboard = Dashboard() + Dashboard.set_custom_prompt(dashboard) + # parse Python inits, load modules then parse GDB inits + Dashboard.parse_inits(True) + modules = Dashboard.get_modules() + dashboard.load_modules(modules) + Dashboard.parse_inits(False) + # GDB overrides + run('set pagination off') + # enable and display if possible (program running) + dashboard.enable() + dashboard.redisplay() + + @staticmethod + def get_term_width(fd=1): # defaults to the main terminal + # first 2 shorts (4 byte) of struct winsize + raw = fcntl.ioctl(fd, termios.TIOCGWINSZ, ' ' * 4) + height, width = struct.unpack('hh', raw) + return int(width) + + @staticmethod + def set_custom_prompt(dashboard): + def custom_prompt(_): + # render thread status indicator + if dashboard.is_running(): + pid = dashboard.inferior_pid() + status = R.prompt_running.format(pid=pid) + else: + status = R.prompt_not_running + # build prompt + prompt = R.prompt.format(status=status) + prompt = gdb.prompt.substitute_prompt(prompt) + return prompt + ' ' # force trailing space + gdb.prompt_hook = custom_prompt + + @staticmethod + def parse_inits(python): + for root, dirs, files in os.walk(os.path.expanduser('~/.gdbinit.d/')): + dirs.sort() + for init in sorted(files): + path = os.path.join(root, init) + _, ext = os.path.splitext(path) + # either load Python files or GDB + if python == (ext == '.py'): + gdb.execute('source ' + path) + + @staticmethod + def get_modules(): + # scan the scope for modules + modules = [] + for name in globals(): + obj = globals()[name] + try: + if issubclass(obj, Dashboard.Module): + modules.append(obj) + except TypeError: + continue + # sort modules alphabetically + modules.sort(key=lambda x: x.__name__) + return modules + + @staticmethod + def create_command(name, invoke, doc, is_prefix, complete=None): + Class = type('', (gdb.Command,), {'invoke': invoke, '__doc__': doc}) + Class(name, gdb.COMMAND_USER, complete or gdb.COMPLETE_NONE, is_prefix) + + @staticmethod + def err(string): + print(ansi(string, R.style_error)) + + @staticmethod + def complete(word, candidates): + return filter(lambda candidate: candidate.startswith(word), candidates) + + @staticmethod + def parse_arg(arg): + # encode unicode GDB command arguments as utf8 in Python 2.7 + if type(arg) is not str: + arg = arg.encode('utf8') + return arg + + @staticmethod + def clear_screen(): + # ANSI: move the cursor to top-left corner and clear the screen + return '\x1b[H\x1b[J' + + @staticmethod + def hide_cursor(): + # ANSI: hide cursor + return '\x1b[?25l' + + @staticmethod + def reset_terminal(): + # ANSI: reset to initial state + return '\x1bc' + +# Module descriptor ------------------------------------------------------------ + + class ModuleInfo: + + def __init__(self, dashboard, module): + self.name = module.__name__.lower() # from class to module name + self.enabled = True + self.output = None # value from the dashboard by default + self.instance = module() + self.doc = self.instance.__doc__ or '(no documentation)' + self.prefix = 'dashboard {}'.format(self.name) + # add GDB commands + self.add_main_command(dashboard) + self.add_output_command(dashboard) + self.add_style_command(dashboard) + self.add_subcommands(dashboard) + + def add_main_command(self, dashboard): + module = self + def invoke(self, arg, from_tty, info=self): + arg = Dashboard.parse_arg(arg) + if arg == '': + info.enabled ^= True + if dashboard.is_running(): + dashboard.redisplay() + else: + status = 'enabled' if info.enabled else 'disabled' + print('{} module {}'.format(module.name, status)) + else: + Dashboard.err('Wrong argument "{}"'.format(arg)) + doc_brief = 'Configure the {} module.'.format(self.name) + doc_extended = 'Toggle the module visibility.' + doc = '{}\n{}\n\n{}'.format(doc_brief, doc_extended, self.doc) + Dashboard.create_command(self.prefix, invoke, doc, True) + + def add_output_command(self, dashboard): + Dashboard.OutputCommand(dashboard, self.prefix, self) + + def add_style_command(self, dashboard): + if 'attributes' in dir(self.instance): + Dashboard.StyleCommand(dashboard, self.prefix, self.instance, + self.instance.attributes()) + + def add_subcommands(self, dashboard): + if 'commands' in dir(self.instance): + for name, command in self.instance.commands().items(): + self.add_subcommand(dashboard, name, command) + + def add_subcommand(self, dashboard, name, command): + action = command['action'] + doc = command['doc'] + complete = command.get('complete') + def invoke(self, arg, from_tty, info=self): + arg = Dashboard.parse_arg(arg) + if info.enabled: + try: + action(arg) + except Exception as e: + Dashboard.err(e) + return + # don't catch redisplay errors + dashboard.redisplay() + else: + Dashboard.err('Module disabled') + prefix = '{} {}'.format(self.prefix, name) + Dashboard.create_command(prefix, invoke, doc, False, complete) + +# GDB commands ----------------------------------------------------------------- + + def invoke(self, arg, from_tty): + arg = Dashboard.parse_arg(arg) + # show messages for checks in redisplay + if arg != '': + Dashboard.err('Wrong argument "{}"'.format(arg)) + elif not self.is_running(): + Dashboard.err('Is the target program running?') + else: + self.redisplay() + + class ConfigurationCommand(gdb.Command): + """Dump the dashboard configuration (layout, styles, outputs). +With an optional argument the configuration will be written to the specified +file.""" + + def __init__(self, dashboard): + gdb.Command.__init__(self, 'dashboard -configuration', + gdb.COMMAND_USER, gdb.COMPLETE_FILENAME) + self.dashboard = dashboard + + def invoke(self, arg, from_tty): + arg = Dashboard.parse_arg(arg) + if arg: + with open(os.path.expanduser(arg), 'w') as fs: + fs.write('# auto generated by GDB dashboard\n\n') + self.dump(fs) + self.dump(gdb) + + def dump(self, fs): + # dump layout + self.dump_layout(fs) + # dump styles + self.dump_style(fs, R) + for module in self.dashboard.modules: + self.dump_style(fs, module.instance, module.prefix) + # dump outputs + self.dump_output(fs, self.dashboard) + for module in self.dashboard.modules: + self.dump_output(fs, module, module.prefix) + + def dump_layout(self, fs): + layout = ['dashboard -layout'] + for module in self.dashboard.modules: + mark = '' if module.enabled else '!' + layout.append('{}{}'.format(mark, module.name)) + fs.write(' '.join(layout)) + fs.write('\n') + + def dump_style(self, fs, obj, prefix='dashboard'): + attributes = getattr(obj, 'attributes', lambda: dict())() + for name, attribute in attributes.items(): + real_name = attribute.get('name', name) + default = attribute.get('default') + value = getattr(obj, real_name) + if value != default: + fs.write('{} -style {} {!r}\n'.format(prefix, name, value)) + + def dump_output(self, fs, obj, prefix='dashboard'): + output = getattr(obj, 'output') + if output: + fs.write('{} -output {}\n'.format(prefix, output)) + + class OutputCommand(gdb.Command): + """Set the output file/TTY for both the dashboard and modules. +The dashboard/module will be written to the specified file, which will be +created if it does not exist. If the specified file identifies a terminal then +its width will be used to format the dashboard, otherwise falls back to the +width of the main GDB terminal. Without argument the dashboard, the +output/messages and modules which do not specify the output will be printed on +standard output (default). Without argument the module will be printed where the +dashboard will be printed.""" + + def __init__(self, dashboard, prefix=None, obj=None): + if not prefix: + prefix = 'dashboard' + if not obj: + obj = dashboard + prefix = prefix + ' -output' + gdb.Command.__init__(self, prefix, + gdb.COMMAND_USER, gdb.COMPLETE_FILENAME) + self.dashboard = dashboard + self.obj = obj # None means the dashboard itself + + def invoke(self, arg, from_tty): + arg = Dashboard.parse_arg(arg) + # display a message in a separate terminal if released (note that + # the check if this is the last module to use the output is not + # performed since if that's not the case the message will be + # overwritten) + if self.obj.output: + try: + with open(self.obj.output, 'w') as fs: + fs.write(Dashboard.clear_screen()) + fs.write('--- RELEASED ---\n') + except: + # just do nothing if the file is not writable + pass + # set or open the output file + if arg == '': + self.obj.output = None + else: + self.obj.output = arg + # redisplay the dashboard in the new output + self.dashboard.redisplay() + + class EnabledCommand(gdb.Command): + """Enable or disable the dashboard [on|off]. +The current status is printed if no argument is present.""" + + def __init__(self, dashboard): + gdb.Command.__init__(self, 'dashboard -enabled', gdb.COMMAND_USER) + self.dashboard = dashboard + + def invoke(self, arg, from_tty): + arg = Dashboard.parse_arg(arg) + if arg == '': + status = 'enabled' if self.dashboard.enabled else 'disabled' + print('The dashboard is {}'.format(status)) + elif arg == 'on': + self.dashboard.enable() + self.dashboard.redisplay() + elif arg == 'off': + self.dashboard.disable() + else: + msg = 'Wrong argument "{}"; expecting "on" or "off"' + Dashboard.err(msg.format(arg)) + + def complete(self, text, word): + return Dashboard.complete(word, ['on', 'off']) + + class LayoutCommand(gdb.Command): + """Set or show the dashboard layout. +Accepts a space-separated list of directive. Each directive is in the form +"[!]". Modules in the list are placed in the dashboard in the same order +as they appear and those prefixed by "!" are disabled by default. Omitted +modules are hidden and placed at the bottom in alphabetical order. Without +arguments the current layout is shown where the first line uses the same form +expected by the input while the remaining depict the current status of output +files.""" + + def __init__(self, dashboard): + gdb.Command.__init__(self, 'dashboard -layout', gdb.COMMAND_USER) + self.dashboard = dashboard + + def invoke(self, arg, from_tty): + arg = Dashboard.parse_arg(arg) + directives = str(arg).split() + if directives: + self.layout(directives) + if from_tty and not self.dashboard.is_running(): + self.show() + else: + self.show() + + def show(self): + global_str = 'Global' + max_name_len = len(global_str) + # print directives + modules = [] + for module in self.dashboard.modules: + max_name_len = max(max_name_len, len(module.name)) + mark = '' if module.enabled else '!' + modules.append('{}{}'.format(mark, module.name)) + print(' '.join(modules)) + # print outputs + default = '(default)' + fmt = '{{:{}s}}{{}}'.format(max_name_len + 2) + print(('\n' + fmt + '\n').format(global_str, + self.dashboard.output or default)) + for module in self.dashboard.modules: + style = R.style_high if module.enabled else R.style_low + line = fmt.format(module.name, module.output or default) + print(ansi(line, style)) + + def layout(self, directives): + modules = self.dashboard.modules + # reset visibility + for module in modules: + module.enabled = False + # move and enable the selected modules on top + last = 0 + n_enabled = 0 + for directive in directives: + # parse next directive + enabled = (directive[0] != '!') + name = directive[not enabled:] + try: + # it may actually start from last, but in this way repeated + # modules can be handled transparently and without error + todo = enumerate(modules[last:], start=last) + index = next(i for i, m in todo if name == m.name) + modules[index].enabled = enabled + modules.insert(last, modules.pop(index)) + last += 1 + n_enabled += enabled + except StopIteration: + def find_module(x): + return x.name == name + first_part = modules[:last] + if len(list(filter(find_module, first_part))) == 0: + Dashboard.err('Cannot find module "{}"'.format(name)) + else: + Dashboard.err('Module "{}" already set'.format(name)) + continue + # redisplay the dashboard + if n_enabled: + self.dashboard.redisplay() + + def complete(self, text, word): + all_modules = (m.name for m in self.dashboard.modules) + return Dashboard.complete(word, all_modules) + + class StyleCommand(gdb.Command): + """Access the stylable attributes. +Without arguments print all the stylable attributes. Subcommands are used to set +or print (when the value is omitted) individual attributes.""" + + def __init__(self, dashboard, prefix, obj, attributes): + self.prefix = prefix + ' -style' + gdb.Command.__init__(self, self.prefix, + gdb.COMMAND_USER, gdb.COMPLETE_NONE, True) + self.dashboard = dashboard + self.obj = obj + self.attributes = attributes + self.add_styles() + + def add_styles(self): + this = self + for name, attribute in self.attributes.items(): + # fetch fields + attr_name = attribute.get('name', name) + attr_type = attribute.get('type', str) + attr_check = attribute.get('check', lambda _: True) + attr_default = attribute['default'] + # set the default value (coerced to the type) + value = attr_type(attr_default) + setattr(self.obj, attr_name, value) + # create the command + def invoke(self, arg, from_tty, name=name, attr_name=attr_name, + attr_type=attr_type, attr_check=attr_check): + new_value = Dashboard.parse_arg(arg) + if new_value == '': + # print the current value + value = getattr(this.obj, attr_name) + print('{} = {!r}'.format(name, value)) + else: + try: + # convert and check the new value + parsed = ast.literal_eval(new_value) + value = attr_type(parsed) + if not attr_check(value): + msg = 'Invalid value "{}" for "{}"' + raise Exception(msg.format(new_value, name)) + except Exception as e: + Dashboard.err(e) + else: + # set and redisplay + setattr(this.obj, attr_name, value) + this.dashboard.redisplay(True) + prefix = self.prefix + ' ' + name + doc = attribute.get('doc', 'This style is self-documenting') + Dashboard.create_command(prefix, invoke, doc, False) + + def invoke(self, arg, from_tty): + # an argument here means that the provided attribute is invalid + if arg: + Dashboard.err('Invalid argument "{}"'.format(arg)) + return + # print all the pairs + for name, attribute in self.attributes.items(): + attr_name = attribute.get('name', name) + value = getattr(self.obj, attr_name) + print('{} = {!r}'.format(name, value)) + +# Base module ------------------------------------------------------------------ + + # just a tag + class Module(): + pass + +# Default modules -------------------------------------------------------------- + +class Source(Dashboard.Module): + """Show the program source code, if available.""" + + def __init__(self): + self.file_name = None + self.source_lines = [] + self.ts = None + self.highlighted = False + + def label(self): + return 'Source' + + def lines(self, term_width, style_changed): + # skip if the current thread is not stopped + if not gdb.selected_thread().is_stopped(): + return [] + # try to fetch the current line (skip if no line information) + arch = gdb.parameter('architecture'); + if arch=="i8086": + realpc=int(gdb.parse_and_eval('$pc'))+int(gdb.parse_and_eval('$cs'))*16 + sal = gdb.find_pc_line(realpc) + else: + sal = gdb.selected_frame().find_sal() + current_line = sal.line + if current_line == 0: + return [] + # reload the source file if changed + file_name = sal.symtab.fullname() + ts = None + try: + ts = os.path.getmtime(file_name) + except: + pass # delay error check to open() + if (style_changed or + file_name != self.file_name or # different file name + ts and ts > self.ts): # file modified in the meanwhile + self.file_name = file_name + self.ts = ts + try: + highlighter = Beautifier(self.file_name, self.tab_size) + self.highlighted = highlighter.active + with codecs.open(self.file_name,encoding="ascii",errors="ignore") as source_file: + source = highlighter.process(source_file.read()) + self.source_lines = source.split('\n') + except Exception as e: + msg = 'Cannot display "{}" ({})'.format(self.file_name, e) + return [ansi(msg, R.style_error)] + # compute the line range + start = max(current_line - 1 - self.context, 0) + end = min(current_line - 1 + self.context + 1, len(self.source_lines)) + # return the source code listing + out = [] + number_format = '{{:>{}}}'.format(len(str(end))) + for number, line in enumerate(self.source_lines[start:end], start + 1): + # properly handle UTF-8 source files + line = to_string(line) + if int(number) == current_line: + # the current line has a different style without ANSI + if R.ansi: + if self.highlighted: + line_format = ansi(number_format, + R.style_selected_1) + ' {}' + else: + line_format = ansi(number_format + ' {}', + R.style_selected_1) + else: + # just show a plain text indicator + line_format = number_format + '>{}' + else: + line_format = ansi(number_format, R.style_low) + ' {}' + out.append(line_format.format(number, line.rstrip('\n'))) + return out + + def attributes(self): + return { + 'context': { + 'doc': 'Number of context lines.', + 'default': 12, + 'type': int, + 'check': check_ge_zero + }, + 'tab-size': { + 'doc': 'Number of spaces used to display the tab character.', + 'default': 4, + 'name': 'tab_size', + 'type': int, + 'check': check_gt_zero + } + } + +class Assembly(Dashboard.Module): + """Show the disassembled code surrounding the program counter. The +instructions constituting the current statement are marked, if available.""" + + def label(self): + return 'Assembly' + + def lines(self, term_width, style_changed): + # skip if the current thread is not stopped + if not gdb.selected_thread().is_stopped(): + return [] + line_info = None + arch = gdb.parameter('architecture'); + frame = gdb.selected_frame() # PC is here + if arch=="i8086": + realpc=frame.pc()+int(gdb.parse_and_eval('$cs'))*16 + else: + realpc=frame.pc() + disassemble = frame.architecture().disassemble + try: + # try to fetch the function boundaries using the disassemble command + output = run('disassemble').split('\n') + start = int(re.split('[ :]', output[1][3:], 1)[0], 16) + end = int(re.split('[ :]', output[-3][3:], 1)[0], 16) + asm = disassemble(start, end_pc=end) + # find the location of the PC + pc_index = next(index for index, instr in enumerate(asm) if instr['addr'] == realpc) + start = max(pc_index - self.context, 0) + end = pc_index + self.context + 1 + asm = asm[start:end] + # if there are line information then use it, it may be that + # line_info is not None but line_info.last is None + line_info = gdb.find_pc_line(realpc) + line_info = line_info if line_info.last else None + except (gdb.error, StopIteration): + # if it is not possible (stripped binary or the PC is not present in + # the output of `disassemble` as per issue #31) start from PC and + # end after twice the context + try: + asm = disassemble(realpc, count=2 * self.context + 1) + except gdb.error as e: + msg = '{}'.format(e) + return [ansi(msg, R.style_error)] + # fetch function start if available + func_start = None + if self.show_function and frame.name(): + try: + # it may happen that the frame name is the whole function + # declaration, instead of just the name, e.g., 'getkey()', so it + # would be treated as a function call by 'gdb.parse_and_eval', + # hence the trim, see #87 and #88 + value = gdb.parse_and_eval(frame.name().split('(')[0]).address + func_start = to_unsigned(value) + except gdb.error: + pass # e.g., @plt + # fetch the assembly flavor and the extension used by Pygments + try: + flavor = gdb.parameter('disassembly-flavor') + except: + flavor = None # not always defined (see #36) + filename = { + 'att': '.s', + 'intel': '.asm' + }.get(flavor, '.s') + # prepare the highlighter + highlighter = Beautifier(filename) + # compute the maximum offset size + if func_start: + max_offset = max(len(str(abs(asm[0]['addr'] - func_start))), + len(str(abs(asm[-1]['addr'] - func_start)))) + # return the machine code + max_length = max(instr['length'] for instr in asm) + inferior = gdb.selected_inferior() + out = [] + for index, instr in enumerate(asm): + addr = instr['addr'] + length = instr['length'] + text = instr['asm'] + addr_str = format_address(addr) + if self.show_opcodes: + # fetch and format opcode + region = inferior.read_memory(addr, length) + opcodes = (' '.join('{:02x}'.format(ord(byte)) + for byte in region)) + opcodes += (max_length - len(region)) * 3 * ' ' + ' ' + else: + opcodes = '' + # compute the offset if available + if self.show_function: + if func_start: + offset = '{:+d}'.format(addr - func_start) + offset = offset.ljust(max_offset + 1) # sign + func_info = '{}{}'.format(frame.name(), offset) + else: + func_info = '?' + else: + func_info = '' + format_string = '{}{}{}{}{}' + indicator = ' ' + text = ' ' + highlighter.process(text) + if addr == realpc: + if not R.ansi: + indicator = '>' + addr_str = ansi(addr_str, R.style_selected_1) + indicator = ansi(indicator, R.style_selected_1) + opcodes = ansi(opcodes, R.style_selected_1) + func_info = ansi(func_info, R.style_selected_1) + if not highlighter.active: + text = ansi(text, R.style_selected_1) + elif line_info and line_info.pc <= addr < line_info.last: + if not R.ansi: + indicator = ':' + addr_str = ansi(addr_str, R.style_selected_2) + indicator = ansi(indicator, R.style_selected_2) + opcodes = ansi(opcodes, R.style_selected_2) + func_info = ansi(func_info, R.style_selected_2) + if not highlighter.active: + text = ansi(text, R.style_selected_2) + else: + addr_str = ansi(addr_str, R.style_low) + func_info = ansi(func_info, R.style_low) + out.append(format_string.format(addr_str, indicator, + opcodes, func_info, text)) + return out + + def attributes(self): + return { + 'context': { + 'doc': 'Number of context instructions.', + 'default': 10, + 'type': int, + 'check': check_ge_zero + }, + 'opcodes': { + 'doc': 'Opcodes visibility flag.', + 'default': False, + 'name': 'show_opcodes', + 'type': bool + }, + 'function': { + 'doc': 'Function information visibility flag.', + 'default': True, + 'name': 'show_function', + 'type': bool + } + } + +class Stack(Dashboard.Module): + """Show the current stack trace including the function name and the file +location, if available. Optionally list the frame arguments and locals too.""" + + def label(self): + return 'Stack' + + def lines(self, term_width, style_changed): + # skip if the current thread is not stopped + if not gdb.selected_thread().is_stopped(): + return [] + # find the selected frame (i.e., the first to display) + selected_index = 0 + frame = gdb.newest_frame() + while frame: + if frame == gdb.selected_frame(): + break + frame = frame.older() + selected_index += 1 + # format up to "limit" frames + frames = [] + number = selected_index + more = False + while frame: + # the first is the selected one + selected = (len(frames) == 0) + # fetch frame info + style = R.style_selected_1 if selected else R.style_selected_2 + frame_id = ansi(str(number), style) + info = Stack.get_pc_line(frame, style) + frame_lines = [] + frame_lines.append('[{}] {}'.format(frame_id, info)) + # fetch frame arguments and locals + decorator = gdb.FrameDecorator.FrameDecorator(frame) + separator = ansi(', ', R.style_low) + strip_newlines = re.compile(r'$\s*', re.MULTILINE) + if self.show_arguments: + def prefix(line): + return Stack.format_line('arg', line) + frame_args = decorator.frame_args() + args_lines = Stack.fetch_frame_info(frame, frame_args) + if args_lines: + if self.compact: + args_line = separator.join(args_lines) + args_line = strip_newlines.sub('', args_line) + single_line = prefix(args_line) + frame_lines.append(single_line) + else: + frame_lines.extend(map(prefix, args_lines)) + else: + frame_lines.append(ansi('(no arguments)', R.style_low)) + if self.show_locals: + def prefix(line): + return Stack.format_line('loc', line) + frame_locals = decorator.frame_locals() + locals_lines = Stack.fetch_frame_info(frame, frame_locals) + if locals_lines: + if self.compact: + locals_line = separator.join(locals_lines) + locals_line = strip_newlines.sub('', locals_line) + single_line = prefix(locals_line) + frame_lines.append(single_line) + else: + frame_lines.extend(map(prefix, locals_lines)) + else: + frame_lines.append(ansi('(no locals)', R.style_low)) + # add frame + frames.append(frame_lines) + # next + frame = frame.older() + number += 1 + # check finished according to the limit + if self.limit and len(frames) == self.limit: + # more frames to show but limited + if frame: + more = True + break + # format the output + lines = [] + for frame_lines in frames: + lines.extend(frame_lines) + # add the placeholder + if more: + lines.append('[{}]'.format(ansi('+', R.style_selected_2))) + return lines + + @staticmethod + def format_line(prefix, line): + prefix = ansi(prefix, R.style_low) + return '{} {}'.format(prefix, line) + + @staticmethod + def fetch_frame_info(frame, data): + lines = [] + for elem in data or []: + name = elem.sym + equal = ansi('=', R.style_low) + value = format_value(elem.sym.value(frame)) + lines.append('{} {} {}'.format(name, equal, value)) + return lines + + @staticmethod + def get_pc_line(frame, style): + frame_pc = ansi(format_address(frame.pc()), style) + info = 'from {}'.format(frame_pc) + if frame.name(): + frame_name = ansi(frame.name(), style) + try: + # try to compute the offset relative to the current function (it + # may happen that the frame name is the whole function + # declaration, instead of just the name, e.g., 'getkey()', so it + # would be treated as a function call by 'gdb.parse_and_eval', + # hence the trim, see #87 and #88) + value = gdb.parse_and_eval(frame.name().split('(')[0]).address + # it can be None even if it is part of the "stack" (C++) + if value: + func_start = to_unsigned(value) + offset = frame.pc() - func_start + frame_name += '+' + ansi(str(offset), style) + except gdb.error: + pass # e.g., @plt + info += ' in {}'.format(frame_name) + sal = frame.find_sal() + if sal.symtab: + file_name = ansi(sal.symtab.filename, style) + file_line = ansi(str(sal.line), style) + info += ' at {}:{}'.format(file_name, file_line) + return info + + def attributes(self): + return { + 'limit': { + 'doc': 'Maximum number of displayed frames (0 means no limit).', + 'default': 2, + 'type': int, + 'check': check_ge_zero + }, + 'arguments': { + 'doc': 'Frame arguments visibility flag.', + 'default': True, + 'name': 'show_arguments', + 'type': bool + }, + 'locals': { + 'doc': 'Frame locals visibility flag.', + 'default': False, + 'name': 'show_locals', + 'type': bool + }, + 'compact': { + 'doc': 'Single-line display flag.', + 'default': False, + 'type': bool + } + } + +class History(Dashboard.Module): + """List the last entries of the value history.""" + + def label(self): + return 'History' + + def lines(self, term_width, style_changed): + out = [] + # fetch last entries + for i in range(-self.limit + 1, 1): + try: + value = format_value(gdb.history(i)) + value_id = ansi('$${}', R.style_low).format(abs(i)) + line = '{} = {}'.format(value_id, value) + out.append(line) + except gdb.error: + continue + return out + + def attributes(self): + return { + 'limit': { + 'doc': 'Maximum number of values to show.', + 'default': 3, + 'type': int, + 'check': check_gt_zero + } + } + +class Memory(Dashboard.Module): + """Allow to inspect memory regions.""" + + @staticmethod + def format_byte(byte): + # `type(byte) is bytes` in Python 3 + if byte.isspace(): + return ' ' + elif 0x20 < ord(byte) < 0x7e: + return chr(ord(byte)) + else: + return '.' + + @staticmethod + def parse_as_address(expression): + value = gdb.parse_and_eval(expression) + return to_unsigned(value) + + def __init__(self): + self.row_length = 16 + self.table = {} + + def format_memory(self, start, memory): + out = [] + for i in range(0, len(memory), self.row_length): + region = memory[i:i + self.row_length] + pad = self.row_length - len(region) + address = format_address(start + i) + hexa = (' '.join('{:02x}'.format(ord(byte)) for byte in region)) + text = (''.join(Memory.format_byte(byte) for byte in region)) + out.append('{} {}{} {}{}'.format(ansi(address, R.style_low), + hexa, + ansi(pad * ' --', R.style_low), + ansi(text, R.style_high), + ansi(pad * '.', R.style_low))) + return out + + def label(self): + return 'Memory' + + def lines(self, term_width, style_changed): + out = [] + inferior = gdb.selected_inferior() + for address, length in sorted(self.table.items()): + try: + memory = inferior.read_memory(address, length) + out.extend(self.format_memory(address, memory)) + except gdb.error: + msg = 'Cannot access {} bytes starting at {}' + msg = msg.format(length, format_address(address)) + out.append(ansi(msg, R.style_error)) + out.append(divider(term_width)) + # drop last divider + if out: + del out[-1] + return out + + def watch(self, arg): + if arg: + address, _, length = arg.partition(' ') + address = Memory.parse_as_address(address) + if length: + length = Memory.parse_as_address(length) + else: + length = self.row_length + self.table[address] = length + else: + raise Exception('Specify an address') + + def unwatch(self, arg): + if arg: + try: + del self.table[Memory.parse_as_address(arg)] + except KeyError: + raise Exception('Memory region not watched') + else: + raise Exception('Specify an address') + + def clear(self, arg): + self.table.clear() + + def commands(self): + return { + 'watch': { + 'action': self.watch, + 'doc': 'Watch a memory region by address and length.\n' + 'The length defaults to 16 byte.', + 'complete': gdb.COMPLETE_EXPRESSION + }, + 'unwatch': { + 'action': self.unwatch, + 'doc': 'Stop watching a memory region by address.', + 'complete': gdb.COMPLETE_EXPRESSION + }, + 'clear': { + 'action': self.clear, + 'doc': 'Clear all the watched regions.' + } + } + +class Registers(Dashboard.Module): + """Show the CPU registers and their values.""" + + def __init__(self): + self.table = {} + + def label(self): + return 'Registers' + + def lines(self, term_width, style_changed): + # skip if the current thread is not stopped + if not gdb.selected_thread().is_stopped(): + return [] + # fetch registers status + registers = [] + for reg_info in run('info registers').strip().split('\n'): + # fetch register and update the table + name = reg_info.split(None, 1)[0] + # Exclude registers with a dot '.' or parse_and_eval() will fail + if '.' in name: + continue + value = gdb.parse_and_eval('${}'.format(name)) + string_value = Registers.format_value(value) + changed = self.table and (self.table.get(name, '') != string_value) + self.table[name] = string_value + registers.append((name, string_value, changed)) + # split registers in rows and columns, each column is composed of name, + # space, value and another trailing space which is skipped in the last + # column (hence term_width + 1) + max_name = max(len(name) for name, _, _ in registers) + max_value = max(len(value) for _, value, _ in registers) + max_width = max_name + max_value + 2 + per_line = int((term_width + 1) / max_width) or 1 + # redistribute extra space among columns + extra = int((term_width + 1 - max_width * per_line) / per_line) + if per_line == 1: + # center when there is only one column + max_name += int(extra / 2) + max_value += int(extra / 2) + else: + max_value += extra + # format registers info + partial = [] + for name, value, changed in registers: + styled_name = ansi(name.rjust(max_name), R.style_low) + value_style = R.style_selected_1 if changed else '' + styled_value = ansi(value.ljust(max_value), value_style) + partial.append(styled_name + ' ' + styled_value) + out = [] + if self.column_major: + num_lines = int(math.ceil(float(len(partial)) / per_line)) + for i in range(num_lines): + line = ' '.join(partial[i:len(partial):num_lines]).rstrip() + real_n_col = math.ceil(float(len(partial)) / num_lines) + line = ' ' * int((per_line - real_n_col) * max_width / 2) + line + out.append(line) + else: + for i in range(0, len(partial), per_line): + out.append(' '.join(partial[i:i + per_line]).rstrip()) + return out + + def attributes(self): + return { + 'column-major': { + 'doc': 'Whether to show registers in columns instead of rows.', + 'default': False, + 'name': 'column_major', + 'type': bool + } + } + + @staticmethod + def format_value(value): + try: + if value.type.code in [gdb.TYPE_CODE_INT, gdb.TYPE_CODE_PTR]: + int_value = to_unsigned(value, value.type.sizeof) + value_format = '0x{{:0{}x}}'.format(2 * value.type.sizeof) + return value_format.format(int_value) + except (gdb.error, ValueError): + # convert to unsigned but preserve code and flags information + pass + return str(value) + +class Threads(Dashboard.Module): + """List the currently available threads.""" + + def label(self): + return 'Threads' + + def lines(self, term_width, style_changed): + out = [] + selected_thread = gdb.selected_thread() + # do not restore the selected frame if the thread is not stopped + restore_frame = gdb.selected_thread().is_stopped() + if restore_frame: + selected_frame = gdb.selected_frame() + for thread in gdb.Inferior.threads(gdb.selected_inferior()): + # skip running threads if requested + if self.skip_running and thread.is_running(): + continue + is_selected = (thread.ptid == selected_thread.ptid) + style = R.style_selected_1 if is_selected else R.style_selected_2 + number = ansi(str(thread.num), style) + tid = ansi(str(thread.ptid[1] or thread.ptid[2]), style) + info = '[{}] id {}'.format(number, tid) + if thread.name: + info += ' name {}'.format(ansi(thread.name, style)) + # switch thread to fetch info (unless is running in non-stop mode) + try: + thread.switch() + frame = gdb.newest_frame() + info += ' ' + Stack.get_pc_line(frame, style) + except gdb.error: + info += ' (running)' + out.append(info) + # restore thread and frame + selected_thread.switch() + if restore_frame: + selected_frame.select() + return out + + def attributes(self): + return { + 'skip-running': { + 'doc': 'Skip running threads.', + 'default': False, + 'name': 'skip_running', + 'type': bool + } + } + +class Expressions(Dashboard.Module): + """Watch user expressions.""" + + def __init__(self): + self.number = 1 + self.table = {} + + def label(self): + return 'Expressions' + + def lines(self, term_width, style_changed): + out = [] + for number, expression in sorted(self.table.items()): + try: + value = format_value(gdb.parse_and_eval(expression)) + except gdb.error as e: + value = ansi(e, R.style_error) + number = ansi(number, R.style_selected_2) + expression = ansi(expression, R.style_low) + out.append('[{}] {} = {}'.format(number, expression, value)) + return out + + def watch(self, arg): + if arg: + self.table[self.number] = arg + self.number += 1 + else: + raise Exception('Specify an expression') + + def unwatch(self, arg): + if arg: + try: + del self.table[int(arg)] + except: + raise Exception('Expression not watched') + else: + raise Exception('Specify an identifier') + + def clear(self, arg): + self.table.clear() + + def commands(self): + return { + 'watch': { + 'action': self.watch, + 'doc': 'Watch an expression.', + 'complete': gdb.COMPLETE_EXPRESSION + }, + 'unwatch': { + 'action': self.unwatch, + 'doc': 'Stop watching an expression by id.', + 'complete': gdb.COMPLETE_EXPRESSION + }, + 'clear': { + 'action': self.clear, + 'doc': 'Clear all the watched expressions.' + } + } + +# XXX traceback line numbers in this Python block must be increased by 1 +end + +# Better GDB defaults ---------------------------------------------------------- + +set history save +set verbose off +set print pretty on +set print array off +set print array-indexes on +set python print-stack full + +# Start ------------------------------------------------------------------------ + +python Dashboard.start() + +# ------------------------------------------------------------------------------ +# Copyright (c) 2015-2017 Andrea Cardaci +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# ------------------------------------------------------------------------------ +# vim: filetype=python +# Local Variables: +# mode: python +# End: + diff --git a/final/harddiskuefi.img.xz b/final/harddiskuefi.img.xz new file mode 100644 index 0000000..735ae33 Binary files /dev/null and b/final/harddiskuefi.img.xz differ diff --git a/final/makefile b/final/makefile index daabe11..a4a2012 100755 --- a/final/makefile +++ b/final/makefile @@ -1,48 +1,53 @@ -all: harddisk.img.final floppy.img.final harddiskuefi.img.final - -harddiskuefi.img.before: - (xz -d -k harddiskuefi.img.xz) - (dd if=harddiskuefi.img of=harddiskuefi.img.part1 skip=13672 bs=512) - (dd if=harddiskuefi.img of=harddiskuefi.img.before count=13672 bs=512;sync) - (mkdir ./mnt -p) - -harddiskuefi.img.final: harddiskuefi.img.before - (mount.fuse-ext2 -o rw+ harddiskuefi.img.part1 ./mnt) - (cp ../system/system.sys ./mnt/boot/;sync) - (fusermount ./mnt -u) - (cat harddiskuefi.img.before > harddiskuefi.img.final) - (cat harddiskuefi.img.part1 >> harddiskuefi.img.final;sync) - -harddisk.img.before: - (xz -d -k harddisk.img.xz) - (dd if=harddisk.img of=harddisk.img.part1 skip=63 bs=512) - (dd if=harddisk.img of=harddisk.img.before count=63 bs=512;sync) - (mkdir ./mnt -p) - -harddisk.img.final: harddisk.img.before - (mount.fuse-ext2 -o rw+ harddisk.img.part1 ./mnt) - (cp ../system/system.sys ./mnt/boot/;sync) - (fusermount ./mnt -u) - (cat harddisk.img.before > harddisk.img.final) - (cat harddisk.img.part1 >> harddisk.img.final;sync) - -floppy.img.final: - (dd if=/dev/zero of=floppy.img.final count=2880 bs=512) - (mkfs.msdos -F 12 -n "COS2000" floppy.img.final) - (mkdir ./mnt -p) - (fusefat floppy.img.final ./mnt -o rw+) - (cp ../boot/loader.sys ./mnt/) - (cp ../system/system.sys ./mnt/;sync) - (fusermount ./mnt -u) - (dd if=../boot/boot12.bin of=floppy.img.final seek=0 count=1 conv=notrunc;sync) - -littleclean: - rm -f *.final - -togit: clean - -clean: - rm -f *.before - rm -f *.part1 - rm -f *.img - rm -f *.final +REMOVE=rm -f +INSTALL=sudo apt-get install +COPY=cp +DISKCOPY=dd +COMPRESS=xz +SYNC=sync +CREATEDIR=mkdir +CAT=cat + +all: harddisk.img.final harddiskuefi.img.final + +harddiskuefi.img.before: + $(COMPRESS) -d -k harddiskuefi.img.xz + $(DISKCOPY) if=harddiskuefi.img of=harddiskuefi.img.part1 skip=13672 bs=512 + $(DISKCOPY) if=harddiskuefi.img of=harddiskuefi.img.before count=13672 bs=512 + $(SYNC) + $(CREATEDIR) ./mnt -p + +harddiskuefi.img.final: harddiskuefi.img.before + mount.fuse-ext2 -o rw+ harddiskuefi.img.part1 ./mnt + $(COPY) ../system/system.sys ./mnt/boot/ + $(SYNC) + fusermount ./mnt -u + cat harddiskuefi.img.before > harddiskuefi.img.final + cat harddiskuefi.img.part1 >> harddiskuefi.img.final + $(SYNC) + +harddisk.img.before: + $(COMPRESS) -d -k harddisk.img.xz + $(DISKCOPY) if=harddisk.img of=harddisk.img.part1 skip=63 bs=512 + $(DISKCOPY) if=harddisk.img of=harddisk.img.before count=63 bs=512 + $(SYNC) + $(CREATEDIR) ./mnt -p + +harddisk.img.final: harddisk.img.before + mount.fuse-ext2 -o rw+ harddisk.img.part1 ./mnt + $(COPY) ../system/system.sys ./mnt/boot/ + $(SYNC) + fusermount ./mnt -u + cat harddisk.img.before > harddisk.img.final + cat harddisk.img.part1 >> harddisk.img.final + $(SYNC) + +littleclean: + $(REMOVE) *.final + +togit: clean + +clean: + $(REMOVE) *.before + $(REMOVE) *.part1 + $(REMOVE) *.img + $(REMOVE) *.final diff --git a/final/makeimageuefi b/final/makeimageuefi index 45d9169..2a332ad 100755 --- a/final/makeimageuefi +++ b/final/makeimageuefi @@ -12,14 +12,30 @@ mkfs.ext2 ${lo}p2 mount ${lo}p1 /mnt mkdir /mnt/grub echo -en "(hd0) ${lo}\n(hd0,1) ${lo}p1\n(hd0,2) ${lo}p2" > /mnt/grub/device.map -grub-install --no-floppy --boot-directory=/mnt/ --efi-directory=/mnt/ ${lo} --install-modules="part_gpt ext2 configfile normal multiboot2 video video_colors video_cirrus video_fb videotest all_video" --locales=fr --target=x86_64-efi --no-nvram +#LS MINICMD pour avoir vision paritions +grub-install --no-floppy --boot-directory=/mnt/ --efi-directory=/mnt/ ${lo} --install-modules="part_gpt ext2 configfile normal linux16 video video_colors video_cirrus video_fb videotest all_video" --locales=fr --target=x86_64-efi --no-nvram mkdir /mnt/EFI/BOOT cp /mnt/EFI/ubuntu/grubx64.efi /mnt/EFI/BOOT/bootx64.efi #grub-mkimage -d /usr/lib/grub/x86_64-efi -o /mnt/EFI/BOOT/bootx64.efi -c /mnt/EFI/ubuntu/grub.cfg -p "(hd0,1)/grub/" -O x86_64-efi part_gpt ext2 configfile normal multiboot2 video video_color video_cirrus video_fb videotest all_video -echo -en "set timeout=4\nset default=0\n\nmenuentry "cos2000" {\nmultiboot2 (hd0,2)/boot/system.sys\nboot\n}" > /mnt/grub/grub.cfg +echo -en "\ +insmod ext2 +insmod biosdisk +insmod part_msdos +insmod linux +insmod vbe +insmod gfxterm +insmod png +insmod font +set timeout=4\n\ +set default=0\n\ +menuentry "cos2000" {\n\ +set root=(hd0,gpt2)\n\ +linux16 /boot/system.sys root=hd0,gpt2\n +boot\n\ +}" > /mnt/grub/grub.cfg umount /mnt mount ${lo}p2 /mnt mkdir /mnt/boot/ umount /mnt losetup -d ${lo} -#xz -c harddiskuefi.img > harddiskuefi.img.xzcl +xz -c harddiskuefi.img > harddiskuefi.img.xz diff --git a/lib/makefile b/lib/makefile index 11671c1..b1b785a 100755 --- a/lib/makefile +++ b/lib/makefile @@ -1,59 +1,61 @@ -CC=gcc -O0 -g -nostdinc -ffreestanding -fno-builtin -Wall -w -m32 -F elf_i386 -fno-pie -no-pie -I ../include -c -ASM=gcc -nostdinc -ffreestanding -fno-builtin -m32 -c -fno-pie -no-pie -LINK=ld -m elf_i386 -r -o -SRCS= $(wildcard *.c) -OBJS= $(SRCS:.c=.o) -SRCASM= $(wildcard *.S) -OBJASM= $(SRCASM:.S=.o) -CONVERT=dos2unix -INDENT=indent -nhnl -l75 -ppi3 -ts8 -bls -nbc -di8 -nbad -nbap -nsob -i8 -bl -bli0 -ncdw -nce -cli8 -cbi0 -npcs -cs -saf -sai -saw -nprs -lp -npsl -REMOVE=rm -f -CHANGEPERM=chmod 644 - -all: libs.o - sync - -togit: clean indent - -libs.o:$(OBJS) $(OBJASM) - $(LINK) libs.o $(OBJS) $(OBJASM) - -.o: .S - $(ASM) $^ - -handlers.o:handlers.c - $(CC) -mgeneral-regs-only $^ - -keyboard.o:keyboard.c - $(CC) -mgeneral-regs-only $^ - -mouse.o:mouse.c - $(CC) -mgeneral-regs-only $^ - -syscall.o:syscall.c - $(CC) -fomit-frame-pointer $^ -.o: .c - $(CC) $^ - -clean: - $(REMOVE) *.o - $(REMOVE) *.c~ - $(REMOVE) */*.c~ - $(REMOVE) ../include/*.h~ - $(REMOVE) ./TEST/*.c - sync - -indent: - $(CHANGEPERM) *.c - $(CONVERT) *.c - $(INDENT) *.c - $(REMOVE) *.c~ - $(CHANGEPERM) ./*/*.c - $(CONVERT) ./*/*.c - $(INDENT) ./*/*.c - $(REMOVE) */*.c~ - $(CHANGEPERM) ../include/*.h - $(CONVERT) ../include/*.h - $(INDENT) ../include/*.h - $(REMOVE) ../include/*.h~ - sync +CC=gcc -O0 -g -nostdinc -ffreestanding -fno-builtin -Wall -w -m32 -F elf_i386 -fno-pie -no-pie -I ../include -c +ASM=gcc -nostdinc -ffreestanding -fno-builtin -m32 -c -fno-pie -no-pie +LINK=ld -m elf_i386 -r -o +SRCS= $(wildcard *.c) +OBJS= $(SRCS:.c=.o) +SRCASM= $(wildcard *.S) +OBJASM= $(SRCASM:.S=.o) +CONVERT=dos2unix +INDENT=indent -nhnl -l75 -ppi3 -ts8 -bls -nbc -di8 -nbad -nbap -nsob -i8 -bl -bli0 -ncdw -nce -cli8 -cbi0 -npcs -cs -saf -sai -saw -nprs -lp -npsl +REMOVE=rm -f +CHANGEPERM=chmod 644 +SYNC=sync + +all: libs.o + $(SYNC) + +togit: clean indent + +libs.o:$(OBJS) $(OBJASM) + $(LINK) libs.o $(OBJS) $(OBJASM) + +.o: .S + $(ASM) $^ + +handlers.o:handlers.c + $(CC) -mgeneral-regs-only $^ + +keyboard.o:keyboard.c + $(CC) -mgeneral-regs-only $^ + +mouse.o:mouse.c + $(CC) -mgeneral-regs-only $^ + +syscall.o:syscall.c + $(CC) -fomit-frame-pointer $^ +.o: .c + $(CC) $^ + +clean: + $(REMOVE) *.o + $(REMOVE) *.c~ + $(REMOVE) */*.c~ + $(REMOVE) ../include/*.h~ + $(REMOVE) ./TEST/*.c + $(SYNC) + +indent: + $(CHANGEPERM) *.c + $(CONVERT) *.c + $(INDENT) *.c + $(REMOVE) *.c~ + $(CHANGEPERM) ./*/*.c + $(CONVERT) ./*/*.c + $(INDENT) ./*/*.c + $(REMOVE) */*.c~ + $(CHANGEPERM) ../include/*.h + $(CONVERT) ../include/*.h + $(INDENT) ../include/*.h + $(REMOVE) ../include/*.h~ + $(SYNC) + diff --git a/makefile b/makefile index 6a02df0..0a94e06 100755 --- a/makefile +++ b/makefile @@ -1,151 +1,183 @@ -DEBUG=exec gnome-terminal --geometry=120x55+1+1 -x ./debug/debug.sh -REMOVE=rm -f -INSTALL=sudo apt-get install -COPY=cp -EMULATOR=bochs -f -GIT=git status -MAKECALL=python makesyscall.py - -all: tools programs bits32 bits64 harddisk uefi - sync - -bits32: ARCH=bits32 -bits32: lib/libs.o system/system.sys - sync - -bits64: ARCH=bits64 -bits64: lib/libs.o system/system.sys - sync - -tools: tools/build - -tools/build: - make -C tools - -syscall: clean remakeapi all - -remakeapi: - $(MAKECALL) - -programs: programs/test lib/TEST/test.c lib/TEST/test2.c - -lib/TEST/test.c: - xxd -i programs/test lib/TEST/test.c - -lib/TEST/test2.c: - xxd -i programs/test2 lib/TEST/test2.c - -programs/test: - make -C programs - -harddisk: final/harddisk.img.final - -uefi: final/harddiskuefi.img.final - -install: - $(INSTALL) gcc qemu fusefat fuseext2 gdb ovmf bsdmainutils tar bsdmainutils indent binutils bochs bochs-x bochsbios dos2unix gnome-terminal - -togit: - make -C system togit - make -C lib togit - make -C final togit - make -C programs togit - make -C tools togit - $(GIT) - sync - -clean: - $(RM) -f .gdb_history - make -C system clean - make -C lib clean - make -C final clean - make -C programs clean - make -C tools clean - sync - -littleclean: - make -C system clean - make -C lib clean - make -C final littleclean - make -C programs clean - sync - -indent: - make -C system indent - make -C lib indent - make -C programs indent - make -C tools indent - sync - -backup: clean - cd .. - tar cf - Source\ C | gzip -f - > backup.tar.gz - -test: tools programs bits32 harddisk qemu - -test64: tools programs bits64 uefi qemu64 - -retest: littleclean test - -retest64: littleclean test64 - -testbochs: tools programs bits32 harddisk bochs-debug - -view: - hexdump -C ./final/harddisk.img.final|head -c10000 - -debug: debug-system - -redebug: littleclean debug-system - -debug64: debug-system64 - -redebug64: littleclean debug-system64 - -kernel: debug-kernel - -debug-boot: tools programs bits32 harddisk qemu-debug - sleep 2 - $(DEBUG) ./debug/boot.txt - -debug-system: tools programs bits32 harddisk qemu-debug - sleep 2 - $(DEBUG) ./debug/system.txt - -debug-system64: tools programs bits64 uefi qemu-debug64 - sleep 2 - $(DEBUG) ./debug/system.txt - -bochs-debug: killer - $(EMULATOR) ./debug/config.bochs - -killer: - killall bochs-debug || true - killall qemu-system-x86_64 || true - killall qemu-system-i386 || true - killall gnome-terminal-server || true - tmux kill-session -t debug || true - -qemu-debug: killer - qemu-system-i386 -monitor telnet:127.0.0.1:6666,server,nowait -m 1G -drive format=raw,file=./final/harddisk.img.final -s -S & - -qemu-debug64: killer - qemu-system-x86_64 -monitor telnet:127.0.0.1:6666,server,nowait -m 5G -drive format=raw,file=./final/harddiskuefi.img.final --bios /usr/share/qemu/OVMF.fd -s -S & - -qemu: killer - qemu-system-i386 -m 1G -drive format=raw,file=./final/harddisk.img.final --enable-kvm -cpu host -s & - -qemu64: killer - qemu-system-x86_64 -m 5G -drive format=raw,file=./final/harddiskuefi.img.final --bios /usr/share/qemu/OVMF.fd --enable-kvm -cpu host -s & - -system/system.sys: - make -C system - -final/harddisk.img.final: - make -C final harddisk.img.final - -final/harddiskuefi.img.final: - make -C final harddiskuefi.img.final - -lib/libs.o: - make -C lib +##### Variables +GODEBUG=exec gnome-terminal --geometry=120x55+1+1 -x ./debug/debug.sh +REMOVE=rm -f +INSTALL=sudo apt-get install +COPY=cp +OLDEMUX86=bochs -f +GIT=git status +MAKECALL=python makesyscall.py +MAKE=make -C +SYNC=sync +KILL=killall +TAR=tar cf - Source\ C | gzip -f - > backup.tar.gz +HEXDUMP=hexdump -C ./final/harddisk.img.final|head -c10000 +TMUXKILL=tmux kill-session -t +TRUE=|| true +SPICE=spicy --uri=spice://127.0.0.1?port=5900 +SOURCE=xxd -i +EMUX86=qemu-system-i386 +EMUX64=qemu-system-x86_64 +LEGACY=-m 1G -drive format=raw,file=./final/harddisk.img.final --enable-kvm -cpu host -s -vga qxl -spice port=5900,addr=127.0.0.1,disable-ticketing +UEFI=-m 5G -drive format=raw,file=./final/harddiskuefi.img.final --bios /usr/share/qemu/OVMF.fd --enable-kvm -cpu host -s -vga qxl -spice port=5900,addr=127.0.0.1,disable-ticketing +DEBUG=-S -monitor telnet:127.0.0.1:6666,server,nowait +WAIT2S=sleep 2 + +##### Construction + +all: tools programs system32 system64 harddisk harddiskuefi + $(SYNC) + +system32: ARCH=bits32 +system32: lib/libs.o system/system.sys + $(SYNC) + +system64: ARCH=bits64 +system64: lib/libs.o system/system.sys + $(SYNC) + +tools: tools/build + +tools/build: + $(MAKE) tools + +syscall: clean remakeapi all + +remakeapi: + $(MAKECALL) + +programs: programs/test lib/TEST/test.c lib/TEST/test2.c + +lib/TEST/test.c: + $(SOURCE) programs/test lib/TEST/test.c + +lib/TEST/test2.c: + $(SOURCE) programs/test2 lib/TEST/test2.c + +programs/test: + $(MAKE) programs + +harddisk: final/harddisk.img.final + +harddiskuefi: final/harddiskuefi.img.final + +install: + $(INSTALL) gcc qemu fusefat fuseext2 gdb ovmf bsdmainutils tar bsdmainutils indent binutils bochs bochs-x bochsbios dos2unix gnome-terminal spice-client-gtk python2 + +togit: + $(MAKE) system togit + $(MAKE) lib togit + $(MAKE) final togit + $(MAKE) programs togit + $(MAKE) tools togit + $(GIT) + $(SYNC) + +clean: + $(REMOVE) .gdb_history + $(MAKE) system clean + $(MAKE) lib clean + $(MAKE) final clean + $(MAKE) programs clean + $(MAKE) tools clean + $(SYNC) + +littleclean: + $(MAKE) system clean + $(MAKE) lib clean + $(MAKE) final littleclean + $(MAKE) programs clean + $(SYNC) + +indent: + $(MAKE) system indent + $(MAKE) lib indent + $(MAKE) programs indent + $(MAKE) tools indent + $(SYNC) + +backup: clean + cd .. + $(TAR) + +test: test32 + +retest: retest32 + +test32: tools programs system32 harddisk qemu32 + +test64: tools programs system64 harddiskuefi qemu64 + +retest32: littleclean test32 + +retest64: littleclean test64 + +testbochs: tools programs system32 harddisk bochs-debug + +view: + $(HEXDUMP) + +##### Debuguage + +debug: debug-system32 + +redebug32: littleclean debug-system32 + +debug64: debug-system64 + +redebug64: littleclean debug-system64 + +kernel: debug-kernel + +debug-boot: tools programs system32 harddisk qemu-debug32 + $(WAIT2S) + $(GODEBUG) ./debug/boot.txt + +debug-system32: tools programs system32 harddisk qemu-debug32 + $(WAIT2S) + $(GODEBUG) ./debug/system.txt + +debug-system64: tools programs system32 harddiskuefi qemu-debug64 + $(WAIT2S) + $(GODEBUG) ./debug/system.txt + +bochs-debug: killer + $(OLDEMUX86) ./debug/config.bochs + +killer: + $(KILL) bochs-debug $(TRUE) + $(KILL) qemu-system-x86_64 $(TRUE) + $(KILL) qemu-system-i386 $(TRUE) + $(KILL) gnome-terminal-server $(TRUE) + $(TMUXKILL) debug $(TRUE) + +##### Emulation + +qemu-debug32: killer + $(EMUX86) $(LEGACY) $(DEBUG) & + $(SPICE) & + +qemu-debug64: killer + $(EMUX64) $(UEFI) $(DEBUG) & + $(SPICE) & + +qemu32: killer + $(EMUX86) $(LEGACY) & + $(WAIT2S) + $(SPICE) + +qemu64: killer + $(EMUX64) $(UEFI) & + $(WAIT2S) + $(SPICE) + +system/system.sys: + $(MAKE) system + +final/harddisk.img.final: + $(MAKE) final harddisk.img.final + +final/harddiskuefi.img.final: + $(MAKE) final harddiskuefi.img.final + +lib/libs.o: + $(MAKE) lib diff --git a/programs/makefile b/programs/makefile index a17bb24..8e0afbe 100755 --- a/programs/makefile +++ b/programs/makefile @@ -1,38 +1,41 @@ -CC=gcc -O0 -g -nostdinc -ffreestanding -fno-builtin -Wall -w -m32 -I ./include -fno-pie -no-pie -c -o -LINK=ld -m elf_i386 -T linker.lds -n -o -SRCS= $(wildcard *.c) -EXECS= $(SRCS:.c=) -CONVERT=dos2unix -INDENT=indent -nhnl -l75 -ppi3 -ts8 -bls -nbc -di8 -nbad -nbap -nsob -i8 -bl -bli0 -ncdw -nce -cli8 -cbi0 -npcs -cs -saf -sai -saw -nprs -lp -npsl -REMOVE=rm -f -CHANGELF=elfedit --output-osabi FenixOS -CHANGEPERM=chmod 644 - -all: lib/libs.a $(EXECS) - sync - -togit: clean indent - -lib/libs.a: - make -C lib - -%: %.c - $(CC) $@.o $< - $(LINK) $@ $@.o lib/libs.a - $(CHANGEPERM) $@ - $(CHANGELF) $@ - -clean: - make -C lib clean - $(REMOVE) *.o - $(REMOVE) *.c~ - find . -type f ! -perm /u=x -maxdepth 1 -regex '.+/\.?[^\.]+' -exec $(REMOVE) {} \; - sync - -indent: - make -C lib indent - $(CHANGEPERM) *.c - $(CONVERT) *.c - $(INDENT) *.c - $(REMOVE) *.c~ - sync +CC=gcc -O0 -g -nostdinc -ffreestanding -fno-builtin -Wall -w -m32 -I ./include -fno-pie -no-pie -c -o +LINK=ld -m elf_i386 -T linker.lds -n -o +SRCS= $(wildcard *.c) +EXECS= $(SRCS:.c=) +CONVERT=dos2unix +INDENT=indent -nhnl -l75 -ppi3 -ts8 -bls -nbc -di8 -nbad -nbap -nsob -i8 -bl -bli0 -ncdw -nce -cli8 -cbi0 -npcs -cs -saf -sai -saw -nprs -lp -npsl +REMOVE=rm -f +CHANGELF=elfedit --output-osabi FenixOS +CHANGEPERM=chmod 644 +MAKE=make -C +SYNC=sync + +all: lib/libs.a $(EXECS) + $(SYNC) + +togit: clean indent + +lib/libs.a: + $(MAKE) lib + +%: %.c + $(CC) $@.o $< + $(LINK) $@ $@.o lib/libs.a + $(CHANGEPERM) $@ + $(CHANGELF) $@ + +clean: + $(MAKE) lib clean + $(REMOVE) *.o + $(REMOVE) *.c~ + find . -maxdepth 1 -type f ! -perm /u=x -regex '.+/\.?[^\.]+' -exec $(REMOVE) {} \; + $(SYNC) + +indent: + $(MAKE) lib indent + $(CHANGEPERM) *.c + $(CONVERT) *.c + $(INDENT) *.c + $(REMOVE) *.c~ + $(SYNC) + diff --git a/system/makefile b/system/makefile index 137a907..348cf33 100755 --- a/system/makefile +++ b/system/makefile @@ -1,83 +1,86 @@ -GCC=gcc -O0 -g -nostdinc -ffreestanding -fno-builtin -Wall -w -I ../include -m32 -fno-pie -no-pie -c -o -ASM=gcc -nostdinc -ffreestanding -fno-builtin -m32 -c -fno-pie -no-pie -I ../include -D__ASSEMBLY__ -c -o -LINK=ld -m elf_i386 -n -CONVERT=dos2unix -INDENT=indent -nhnl -l75 -ppi3 -ts8 -bls -nbc -di8 -nbad -nbap -nsob -i8 -bl -bli0 -ncdw -nce -cli8 -cbi0 -npcs -cs -saf -sai -saw -nprs -lp -npsl -REMOVE=rm -f -CHANGEPERM=chmod 644 -NM=nm -OBJCOPY=objcopy -O binary -R .note -R .comment -S -OBJDEBUG=objcopy --only-keep-debug -ZOFFSET=sed -n -e 's/^\([0-9a-fA-F]*\) [ABCDGRSTVW] \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|input_data\|_end\|_ehead\|_text\|z_.*\)$$/\#define ZO_\2 0x\1/p' -VOFFSET=sed -n -e 's/^\([0-9a-fA-F]*\) [ABCDGRSTVW] \(_text\|__bss_start\|_end\)$$/\#define VO_\2 _AC(0x\1,UL)/p' -COMP=gzip -9 -f -BUILD=../tools/build -MKPIGGY=../tools/mkpiggy - -all: system.sys - -system.sys: piggy.o voffset.h zoffset.h realmode/setup.bin - $(BUILD) realmode/setup.bin system.bin zoffset.h system.sys - sync - -allpiggy.o: piggy.o decompress.o header.o - $(LINK) -T allpiggy piggy.o decompress.o header.o - -voffset.h: system - $(NM) system|$(VOFFSET)>voffset.h - -zoffset.h: piggy.o - $(NM) piggy.o|$(ZOFFSET)>zoffset.h - -togit: clean indent - -piggy.o: piggy.S - $(ASM) $@ $^ - -system: system.o system_asm.o ../lib/libs.o - $(LINK) -T system.ld system.o system_asm.o ../lib/libs.o - $(OBJDEBUG) system system.sym - $(NM) system > system.map - -system.bin: system - $(OBJCOPY) $^ $@ - -system.bin.gz: system.bin - cat $^|$(COMP) > $@ - -piggy.S: system.bin.gz - $(MKPIGGY) $^ > $@ - -realmode/setup.bin: - make -C realmode - -system.o: system.c - $(GCC) $@ $^ - -system_asm.o: system_asm.S - $(ASM) $@ $^ - -clean: - make -C realmode clean - $(REMOVE) system - $(REMOVE) piggy.S - $(REMOVE) *.o - $(REMOVE) *.tmp - $(REMOVE) *.sym - $(REMOVE) *.map - $(REMOVE) *.gz - $(REMOVE) *.h - $(REMOVE) *.out - $(REMOVE) *.bin - $(REMOVE) *.sys - $(REMOVE) *.s - $(REMOVE) *.c~ - sync - -indent: - make -C realmode indent - $(CHANGEPERM) *.c - $(CONVERT) *.c - $(INDENT) *.c - $(REMOVE) *.c~ - sync +GCC=gcc -O0 -g -nostdinc -ffreestanding -fno-builtin -Wall -w -I ../include -m32 -fno-pie -no-pie -c -o +ASM=gcc -nostdinc -ffreestanding -fno-builtin -m32 -c -fno-pie -no-pie -I ../include -D__ASSEMBLY__ -c -o +LINK=ld -m elf_i386 -n +CONVERT=dos2unix +INDENT=indent -nhnl -l75 -ppi3 -ts8 -bls -nbc -di8 -nbad -nbap -nsob -i8 -bl -bli0 -ncdw -nce -cli8 -cbi0 -npcs -cs -saf -sai -saw -nprs -lp -npsl +REMOVE=rm -f +CHANGEPERM=chmod 644 +NM=nm +OBJCOPY=objcopy -O binary -R .note -R .comment -S +OBJDEBUG=objcopy --only-keep-debug +ZOFFSET=sed -n -e 's/^\([0-9a-fA-F]*\) [ABCDGRSTVW] \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|input_data\|_end\|_ehead\|_text\|z_.*\)$$/\#define ZO_\2 0x\1/p' +VOFFSET=sed -n -e 's/^\([0-9a-fA-F]*\) [ABCDGRSTVW] \(_text\|__bss_start\|_end\)$$/\#define VO_\2 _AC(0x\1,UL)/p' +COMP=gzip -9 -f +BUILD=../tools/build +MKPIGGY=../tools/mkpiggy +MAKE=make -C +SYNC=sync + +all: system.sys + +system.sys: piggy.o voffset.h zoffset.h realmode/setup.bin + $(BUILD) realmode/setup.bin system.bin zoffset.h system.sys + $(SYNC) + +allpiggy.o: piggy.o decompress.o header.o + $(LINK) -T allpiggy piggy.o decompress.o header.o + +voffset.h: system + $(NM) system|$(VOFFSET)>voffset.h + +zoffset.h: piggy.o + $(NM) piggy.o|$(ZOFFSET)>zoffset.h + +togit: clean indent + +piggy.o: piggy.S + $(ASM) $@ $^ + +system: system.o system_asm.o ../lib/libs.o + $(LINK) -T system.ld system.o system_asm.o ../lib/libs.o + $(OBJDEBUG) system system.sym + $(NM) system > system.map + +system.bin: system + $(OBJCOPY) $^ $@ + +system.bin.gz: system.bin + cat $^|$(COMP) > $@ + +piggy.S: system.bin.gz + $(MKPIGGY) $^ > $@ + +realmode/setup.bin: + $(MAKE) realmode + +system.o: system.c + $(GCC) $@ $^ + +system_asm.o: system_asm.S + $(ASM) $@ $^ + +clean: + $(MAKE) realmode clean + $(REMOVE) system + $(REMOVE) piggy.S + $(REMOVE) *.o + $(REMOVE) *.tmp + $(REMOVE) *.sym + $(REMOVE) *.map + $(REMOVE) *.gz + $(REMOVE) *.h + $(REMOVE) *.out + $(REMOVE) *.bin + $(REMOVE) *.sys + $(REMOVE) *.s + $(REMOVE) *.c~ + $(SYNC) + +indent: + $(MAKE) realmode indent + $(CHANGEPERM) *.c + $(CONVERT) *.c + $(INDENT) *.c + $(REMOVE) *.c~ + $(SYNC) + diff --git a/system/realmode/makefile b/system/realmode/makefile index 88f9fbf..fe4996e 100644 --- a/system/realmode/makefile +++ b/system/realmode/makefile @@ -9,9 +9,10 @@ NM=nm OBJCOPY=objcopy -O binary -R .note -R .comment -S OBJDEBUG=objcopy --only-keep-debug $(eval VERSION=$(shell git describe --tags)) +SYNC=sync all: setup.bin - sync + $(SYNC) setup: setupc.o setup.o setup32.o $(LINK) -T setup.ld setupc.o setup.o setup32.o @@ -40,11 +41,12 @@ clean: $(REMOVE) *.sys $(REMOVE) *.s $(REMOVE) *.c~ - sync + $(SYNC) indent: $(CHANGEPERM) *.c $(CONVERT) *.c $(INDENT) *.c $(REMOVE) *.c~ - sync + $(SYNC) + diff --git a/tools/makefile b/tools/makefile index 04c0792..0ae3b80 100755 --- a/tools/makefile +++ b/tools/makefile @@ -1,28 +1,28 @@ -CC=gcc -DCONFIG_X86_32 -I . -o -SRCS= $(wildcard *.c) -EXECS= $(SRCS:.c=) -CONVERT=dos2unix -INDENT=indent -nhnl -l75 -ppi3 -ts8 -bls -nbc -di8 -nbad -nbap -nsob -i8 -bl -bli0 -ncdw -nce -cli8 -cbi0 -npcs -cs -saf -sai -saw -nprs -lp -npsl -REMOVE=rm -f -CHANGELF=elfedit --output-osabi FenixOS -CHANGEPERM=chmod 644 - -all: $(EXECS) - sync - -togit: clean indent - -%: %.c - $(CC) $@ $< -clean: - $(REMOVE) *.o - $(REMOVE) *.c~ - find . -type f ! -name makefile -perm /u=x -maxdepth 1 -regex '.+/\.?[^\.]+' -exec $(REMOVE) {} \; - sync - -indent: - $(CHANGEPERM) *.c - $(CONVERT) *.c - $(INDENT) *.c - $(REMOVE) *.c~ - sync +CC=gcc -DCONFIG_X86_32 -I . -o +SRCS= $(wildcard *.c) +EXECS= $(SRCS:.c=) +CONVERT=dos2unix +INDENT=indent -nhnl -l75 -ppi3 -ts8 -bls -nbc -di8 -nbad -nbap -nsob -i8 -bl -bli0 -ncdw -nce -cli8 -cbi0 -npcs -cs -saf -sai -saw -nprs -lp -npsl +REMOVE=rm -f +CHANGELF=elfedit --output-osabi FenixOS +CHANGEPERM=chmod 644 + +all: $(EXECS) + sync + +togit: clean indent + +%: %.c + $(CC) $@ $< +clean: + $(REMOVE) *.o + $(REMOVE) *.c~ + find . -maxdepth 1 -type f ! -name makefile -perm /u=x -regex '.+/\.?[^\.]+' -exec $(REMOVE) {} \; + sync + +indent: + $(CHANGEPERM) *.c + $(CONVERT) *.c + $(INDENT) *.c + $(REMOVE) *.c~ + sync