docs: def remove_cgc_attachments(self):
          """
          Remove CGC attachments.
  
          :return: True if CGC attachments are found and removed, False otherwise
          :rtype: bool
          """
  
          cgc_package_list = None
          cgc_extended_application = None
  
          for data in self.data:
              if data.sort == 'cgc-package-list':
                  cgc_package_list = data
              elif data.sort == 'cgc-extended-application':
                  cgc_extended_application = data
  
          if not cgc_package_list or not cgc_extended_application:
              return False
  
          if cgc_package_list.skip or cgc_extended_application.skip:
              # they have already been removed
              # so we still return True to indicate that CGC attachments have been removed
              return True
  
          # there is a single function referencing them
          cgcpl_memory_data = self.cfg.memory_data.get(cgc_package_list.addr, None)
          cgcea_memory_data = self.cfg.memory_data.get(cgc_extended_application.addr, None)
          refs = self.cfg.model.references
  
          if cgcpl_memory_data is None or cgcea_memory_data is None:
              return False
  
          if len(refs.data_addr_to_ref[cgcpl_memory_data.addr]) != 1:
              return False
          if len(refs.data_addr_to_ref[cgcea_memory_data.addr]) != 1:
              return False
  
          # check if the irsb addresses are the same
          if next(iter(refs.data_addr_to_ref[cgcpl_memory_data.addr])).block_addr != \
                  next(iter(refs.data_addr_to_ref[cgcea_memory_data.addr])).block_addr:
              return False
  
          insn_addr = next(iter(refs.data_addr_to_ref[cgcpl_memory_data.addr])).insn_addr
          # get the basic block
          cfg_node = self.cfg.get_any_node(insn_addr, anyaddr=True)
          if not cfg_node:
              return False
  
          func_addr = cfg_node.function_address
  
          # this function should be calling another function
          sub_func_addr = None
          if func_addr not in self.cfg.functions:
              return False
          function = self.cfg.functions[func_addr]
          # traverse the graph and make sure there is only one call edge
          calling_targets = [ ]
          for _, dst, data in function.transition_graph.edges(data=True):
              if 'type' in data and data['type'] == 'call':
                  calling_targets.append(dst.addr)
  
          if len(calling_targets) != 1:
              return False
  
          sub_func_addr = calling_targets[0]
  
          # alright. We want to nop this function, as well as the subfunction
          proc = next((p for p in self.procedures if p.addr == func_addr), None)
          if proc is None:
              return False
  
          subproc = next((p for p in self.procedures if p.addr == sub_func_addr), None)
          if subproc is None:
              return False
  
          # if those two data entries have any label, we should properly modify them
          # at this point, we are fairly confident that none of those labels are direct data references to either package
          # list or extended application
          has_label = True
          lowest_address = min(cgc_package_list.addr, cgc_extended_application.addr)
          for obj in (cgc_package_list, cgc_extended_application):
              labels = obj.labels
              for addr, label in labels:
                  if addr != lowest_address:
                      label.base_addr = lowest_address
  
          if has_label:
              # is there any memory data entry that ends right at the lowest address?
              data = next((d for d in self.data if d.addr is not None and d.addr + d.size == lowest_address), None)
              if data is None:
                  # since there is no gap between memory data entries (we guarantee that), this can only be that no other
                  # data resides in the same memory region that CGC attachments are in
                  pass
              else:
                  lbl = self.symbol_manager.addr_to_label[lowest_address][0]
                  if lbl not in data.end_labels:
                      data.end_labels.append(lbl)
  
          # practically nop the function
          proc.asm_code = "\tret\n"
          subproc.asm_code = "\tret\n"
  
          # remove those two data entries
          cgc_package_list.skip = True
          cgc_extended_application.skip = True
  
          l.info('CGC attachments are removed.')
  
          return True