15867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com/* 25867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * [The "BSD licence"] 300fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * Copyright (c) 2010 Ben Gruver (JesusFreke) 45867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * All rights reserved. 55867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * 65867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * Redistribution and use in source and binary forms, with or without 75867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * modification, are permitted provided that the following conditions 85867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * are met: 95867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * 1. Redistributions of source code must retain the above copyright 105867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * notice, this list of conditions and the following disclaimer. 115867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * 2. Redistributions in binary form must reproduce the above copyright 125867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * notice, this list of conditions and the following disclaimer in the 135867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * documentation and/or other materials provided with the distribution. 145867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * 3. The name of the author may not be used to endorse or promote products 155867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * derived from this software without specific prior written permission. 165867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * 175867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 185867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 195867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 205867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 215867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 225867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 235867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 245867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 255867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 265867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 275867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com */ 285867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 295867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.compackage org.jf.dexlib.Util; 305867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 315867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.comimport org.jf.dexlib.CodeItem; 325867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.comimport org.jf.dexlib.TypeIdItem; 335867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 345867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.comimport java.util.ArrayList; 355867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.comimport java.util.HashMap; 365867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.comimport java.util.LinkedList; 375867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.comimport java.util.List; 385867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 395867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.compublic class TryListBuilder 405867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com{ 415867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com /*TODO: add logic to merge adjacent, identical try blocks, and remove superflous handlers 425867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com Also provide a "strict" mode, where the above isn't performed, which will be useful to be able to 435867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com exactly reproduce the original .dex file (for testing/verification purposes)*/ 445867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 455867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 465867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com private TryRange firstTryRange = new TryRange(0,0); 475867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com private TryRange lastTryRange = new TryRange(0,0); 485867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 495867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com public TryListBuilder() { 505867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com firstTryRange.next = lastTryRange; 515867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com lastTryRange.previous = firstTryRange; 525867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 535867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 545867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com private class TryRange 555867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com { 565867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com public TryRange previous = null; 575867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com public TryRange next = null; 585867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 595867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com public int startAddress; 605867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com public int endAddress; 615867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com public LinkedList<Handler> handlers; 625867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 635867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com public int catchAllHandlerAddress; 645867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 655867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com public TryRange(int startAddress, int endAddress) { 665867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com this.startAddress = startAddress; 675867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com this.endAddress = endAddress; 685867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com this.handlers = new LinkedList<Handler>(); 695867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com this.previous = null; 705867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com this.next = null; 715867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com catchAllHandlerAddress = -1; 725867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 735867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 745867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com public void append(TryRange tryRange) { 755867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com /*we use a dummy last item, so this.next will always 765867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com have a value*/ 775867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com this.next.previous = tryRange; 785867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com tryRange.next = this.next; 795867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 805867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com this.next = tryRange; 815867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com tryRange.previous = this; 825867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 835867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 845867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com public void prepend(TryRange tryRange){ 855867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com /*we use a dummy first item, so this.previous will always 865867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com have a value*/ 875867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com this.previous.next = tryRange; 885867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com tryRange.previous = this.previous; 895867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 905867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com this.previous = tryRange; 915867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com tryRange.next = this; 925867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 935867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 945867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com /** 955867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * This splits the current range into two ranges at the given 965867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * address. The existing range will be shortened to the first 975867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * half, and a new range will be created and returned for the 985867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * 2nd half. 995867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * @param address The address to split at 1005867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * @return The 2nd half of the 1015867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com */ 1025867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com public TryRange split(int address) { 1035867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com //this is a private class, so address is assumed 1045867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com //to be valid 1055867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 1065867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com TryRange tryRange = new TryRange(address, endAddress); 1075867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com tryRange.catchAllHandlerAddress = this.catchAllHandlerAddress; 1085867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com tryRange.handlers.addAll(this.handlers); 1095867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com append(tryRange); 1105867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 1115867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com this.endAddress = address; 1125867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 1135867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com return tryRange; 1145867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 1155867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 1165867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com public void appendHandler(Handler handler) { 1175867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com handlers.addLast(handler); 1185867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 1195867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 1205867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com public void prependHandler(Handler handler) { 1215867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com handlers.addFirst(handler); 1225867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 1235867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 1245867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 1255867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com private class Handler 1265867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com { 1275867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com public final TypeIdItem type; 1285867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com public final int handlerAddress; 1295867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 1305867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com public Handler(TypeIdItem type, int handlerAddress) { 1315867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com this.type = type; 1325867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com this.handlerAddress = handlerAddress; 1335867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 1345867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 1355867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 1365867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com public Pair<List<CodeItem.TryItem>, List<CodeItem.EncodedCatchHandler>> encodeTries() { 1375867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com if (firstTryRange.next == lastTryRange) { 1385867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com return new Pair<List<CodeItem.TryItem>, List<CodeItem.EncodedCatchHandler>>(null, null); 1395867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 1405867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 1415867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com ArrayList<CodeItem.TryItem> tries = new ArrayList<CodeItem.TryItem>(); 1425867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com ArrayList<CodeItem.EncodedCatchHandler> handlers = new ArrayList<CodeItem.EncodedCatchHandler>(); 1435867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 1445867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com HashMap<CodeItem.EncodedCatchHandler, CodeItem.EncodedCatchHandler> handlerDict = 1455867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com new HashMap<CodeItem.EncodedCatchHandler, CodeItem.EncodedCatchHandler>(); 1465867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 1475867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com TryRange tryRange = firstTryRange.next; 1485867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 1495867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com while (tryRange != lastTryRange) { 1505867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com CodeItem.EncodedTypeAddrPair[] encodedTypeAddrPairs = 1515867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com new CodeItem.EncodedTypeAddrPair[tryRange.handlers.size()]; 1525867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 1535867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com int index = 0; 1545867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com for (Handler handler: tryRange.handlers) { 1555867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com CodeItem.EncodedTypeAddrPair encodedTypeAddrPair = new CodeItem.EncodedTypeAddrPair( 1565867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com handler.type, 1575867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com handler.handlerAddress); 1585867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com encodedTypeAddrPairs[index++] = encodedTypeAddrPair; 1595867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 1605867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 1615867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com CodeItem.EncodedCatchHandler encodedCatchHandler = new CodeItem.EncodedCatchHandler( 1625867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com encodedTypeAddrPairs, 1635867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com tryRange.catchAllHandlerAddress); 1645867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com CodeItem.EncodedCatchHandler internedEncodedCatchHandler = handlerDict.get(encodedCatchHandler); 1655867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com if (internedEncodedCatchHandler == null) { 1665867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com handlerDict.put(encodedCatchHandler, encodedCatchHandler); 1675867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com handlers.add(encodedCatchHandler); 1685867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } else { 1695867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com encodedCatchHandler = internedEncodedCatchHandler; 1705867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 1715867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 1725867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com CodeItem.TryItem tryItem = new CodeItem.TryItem( 1735867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com tryRange.startAddress, 1745867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com tryRange.endAddress - tryRange.startAddress, 1755867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com encodedCatchHandler); 1765867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com tries.add(tryItem); 1775867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 1785867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com tryRange = tryRange.next; 1795867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 1805867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 1815867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com return new Pair<List<CodeItem.TryItem>, List<CodeItem.EncodedCatchHandler>>(tries, handlers); 1825867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 1835867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 1845867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com public void addCatchAllHandler(int startAddress, int endAddress, int handlerAddress) { 1855867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com TryRange startRange; 1865867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com TryRange endRange; 1875867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 1885867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com Pair<TryRange, TryRange> ranges = getBoundingRanges(startAddress, endAddress); 1895867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com startRange = ranges.first; 1905867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com endRange = ranges.second; 1915867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 1925867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com int previousEnd = startAddress; 1935867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com TryRange tryRange = startRange; 1945867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 1955867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com /*Now we have the start and end ranges that exactly match the start and end 1965867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com of the range being added. We need to iterate over all the ranges from the start 1975867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com to end range inclusively, and append the handler to the end of each range's handler 1985867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com list. We also need to create a new range for any "holes" in the existing ranges*/ 1995867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com do 2005867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com { 2015867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com //is there a hole? If so, add a new range to fill the hole 2025867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com if (tryRange.startAddress > previousEnd) { 2035867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com TryRange newRange = new TryRange(previousEnd, tryRange.startAddress); 2045867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com tryRange.prepend(newRange); 2055867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com tryRange = newRange; 2065867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 2075867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 2085867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com if (tryRange.catchAllHandlerAddress == -1) { 2095867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com tryRange.catchAllHandlerAddress = handlerAddress; 2105867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 2115867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 2125867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com previousEnd = tryRange.endAddress; 2135867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com tryRange = tryRange.next; 2145867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } while (tryRange.previous != endRange); 2155867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 2165867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 2175867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com public Pair<TryRange, TryRange> getBoundingRanges(int startAddress, int endAddress) { 2185867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com TryRange startRange = null; 2195867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com TryRange endRange = null; 2205867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 2215867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com TryRange tryRange = firstTryRange.next; 2225867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com while (tryRange != lastTryRange) { 2235867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com if (startAddress == tryRange.startAddress) { 2245867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com //|-----| 2255867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com //^------ 2265867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com /*Bam. We hit the start of the range right on the head*/ 2275867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com startRange = tryRange; 2285867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com break; 2295867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } else if (startAddress > tryRange.startAddress && startAddress < tryRange.endAddress) { 2305867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com //|-----| 2315867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com // ^---- 2325867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com /*Almost. The start of the range being added is in the middle 2335867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com of an existing try range. We need to split the existing range 2345867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com at the start address of the range being added*/ 2355867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com startRange = tryRange.split(startAddress); 2365867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com break; 2375867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com }else if (startAddress < tryRange.startAddress) { 2385867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com if (endAddress <= tryRange.startAddress) { 2395867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com // |-----| 2405867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com //^--^ 2415867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com /*Oops, totally too far! The new range doesn't overlap any existing 2425867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com ones, so we just add it and return*/ 2435867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com startRange = new TryRange(startAddress, endAddress); 2445867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com tryRange.prepend(startRange); 2455867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com return new Pair<TryRange, TryRange>(startRange, startRange); 2465867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } else { 2475867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com // |-----| 2485867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com //^--------- 2495867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com /*Oops, too far! We've passed the start of the range being added, but 2505867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com the new range does overlap this one. We need to add a new range just 2515867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com before this one*/ 2525867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com startRange = new TryRange(startAddress, tryRange.startAddress); 2535867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com tryRange.prepend(startRange); 2545867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com break; 2555867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 2565867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 2575867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 2585867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com tryRange = tryRange.next; 2595867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 2605867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 2615867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com //|-----| 2625867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com // ^----- 2635867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com /*Either the list of tries is blank, or all the tries in the list 2645867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com end before the range being added starts. In either case, we just need 2655867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com to add a new range at the end of the list*/ 2665867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com if (startRange == null) { 2675867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com startRange = new TryRange(startAddress, endAddress); 2685867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com lastTryRange.prepend(startRange); 2695867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com return new Pair<TryRange, TryRange>(startRange, startRange); 2705867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 2715867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 2725867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com tryRange = startRange; 2735867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com while (tryRange != lastTryRange) { 2745867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com if (tryRange.endAddress == endAddress) { 2755867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com //|-----| 2765867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com //------^ 2775867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com /*Bam! We hit the end right on the head.*/ 2785867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com endRange = tryRange; 2795867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com break; 2805867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } else if (tryRange.startAddress < endAddress && tryRange.endAddress > endAddress) { 2815867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com //|-----| 2825867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com //--^ 2835867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com /*Almost. The range being added ends in the middle of an 2845867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com existing range. We need to split the existing range 2855867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com at the end of the range being added.*/ 2865867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com tryRange.split(endAddress); 2875867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com endRange = tryRange; 2885867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com break; 2895867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } else if (tryRange.startAddress >= endAddress) { 2905867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com //|-----| |-----| 2915867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com //-----------^ 2925867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com /*Oops, too far! The current range starts after the range being added 2935867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com ends. We need to create a new range that starts at the end of the 2945867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com previous range, and ends at the end of the range being added*/ 2955867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com endRange = new TryRange(tryRange.previous.endAddress, endAddress); 2965867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com tryRange.prepend(endRange); 2975867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com break; 2985867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 2995867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com tryRange = tryRange.next; 3005867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 3015867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 3025867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com //|-----| 3035867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com //--------^ 3045867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com /*The last range in the list ended before the end of the range being added. 3055867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com We need to add a new range that starts at the end of the last range in the 3065867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com list, and ends at the end of the range being added.*/ 3075867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com if (endRange == null) { 3085867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com endRange = new TryRange(lastTryRange.previous.endAddress, endAddress); 3095867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com lastTryRange.prepend(endRange); 3105867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 3115867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 3125867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com return new Pair<TryRange, TryRange>(startRange, endRange); 3135867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 3145867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 3155867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com public void addHandler(TypeIdItem type, int startAddress, int endAddress, int handlerAddress) { 3165867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com TryRange startRange; 3175867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com TryRange endRange; 3185867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 3195867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com //TODO: need to check for pre-existing exception types in the handler list? 3205867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 3215867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com Pair<TryRange, TryRange> ranges = getBoundingRanges(startAddress, endAddress); 3225867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com startRange = ranges.first; 3235867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com endRange = ranges.second; 3245867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com Handler handler = new Handler(type, handlerAddress); 3255867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 3265867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com int previousEnd = startAddress; 3275867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com TryRange tryRange = startRange; 3285867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 3295867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com /*Now we have the start and end ranges that exactly match the start and end 3305867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com of the range being added. We need to iterate over all the ranges from the start 3315867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com to end range inclusively, and append the handler to the end of each range's handler 3325867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com list. We also need to create a new range for any "holes" in the existing ranges*/ 3335867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com do 3345867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com { 3355867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com //is there a hole? If so, add a new range to fill the hole 3365867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com if (tryRange.startAddress > previousEnd) { 3375867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com TryRange newRange = new TryRange(previousEnd, tryRange.startAddress); 3385867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com tryRange.prepend(newRange); 3395867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com tryRange = newRange; 3405867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 3415867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com 3425867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com tryRange.appendHandler(handler); 3435867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com previousEnd = tryRange.endAddress; 3445867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com tryRange = tryRange.next; 3455867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } while (tryRange.previous != endRange); 3465867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com } 3475867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com} 348