static int section_match(const struct pt_section *lhs, const struct pt_section *rhs) { const char *lfilename, *rfilename; if (!lhs || !rhs) return -pte_internal; if (pt_section_offset(lhs) != pt_section_offset(rhs)) return 0; if (pt_section_size(lhs) != pt_section_size(rhs)) return 0; lfilename = pt_section_filename(lhs); rfilename = pt_section_filename(rhs); if (!lfilename || !rfilename) return -pte_internal; if (strcmp(lfilename, rfilename) != 0) return 0; return 1; }
int pt_section_clone(struct pt_section **pclone, const struct pt_section *section, uint64_t offset, uint64_t size) { struct pt_section *clone; uint64_t begin, end, sbegin, send; if (!pclone || !section) return -pte_internal; begin = offset; end = begin + size; sbegin = pt_section_offset(section); send = sbegin + pt_section_size(section); if (begin < sbegin || send < end) return -pte_internal; clone = pt_mk_section(pt_section_filename(section), offset, size); if (!clone) return -pte_nomem; *pclone = clone; return 0; }
static struct ptunit_result size_null(void) { uint64_t size; size = pt_section_size(NULL); ptu_uint_eq(size, 0ull); return ptu_passed(); }
uint64_t pt_msec_end(const struct pt_mapped_section *msec) { uint64_t size; if (!msec) return 0ull; size = pt_section_size(msec->section); if (!size) return 0ull; return msec->vaddr + size; }
static int pt_iscache_find_locked(struct pt_image_section_cache *iscache, const char *filename, uint64_t offset, uint64_t size, uint64_t laddr) { uint16_t idx, end; if (!iscache || !filename) return -pte_internal; end = iscache->size; for (idx = 0; idx < end; ++idx) { const struct pt_iscache_entry *entry; const struct pt_section *section; const char *sec_filename; uint64_t sec_offset, sec_size; entry = &iscache->entries[idx]; /* We do not zero-initialize the array - a NULL check is * pointless. */ section = entry->section; sec_filename = pt_section_filename(section); sec_offset = pt_section_offset(section); sec_size = pt_section_size(section); if (entry->laddr != laddr) continue; if (sec_offset != offset) continue; if (sec_size != size) continue; /* We should not have a section without a filename. */ if (!sec_filename) return -pte_internal; if (strcmp(sec_filename, filename) != 0) continue; return isid_from_index(idx); } return 0; }
int pt_image_add(struct pt_image *image, struct pt_section *section, const struct pt_asid *asid, uint64_t vaddr) { struct pt_section_list **list, *next; uint64_t begin, end; int errcode; if (!image || !section) return -pte_internal; begin = vaddr; end = begin + pt_section_size(section); /* Check for overlaps while we move to the end of the list. */ for (list = &(image->sections); *list; list = &((*list)->next)) { const struct pt_mapped_section *msec; uint64_t lbegin, lend; msec = &(*list)->section; errcode = pt_msec_matches_asid(msec, asid); if (errcode < 0) return errcode; if (!errcode) continue; lbegin = pt_msec_begin(msec); lend = pt_msec_end(msec); if (end <= lbegin) continue; if (lend <= begin) continue; return -pte_bad_image; } next = pt_mk_section_list(section, asid, vaddr); if (!next) return -pte_nomap; *list = next; return 0; }
static struct ptunit_result create(struct section_fixture *sfix) { const char *name; uint8_t bytes[] = { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc }; uint64_t size; sfix_write(sfix, bytes); sfix->section = pt_mk_section(sfix->name, 0x1ull, 0x3ull); ptu_ptr(sfix->section); name = pt_section_filename(sfix->section); ptu_str_eq(name, sfix->name); size = pt_section_size(sfix->section); ptu_uint_eq(size, 0x3ull); return ptu_passed(); }
int pt_section_alloc_bcache(struct pt_section *section) { struct pt_image_section_cache *iscache; struct pt_block_cache *bcache; uint64_t ssize, memsize; uint32_t csize; int errcode; if (!section) return -pte_internal; if (!section->mcount) return -pte_internal; ssize = pt_section_size(section); csize = (uint32_t) ssize; if (csize != ssize) return -pte_not_supported; memsize = 0ull; /* We need to take both the attach and the section lock in order to pair * the block cache allocation and the resize notification. * * This allows map notifications in between but they only change the * order of sections in the cache. * * The attach lock needs to be taken first. */ errcode = pt_section_lock_attach(section); if (errcode < 0) return errcode; errcode = pt_section_lock(section); if (errcode < 0) goto out_alock; bcache = pt_section_bcache(section); if (bcache) { errcode = 0; goto out_lock; } bcache = pt_bcache_alloc(csize); if (!bcache) { errcode = -pte_nomem; goto out_lock; } /* Install the block cache. It will become visible and may be used * immediately. * * If we fail later on, we leave the block cache and report the error to * the allocating decoder thread. */ section->bcache = bcache; errcode = pt_section_memsize_locked(section, &memsize); if (errcode < 0) goto out_lock; errcode = pt_section_unlock(section); if (errcode < 0) goto out_alock; if (memsize) { iscache = section->iscache; if (iscache) { errcode = pt_iscache_notify_resize(iscache, section, memsize); if (errcode < 0) goto out_alock; } } return pt_section_unlock_attach(section); out_lock: (void) pt_section_unlock(section); out_alock: (void) pt_section_unlock_attach(section); return errcode; }
int pt_image_add(struct pt_image *image, struct pt_section *section, const struct pt_asid *asid, uint64_t vaddr, int isid) { struct pt_section_list **list, *next, *removed; uint64_t begin, end; int errcode; if (!image || !section) return -pte_internal; next = pt_mk_section_list(section, asid, vaddr, isid); if (!next) return -pte_nomem; removed = NULL; errcode = 0; begin = vaddr; end = begin + pt_section_size(section); /* Check for overlaps while we move to the end of the list. */ list = &(image->sections); while (*list) { const struct pt_mapped_section *msec; const struct pt_asid *masid; struct pt_section_list *current; struct pt_section *lsec; uint64_t lbegin, lend; current = *list; msec = ¤t->section; masid = pt_msec_asid(msec); errcode = pt_asid_match(masid, asid); if (errcode < 0) break; if (!errcode) { list = &((*list)->next); continue; } lbegin = pt_msec_begin(msec); lend = pt_msec_end(msec); if ((end <= lbegin) || (lend <= begin)) { list = &((*list)->next); continue; } /* The new section overlaps with @msec's section. */ lsec = pt_msec_section(msec); /* Let's check for an identical overlap that may be the result * of repeatedly copying images or repeatedly adding the same * file. */ if ((begin == lbegin) && (end == lend) && (isid == current->isid)) { const char *fname, *lfname; fname = pt_section_filename(section); lfname = pt_section_filename(lsec); if (!fname || !lfname) { errcode = -pte_internal; break; } if (strcmp(fname, lfname) == 0) { /* There should not have been any removals or * additions. */ if (removed || next->next) { errcode = -pte_internal; break; } pt_section_list_free(next); return 0; } } /* We remove @msec and insert new sections for the remaining * parts, if any. Those new sections are not mapped initially * and need to be added to the end of the section list. */ *list = current->next; /* Keep a list of removed sections so we can re-add them in case * of errors. */ current->next = removed; removed = current; /* Unmap the removed section. If we need to re-add it, it will * be moved to the end of the section list where the unmapped * sections are. */ if (current->mapped) { pt_section_unmap(lsec); current->mapped = 0; } /* Add a section covering the remaining bytes at the front. * * We preserve the section identifier to indicate that the new * section originated from the original section. */ if (lbegin < begin) { errcode = pt_image_clone(&next, msec, lbegin, begin, current->isid); if (errcode < 0) break; } /* Add a section covering the remaining bytes at the back. * * We preserve the section identifier to indicate that the new * section originated from the original section. */ if (end < lend) { errcode = pt_image_clone(&next, msec, end, lend, current->isid); if (errcode < 0) break; } } if (errcode < 0) { pt_section_list_free_tail(next); /* Re-add removed sections to the tail of the section list. */ for (; *list; list = &((*list)->next)) ; *list = removed; return errcode; } pt_section_list_free_tail(removed); *list = next; return 0; }