|
| 1 | +package net.praqma.jenkins.memorymap.parser.powerpceabigcc; |
| 2 | + |
| 3 | +import hudson.AbortException; |
| 4 | +import hudson.Extension; |
| 5 | +import java.io.File; |
| 6 | +import java.io.IOException; |
| 7 | +import java.io.Serializable; |
| 8 | +import java.util.ArrayList; |
| 9 | +import java.util.Collections; |
| 10 | +import java.util.Comparator; |
| 11 | +import java.util.List; |
| 12 | +import java.util.logging.Level; |
| 13 | +import java.util.logging.Logger; |
| 14 | +import java.util.regex.Matcher; |
| 15 | +import java.util.regex.Pattern; |
| 16 | +import net.praqma.jenkins.memorymap.graph.MemoryMapGraphConfiguration; |
| 17 | +import net.praqma.jenkins.memorymap.parser.AbstractMemoryMapParser; |
| 18 | +import net.praqma.jenkins.memorymap.parser.MemoryMapParserDescriptor; |
| 19 | +import net.praqma.jenkins.memorymap.result.MemoryMapConfigMemory; |
| 20 | +import net.praqma.jenkins.memorymap.result.MemoryMapConfigMemoryItem; |
| 21 | +import net.praqma.jenkins.memorymap.util.HexUtils; |
| 22 | +import net.praqma.jenkins.memorymap.util.HexUtils.HexifiableString; |
| 23 | +import net.praqma.jenkins.memorymap.util.MemoryMapMemorySelectionError; |
| 24 | +import net.sf.json.JSONObject; |
| 25 | +import org.jenkinsci.Symbol; |
| 26 | +import org.kohsuke.stapler.DataBoundConstructor; |
| 27 | +import org.kohsuke.stapler.StaplerRequest; |
| 28 | + |
| 29 | +/** |
| 30 | + * @author Praqma |
| 31 | + */ |
| 32 | +public class PowerPCEabiGccMemoryMapParser extends AbstractMemoryMapParser implements Serializable { |
| 33 | + |
| 34 | + private static final Pattern MEM_SECTIONS = Pattern.compile("^\\s*(\\S+)(?=.*:)", Pattern.MULTILINE); |
| 35 | + private static final Pattern COMMENT_BLOCKS = Pattern.compile("\\/\\*[\\s\\S]*?\\*\\/"); |
| 36 | + private static final Logger LOG = Logger.getLogger(PowerPCEabiGccMemoryMapParser.class.getName()); |
| 37 | + |
| 38 | + @DataBoundConstructor |
| 39 | + public PowerPCEabiGccMemoryMapParser(String parserUniqueName, String mapFile, String configurationFile, Integer wordSize, Boolean bytesOnGraph, List<MemoryMapGraphConfiguration> graphConfiguration) { |
| 40 | + super(parserUniqueName, mapFile, configurationFile, wordSize, bytesOnGraph, graphConfiguration); |
| 41 | + } |
| 42 | + |
| 43 | + /** |
| 44 | + * Strip any c-style block comments, e.g slash-star to star-slash. |
| 45 | + * <b>Note:</b> this function down not correctly handle nested comment |
| 46 | + * blocks. |
| 47 | + * <b>Note:</b> this function is a bit greedy, and will incorrectly strip |
| 48 | + * comments inside strings, but this shouldn't be a problem for memory |
| 49 | + * config files. |
| 50 | + * |
| 51 | + * @param seq The content of a file that might contain c-style |
| 52 | + * block-comments |
| 53 | + * @return The same content, that has now had all block-comments stripped |
| 54 | + * out. |
| 55 | + */ |
| 56 | + public static CharSequence stripComments(CharSequence seq) { |
| 57 | + Matcher commentMatcher = COMMENT_BLOCKS.matcher(seq); |
| 58 | + return commentMatcher.replaceAll(""); |
| 59 | + } |
| 60 | + |
| 61 | + /** |
| 62 | + * Parses the MEMORY section of the GCC file. Throws an abort exception |
| 63 | + * which will be shown in the Jenkins console log. |
| 64 | + * |
| 65 | + * @param seq The content of the map file |
| 66 | + * @return a list of the defined MEMORY in the map file |
| 67 | + * @throws hudson.AbortException when a illegal value of memory found |
| 68 | + * |
| 69 | + */ |
| 70 | + public MemoryMapConfigMemory getMemory(CharSequence seq) throws AbortException { |
| 71 | + |
| 72 | + Pattern allMemory = Pattern.compile("^\\s*(\\S+).*?(?:ORIGIN|org|o)\\s*=\\s*\\(([^,]*)\\).*?(?:LENGTH|len|l)\\s*\\=\\s*([^\\s]*.*)", Pattern.MULTILINE); |
| 73 | + Matcher match = allMemory.matcher(seq); |
| 74 | + MemoryMapConfigMemory memory = new MemoryMapConfigMemory(); |
| 75 | + while (match.find()) { |
| 76 | + String sectionName = match.group(1); |
| 77 | + String sectionAddress = match.group(2).replace("(", "").replace(")", "").replace(" ", ""); |
| 78 | + String sectionLength = match.group(3).replace("(", "").replace(")", "").replace(" ", ""); |
| 79 | + |
| 80 | + sectionAddress = getHexSum(sectionAddress); |
| 81 | + sectionLength = getHexSum(sectionLength); |
| 82 | + |
| 83 | + try { |
| 84 | + String hexLength = new HexUtils.HexifiableString(sectionLength).toValidHexString().rawString; |
| 85 | + MemoryMapConfigMemoryItem item = new MemoryMapConfigMemoryItem(sectionName, sectionAddress, hexLength); |
| 86 | + memory.add(item); |
| 87 | + } catch (Throwable ex) { |
| 88 | + logger.log(Level.SEVERE, "Unable to convert %s to a valid hex string.", ex); |
| 89 | + throw new AbortException(String.format("Unable to convert %s to a valid hex string.", sectionLength)); |
| 90 | + } |
| 91 | + } |
| 92 | + return memory; |
| 93 | + } |
| 94 | + |
| 95 | + private static String getHexSum(String group) |
| 96 | + { |
| 97 | + Long sum = Long.valueOf(0L); |
| 98 | + |
| 99 | + String buff = group.replace("0x", ""); |
| 100 | + try |
| 101 | + { |
| 102 | + String[] groupPluses = buff.split("\\+"); |
| 103 | + if (groupPluses.length > 0) { |
| 104 | + for (String str1 : groupPluses) |
| 105 | + { |
| 106 | + String[] minusGroup = str1.split("\\-"); |
| 107 | + if (minusGroup.length > 0) { |
| 108 | + for (int i = 0; i < minusGroup.length; i++) { |
| 109 | + if (i == 0) { |
| 110 | + sum = Long.valueOf(sum.longValue() + Long.parseLong(minusGroup[i], 16)); |
| 111 | + } else { |
| 112 | + sum = Long.valueOf(sum.longValue() - Long.parseLong(minusGroup[i], 16)); |
| 113 | + } |
| 114 | + } |
| 115 | + } else { |
| 116 | + sum = Long.valueOf(sum.longValue() + Long.parseLong(str1, 16)); |
| 117 | + } |
| 118 | + } |
| 119 | + } else { |
| 120 | + sum = Long.valueOf(sum.longValue() + Long.parseLong(group, 16)); |
| 121 | + } |
| 122 | + } |
| 123 | + catch (NumberFormatException ex) |
| 124 | + { |
| 125 | + return group; |
| 126 | + } |
| 127 | + return "0x" + Long.toHexString(sum.longValue()); |
| 128 | + } |
| 129 | + |
| 130 | + /* |
| 131 | + * SECTIONS { |
| 132 | + * --- |
| 133 | + * secname start BLOCK(align) (NOLOAD) : AT ( ldadr ) |
| 134 | + { contents } >region =fill |
| 135 | + ... |
| 136 | + } |
| 137 | + * |
| 138 | + */ |
| 139 | + public List<MemoryMapConfigMemoryItem> getSections(CharSequence m) { |
| 140 | + List<MemoryMapConfigMemoryItem> items = new ArrayList<>(); |
| 141 | + |
| 142 | + Pattern section = Pattern.compile("SECTIONS\\s?\\r?\\n?\\{([\\s\\S]*)\\n\\}", Pattern.MULTILINE); |
| 143 | + |
| 144 | + Matcher sectionMatched = section.matcher(m); |
| 145 | + String sectionString = null; |
| 146 | + |
| 147 | + while (sectionMatched.find()) { |
| 148 | + sectionString = sectionMatched.group(1); |
| 149 | + } |
| 150 | + |
| 151 | + //Find the good stuff (SECTION): *SECTIONS\n\{(.*)\n\} |
| 152 | + Matcher fm = MEM_SECTIONS.matcher(sectionString); |
| 153 | + |
| 154 | + while (fm.find()) { |
| 155 | + MemoryMapConfigMemoryItem it = new MemoryMapConfigMemoryItem(fm.group(1), "0"); |
| 156 | + items.add(it); |
| 157 | + } |
| 158 | + return items; |
| 159 | + } |
| 160 | + |
| 161 | + public PowerPCEabiGccMemoryMapParser() { |
| 162 | + super(); |
| 163 | + } |
| 164 | + |
| 165 | + public Pattern getLinePatternForMapFile(String sectionName) { |
| 166 | + return Pattern.compile(String.format("^(%s)(\\s+)(\\w+)(\\s+)(\\w+)(\\w*)", sectionName), Pattern.MULTILINE); |
| 167 | + } |
| 168 | + |
| 169 | + private static class MemoryMapMemItemComparator implements Comparator<MemoryMapConfigMemoryItem>, Serializable { |
| 170 | + @Override |
| 171 | + public int compare(MemoryMapConfigMemoryItem t, MemoryMapConfigMemoryItem t1) { |
| 172 | + long vt = new HexifiableString(t.getOrigin()).getLongValue(); |
| 173 | + long vt1 = new HexifiableString(t1.getOrigin()).getLongValue(); |
| 174 | + return (vt < vt1 ? -1 : (vt == vt1 ? 1 : 0)); |
| 175 | + } |
| 176 | + } |
| 177 | + |
| 178 | + /** |
| 179 | + * Given an item with length == null. Look down in the list. If we find an |
| 180 | + * item whose length is not null, set the items length to that |
| 181 | + * |
| 182 | + * @param memory the memory list |
| 183 | + * @return a more complete configuration, where i have better values |
| 184 | + */ |
| 185 | + public MemoryMapConfigMemory guessLengthOfSections(MemoryMapConfigMemory memory) { |
| 186 | + Collections.sort(memory, new MemoryMapMemItemComparator()); |
| 187 | + |
| 188 | + for (MemoryMapConfigMemoryItem item : memory) { |
| 189 | + if (item.getLength() == null) { |
| 190 | + int itemIndex = memory.indexOf(item); |
| 191 | + for (int i = itemIndex; i > 1; i--) { |
| 192 | + if (memory.get(i).getLength() != null) { |
| 193 | + item.setParent(memory.get(i)); |
| 194 | + break; |
| 195 | + } |
| 196 | + } |
| 197 | + |
| 198 | + } |
| 199 | + } |
| 200 | + return memory; |
| 201 | + } |
| 202 | + |
| 203 | + @Override |
| 204 | + public MemoryMapConfigMemory parseMapFile(File f, MemoryMapConfigMemory configuration) throws IOException { |
| 205 | + CharSequence sequence = createCharSequenceFromFile(f); |
| 206 | + |
| 207 | + for (MemoryMapConfigMemoryItem item : configuration) { |
| 208 | + Matcher m = getLinePatternForMapFile(item.getName()).matcher(sequence); |
| 209 | + while (m.find()) { |
| 210 | + item.setOrigin(m.group(3)); |
| 211 | + item.setUsed(m.group(5)); |
| 212 | + } |
| 213 | + } |
| 214 | + |
| 215 | + configuration = guessLengthOfSections(configuration); |
| 216 | + |
| 217 | + return configuration; |
| 218 | + } |
| 219 | + |
| 220 | + @Override |
| 221 | + public MemoryMapConfigMemory parseConfigFile(File f) throws IOException { |
| 222 | + //Collect sections from both the MEMORY and the SECTIONS areas from the command file. |
| 223 | + //The memory are the top level components, sections belong to one of these sections |
| 224 | + CharSequence stripped = stripComments(createCharSequenceFromFile(f)); |
| 225 | + |
| 226 | + MemoryMapConfigMemory memConfig = getMemory(stripped); |
| 227 | + memConfig.addAll(getSections(stripped)); |
| 228 | + for (MemoryMapGraphConfiguration g : getGraphConfiguration()) { |
| 229 | + for (String gItem : g.itemizeGraphDataList()) { |
| 230 | + for (String gSplitItem : gItem.split("\\+")) { |
| 231 | + //We will fail if the name of the data section does not match any of the named items in the map file. |
| 232 | + if (!memConfig.containsSectionWithName(gSplitItem)) { |
| 233 | + throw new MemoryMapMemorySelectionError(String.format("The memory section named %s not found in map file%nAvailable sections are:%n%s", gSplitItem, memConfig.getItemNames())); |
| 234 | + } |
| 235 | + } |
| 236 | + } |
| 237 | + } |
| 238 | + return memConfig; |
| 239 | + } |
| 240 | + |
| 241 | + @Override |
| 242 | + public int getDefaultWordSize() { |
| 243 | + return 8; |
| 244 | + } |
| 245 | + |
| 246 | + @Symbol("powerPCEabiGccParser") |
| 247 | + @Extension |
| 248 | + public static final class DescriptorImpl extends MemoryMapParserDescriptor<PowerPCEabiGccMemoryMapParser> { |
| 249 | + |
| 250 | + @Override |
| 251 | + public String getDisplayName() { |
| 252 | + return "PowerPCEabiGcc"; |
| 253 | + } |
| 254 | + |
| 255 | + @Override |
| 256 | + public AbstractMemoryMapParser newInstance(StaplerRequest req, JSONObject formData, AbstractMemoryMapParser instance) throws FormException { |
| 257 | + PowerPCEabiGccMemoryMapParser parser = (PowerPCEabiGccMemoryMapParser) instance; |
| 258 | + save(); |
| 259 | + return parser; |
| 260 | + } |
| 261 | + } |
| 262 | +} |
0 commit comments