LEFT | RIGHT |
(no file at all) | |
| 1 # This file is part of LilyPond, the GNU music typesetter. |
| 2 # |
| 3 # Copyright (C) 2012 Joe Neeman <joeneeman@gmail.com> |
| 4 # |
| 5 # LilyPond is free software: you can redistribute it and/or modify |
| 6 # it under the terms of the GNU General Public License as published by |
| 7 # the Free Software Foundation, either version 3 of the License, or |
| 8 # (at your option) any later version. |
| 9 # |
| 10 # LilyPond is distributed in the hope that it will be useful, |
| 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 # GNU General Public License for more details. |
| 14 # |
| 15 # You should have received a copy of the GNU General Public License |
| 16 # along with LilyPond. If not, see <http://www.gnu.org/licenses/>. |
| 17 |
| 18 # A gdb plugin debugging skylines. To use the plugin, make sure that |
| 19 # skyline_viewer.py is in your PATH, then add |
| 20 # source /path/to/show_skyline_command.py |
| 21 # to your .gdbinit file. The 'vsky' and 'hsky' commands for |
| 22 # drawing skylines will then be available in gdb. |
| 23 |
| 24 import gdb |
| 25 from subprocess import Popen, PIPE |
| 26 from math import isinf |
| 27 |
| 28 SKYLINE_VIEWER = 'skyline_viewer.py' |
| 29 |
| 30 # Function taken from GCC |
| 31 def find_type(orig, name): |
| 32 typ = orig.strip_typedefs() |
| 33 while True: |
| 34 search = str(typ) + '::' + name |
| 35 try: |
| 36 return gdb.lookup_type(search) |
| 37 except RuntimeError: |
| 38 pass |
| 39 # The type was not found, so try the superclass. We only need |
| 40 # to check the first superclass, so we don't bother with |
| 41 # anything fancier here. |
| 42 field = typ.fields()[0] |
| 43 if not field.is_base_class: |
| 44 raise ValueError, "Cannot find type %s::%s" % (str(orig), name) |
| 45 typ = field.type |
| 46 |
| 47 # Class adapted from GCC |
| 48 class ListIterator: |
| 49 def __init__ (self, val): |
| 50 self.val = val |
| 51 self.nodetype = find_type (val.type, '_Node') |
| 52 self.nodetype = self.nodetype.strip_typedefs ().pointer () |
| 53 |
| 54 head = val['_M_impl']['_M_node'] |
| 55 self.base = head['_M_next'] |
| 56 self.head = head.address |
| 57 |
| 58 def __iter__ (self): |
| 59 return self |
| 60 |
| 61 def next (self): |
| 62 if self.base == self.head: |
| 63 raise StopIteration |
| 64 elt = self.base.cast (self.nodetype).dereference () |
| 65 self.base = elt['_M_next'] |
| 66 return elt['_M_data'] |
| 67 |
| 68 def to_list (list_val): |
| 69 return list (ListIterator (list_val)) |
| 70 |
| 71 def skyline_to_lines (sky_value): |
| 72 """Turns a gdb.Value into a list of line segments.""" |
| 73 sky_d = int (sky_value['sky_']) |
| 74 buildings = to_list (sky_value['buildings_']) |
| 75 |
| 76 def bld_to_line (bld): |
| 77 y_intercept = float (bld['y_intercept_']) * sky_d |
| 78 slope = float (bld['slope_']) * sky_d |
| 79 x1 = float (bld['start_']) |
| 80 x2 = float (bld['end_']) |
| 81 |
| 82 if isinf (y_intercept) or isinf (x1) or isinf (x2): |
| 83 return None |
| 84 return (x1, y_intercept + slope * x1, x2, y_intercept + slope * x2) |
| 85 |
| 86 ret = map (bld_to_line, buildings) |
| 87 return [r for r in ret if r is not None] |
| 88 |
| 89 viewer = Popen(SKYLINE_VIEWER, stdin=PIPE) |
| 90 def add_skyline(lines): |
| 91 global viewer |
| 92 try: |
| 93 for line in lines: |
| 94 x1, y1, x2, y2 = line |
| 95 viewer.stdin.write('(%f,%f) (%f,%f)\n' % (x1, y1, x2, y2)) |
| 96 viewer.stdin.write('\n') |
| 97 except IOError: |
| 98 # If the pipe is broken, it probably means that someone closed |
| 99 # the viewer window. Open another one. |
| 100 viewer = Popen(SKYLINE_VIEWER, stdin=PIPE) |
| 101 add_skyline(lines) |
| 102 |
| 103 class ShowSkylineCommand (gdb.Command): |
| 104 "Show a skyline graphically." |
| 105 |
| 106 def __init__ (self, command_name): |
| 107 super (ShowSkylineCommand, self).__init__ (command_name, |
| 108 gdb.COMMAND_DATA, |
| 109 gdb.COMPLETE_SYMBOL, False) |
| 110 |
| 111 def to_lines (self, skyline): |
| 112 pass |
| 113 |
| 114 def invoke (self, arg, from_tty): |
| 115 global plot |
| 116 |
| 117 val = gdb.parse_and_eval (arg) |
| 118 typ = val.type |
| 119 |
| 120 # If they passed in a reference or pointer to a skyline, |
| 121 # dereference it. |
| 122 if typ.code == gdb.TYPE_CODE_PTR or typ.code == gdb.TYPE_CODE_REF: |
| 123 val = val.referenced_value () |
| 124 typ = val.type |
| 125 |
| 126 if typ.tag == 'Skyline_pair': |
| 127 sky = val['skylines_'] |
| 128 arr = sky['array_'] |
| 129 add_skyline (self.to_lines (arr[0])) |
| 130 add_skyline (self.to_lines (arr[1])) |
| 131 |
| 132 elif typ.tag == 'Skyline': |
| 133 add_skyline (self.to_lines (val)) |
| 134 |
| 135 class ShowVSkylineCommand (ShowSkylineCommand): |
| 136 "Show a vertical skyline." |
| 137 |
| 138 def __init__ (self): |
| 139 super (ShowVSkylineCommand, self).__init__ ("vsky") |
| 140 |
| 141 def to_lines (self, skyline): |
| 142 return skyline_to_lines (skyline) |
| 143 |
| 144 class ShowHSkylineCommand (ShowSkylineCommand): |
| 145 "Show a horizontal skyline." |
| 146 |
| 147 def __init__ (self): |
| 148 super (ShowHSkylineCommand, self).__init__ ("hsky") |
| 149 |
| 150 def to_lines (self, skyline): |
| 151 lines = skyline_to_lines (skyline) |
| 152 # Because it is a horizontal skyline, reflect around the line y=x. |
| 153 return [(y1, x1, y2, x2) for (x1, y1, x2, y2) in lines] |
| 154 |
| 155 ShowHSkylineCommand() |
| 156 ShowVSkylineCommand() |
| 157 |
LEFT | RIGHT |