@Override
	public void moveAddressRange(Address fromAddr, Address toAddr, long length, TaskMonitor monitor)
			throws AddressOverflowException, CancelledException {

		if (length < 0) {
			throw new IllegalArgumentException(
				"Invalid negative length for moveAddressRange: " + length);
		}

		if (length == 0) {
			return; // nothing to do
		}

		lock.acquire();

		try {
			Address rangeToMoveEnd = fromAddr.addNoWrap(length - 1);
			AddressRange rangeToMove = new AddressRangeImpl(fromAddr, rangeToMoveEnd);
			RecordIterator recIter =
				sourceMapTableAdapter.getSourceMapRecordIterator(rangeToMoveEnd, false);
			boolean mapChanged = false;

			// Note: we iterate backwards since records are stored based on the start address.
			// We need to move records stored before the beginning of rangeToMove that 
			// overlap rangeToMove but we will never need to move records that start after  
			// rangeToMove.
			List<SourceMapEntryData> entriesToCreate = new ArrayList<>();
			while (recIter.hasPrevious()) {
				monitor.checkCancelled();
				DBRecord rec = recIter.previous();
				long entryLength = getLength(rec);
				if (entryLength == 0) {
					continue; // nothing to check
				}
				Address recStart = getStartAddress(rec);
				Address recEnd = getEndAddress(recStart, entryLength);

				if (!rangeToMove.intersects(recStart, recEnd)) {
					// we've found an entry entirely before rangeToMove
					// this means we can stop looking
					break;
				}
				long fileAndLine = getFileAndLine(rec);
				long fileId = fileAndLine >> 32;
				int lineNum = (int) (fileAndLine & 0xffffffff);

				if (isLessInSameSpace(recStart, fromAddr) &&
					isLessInSameSpace(rangeToMoveEnd, recEnd)) {
					// entry extends over left and right endpoint of rangeToMove
					long newLength = fromAddr.subtract(recStart);
					SourceMapEntryData left =
						new SourceMapEntryData(fileId, lineNum, recStart, newLength);
					entriesToCreate.add(left);
					SourceMapEntryData middle =
						new SourceMapEntryData(fileId, lineNum, fromAddr, length);
					entriesToCreate.add(middle);
					newLength = recEnd.subtract(rangeToMoveEnd);
					SourceMapEntryData right =
						new SourceMapEntryData(fileId, lineNum, rangeToMoveEnd.add(1), newLength);
					entriesToCreate.add(right);
					recIter.delete();
					continue;
				}

				if (isLessInSameSpace(recStart, fromAddr)) {
					// entry extends before left endpoint (but not past right)
					long newLength = fromAddr.subtract(recStart);
					SourceMapEntryData left =
						new SourceMapEntryData(fileId, lineNum, recStart, newLength);
					entriesToCreate.add(left);
					newLength = recEnd.subtract(fromAddr) + 1;
					SourceMapEntryData middle =
						new SourceMapEntryData(fileId, lineNum, fromAddr, newLength);
					entriesToCreate.add(middle);
					recIter.delete();
					continue;
				}

				if (isLessInSameSpace(rangeToMoveEnd, recEnd)) {
					// entry extends past right endpoint (but not before left)
					long newLength = rangeToMoveEnd.subtract(recStart) + 1;
					SourceMapEntryData middle =
						new SourceMapEntryData(fileId, lineNum, recStart, newLength);
					entriesToCreate.add(middle);
					newLength = recEnd.subtract(rangeToMoveEnd);
					SourceMapEntryData right =
						new SourceMapEntryData(fileId, lineNum, rangeToMoveEnd.add(1), newLength);
					entriesToCreate.add(right);
					recIter.delete();
					continue;
				}
				// entry is entirely within range to move, no adjustment needed
				mapChanged = true;

			}

			// add the new entries
			for (SourceMapEntryData data : entriesToCreate) {
				sourceMapTableAdapter.addMapEntry(data.sourceFileId, data.lineNumber,
					data.baseAddress, data.length);
			}

			mapChanged = mapChanged || !entriesToCreate.isEmpty();
			sourceMapTableAdapter.moveAddressRange(fromAddr, toAddr, length, monitor);

			if (mapChanged) {
				program.setChanged(ProgramEvent.SOURCE_MAP_CHANGED, null, null);
			}
		}
		catch (IOException e) {
			dbError(e);
		}
		finally {
			lock.release();
		}
	}
{@inheritDoc}<br>
Note: this method will move any source map entry which is entirely contained within the
source address range.  Entries which also contain addresses outside of this range will 
be split and parts within the range to move will be moved.
@param fromAddr first address of range to be moved
@param toAddr target address
@param length number of addresses to move
@param monitor task monitor
@throws AddressOverflowException if overflow occurs when computing new addresses
@throws CancelledException if {@code monitor} is cancelled
Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/sourcemap/SourceFileManagerDB.java