3 #include "rose_getline.h"
15 inline void * mmap(
void*,
size_t length,
int,
int,
int, off_t)
17 return new char[length];
19 inline void munmap(
void* p_data,
size_t)
21 delete [] (
char *)p_data;
24 #undef TEMP_FAILURE_RETRY
25 #define TEMP_FAILURE_RETRY(expression) expression
26 #define PROT_WRITE 0x02
45 const char *s = what();
46 return s && *s ? dflt : std::string(s);
52 std::ostringstream ss;
64 o <<leader(
"problem") <<details(verbose);
70 o <<leader(
"inconsistent mapping") <<
" for " <<new_range <<
" vs. " <<old_range <<details(verbose);
83 o <<leader(
"no free space") <<
" (nbytes=" <<
size <<
")" <<details(verbose);
89 o <<leader(
"syntax error");
90 if (!filename.empty()) {
91 o <<
" at " <<filename <<
":" <<linenum;
106 static size_t ncalls = 0;
108 retval +=
'a' + (ncalls/(26*26))%26;
109 retval +=
'a' + (ncalls/26)%26;
110 retval +=
'a' + (ncalls%26);
118 std::ofstream file(filename.c_str(), std::ofstream::binary);
124 size_t n =
read(buf, offset,
sizeof buf);
126 if (file.bad() || n<
sizeof buf)
137 size_t n = std::min(
size()-at,
sizeof buf);
138 size_t nread =
read(buf, at, n);
141 for (
size_t i=0; i<nread; ++i) {
173 uint8_t *d =
new uint8_t[
size()];
174 memcpy(d, p_data,
size());
181 assert(!
"not implemented");
188 if (!p_data || offset>=
size())
190 size_t n = std::min(nbytes,
size()-offset);
192 memcpy(buf, (uint8_t*)p_data+offset, n);
199 if (!p_data || is_read_only() || offset>=
size())
201 size_t n = std::min(nbytes,
size()-offset);
203 memcpy((uint8_t*)p_data+offset, buf, n);
217 int fd = open(filename.c_str(), O_RDONLY);
221 if (fstat(fd, &sb)<0) {
225 off_t position = lseek(fd, offset, SEEK_SET);
226 if (-1==position || (
rose_addr_t)position!=offset) {
232 rose_addr_t size = offset > (size_t)sb.st_size ? 0 : sb.st_size-offset;
233 uint8_t *data =
new uint8_t[size];
235 if (-1==n || n!=sb.st_size) {
243 return create(data, size);
267 size_t n = std::min(nbytes,
size()-offset);
270 memcpy(buf, (uint8_t*)p_data+offset, n);
283 size_t n = std::min(nbytes,
size()-offset);
286 bool all_zero =
true;
287 for (
size_t i=0; i<n && all_zero; ++i)
288 all_zero = ((uint8_t*)buf)[i] ==
'\0';
291 p_data =
new uint8_t[
size()];
292 memset(p_data, 0,
size());
294 memcpy((uint8_t*)p_data+offset, buf, n);
303 p_data =
new uint8_t[
size()];
304 memset(p_data, 0,
size());
318 int fd = open(filename.c_str(), oflags, 0666);
320 throw Exception(filename +
": " + strerror(errno), NULL);
322 int status = fstat(fd, &sb);
324 throw Exception(filename +
": " + strerror(errno), NULL);
327 buffer = create(sb.st_size, mprot, mflags, fd, 0);
339 void *buf = mmap(NULL, length, prot, flags, fd, 0);
348 munmap(p_data, p_size);
356 assert(!
"cannot resize");
372 if (!get_buffer() || 0==get_buffer()->size() || get_buffer_offset() >= get_buffer()->size()) {
374 *first_bad_va = range.
first();
377 if (get_buffer_offset() + range.
size() > get_buffer()->size()) {
379 *first_bad_va = range.
first() + (get_buffer()->size() - get_buffer_offset());
390 return get_buffer_offset() + va - my_range.
first();
396 assert(!buffer || n<buffer->
size());
403 assert(pairings!=NULL);
405 std::string::size_type i = 0;
406 while (i<
name.size()) {
408 while (i<
name.size() && isspace(
name[i])) i++;
409 std::string::size_type fname_start = i;
410 while (i<
name.size() && !isspace(
name[i]) && !strchr(
"()+",
name[i])) i++;
411 if (i>=
name.size() ||
'('!=
name[i] || fname_start==i) {
412 retval +=
name.substr(fname_start, i-fname_start);
415 std::string fname =
name.substr(fname_start, i-fname_start);
420 while (i<
name.size() &&
')'!=
name[i]) {
421 while (i<
name.size() && isspace(
name[i])) i++;
422 std::string::size_type gname_start = i;
423 while (i<
name.size() &&
'+'!=
name[i] && (parens>0 ||
')'!=
name[i])) {
426 }
else if (
')'==
name[i]) {
432 (*pairings)[fname].insert(
name.substr(gname_start, i-gname_start));
433 if (i<
name.size() &&
'+'==
name[i]) i++;
437 if (i<
name.size() &&
')'==
name[i]) i++;
438 while (i<
name.size() && isspace(
name[i])) i++;
439 if (i<
name.size() &&
'+'==
name[i]) i++;
442 retval +=
name.substr(i);
450 for (NamePairings::const_iterator pi=pairings.begin(); pi!=pairings.end(); ++pi) {
451 s += (s.empty()?
"":
"+") + pi->first +
"(";
452 for (std::set<std::string>::const_iterator si=pi->second.begin(); si!=pi->second.end(); ++si) {
453 if (
'('!=s[s.size()-1]) s +=
"+";
459 s += (s.empty()?
"":
"+") + s1;
461 s += (s.empty()?
"":
"+") + s2;
474 std::string s1 = get_name_pairings(&pairings);
484 assert(!my_range.
empty());
491 assert(new_end>my_range.
first() && new_end<=my_range.
last());
498 assert(!my_range.
empty() && !other_range.
empty());
500 #if 1 // Relaxed version: segments are compatible if they point to the same underlying "char*" buffer
501 if (get_buffer()==NULL || other.
get_buffer()==NULL)
503 if (get_buffer()->get_data_ptr()==NULL ||
504 get_buffer()->get_data_ptr()!=other.
get_buffer()->get_data_ptr())
506 #else // Strict version: compatible only if segments point to the same MemoryMap::Buffer (this is what we eventually want)
513 if (other_range.
abuts_lt(my_range)) {
518 assert(other_range.
abuts_gt(my_range));
547 std::string bufname = buffer->get_name();
548 if (bufname.find_first_of(
" \t\n()")==std::string::npos)
549 bufname =
"buffer " + bufname;
555 <<
" at " <<(bufname+std::string(12,
' ')).substr(0, 12)
559 static const size_t limit = 55;
561 if (name.size()>limit)
562 name = name.substr(0, limit-3) +
"...";
583 switch (copy_level) {
589 si->second.clear_cow();
590 si->second.set_buffer(si->second.get_buffer()->clone());
595 si->second.set_cow();
606 retval += si->first.size();
619 assert(range.
overlaps(found->first));
620 throw Inconsistent(
"insertion failed",
this, range, segment, found->first, found->second);
627 int o_flags = writable ? O_RDWR : O_RDONLY;
628 int m_prot = writable ? (PROT_READ|PROT_WRITE) : PROT_READ;
629 int m_flags = writable ? MAP_SHARED : MAP_PRIVATE;
632 int fd = open(filename.c_str(), o_flags);
634 throw Exception(filename +
": " + strerror(errno), NULL);
636 if (-1==fstat(fd, &sb))
637 throw Exception(filename +
" stat: " + strerror(errno), NULL);
641 Extent extent(va, sb.st_size);
643 insert(extent,
Segment(buf, 0, s_prot, sgmtname.empty()?filename:sgmtname), erase_prior);
652 if (0==required_perms)
655 while (!range.
empty()) {
659 const Segment &found_segment = found->second;
661 if ((found_segment.
get_mapperms() & required_perms) != required_perms)
663 if (found_range.last() >= range.
last())
680 if (segment==si->second) {
687 std::pair<Extent, MemoryMap::Segment>
701 while ((fmi=free_map.
first_fit(size, fmi)) != free_map.
end()) {
709 throw NoFreeSpace(
"find_free() failed",
this, size);
717 if (fmi==free_map.
end())
718 throw NoFreeSpace(
"find_last_free() failed",
this, 1);
719 return fmi->first.first();
726 (
void) visitor(
this, si->first, si->second);
734 if (predicate(
this, si->first, si->second))
735 matches.
insert(si->first);
746 unsigned required, prohibited;
747 T1(
unsigned required,
unsigned prohibited): required(required), prohibited(prohibited) {}
749 return ((0!=required && 0==(segment.
get_mapperms() & required)) ||
752 } predicate(required, prohibited);
773 return segment.
get_buffer()->read(dst_buf, buffer_offset, desired);
779 size_t total_copied = 0;
780 while (total_copied < desired) {
781 uint8_t *ptr = dst_buf ? (uint8_t*)dst_buf + total_copied : NULL;
782 size_t n =
read1(ptr, start_va+total_copied, desired-total_copied, req_perms);
786 memset((uint8_t*)dst_buf+total_copied, 0, desired-total_copied);
795 size_t can_read =
read1(NULL, va, desired, req_perms);
798 size_t n = retval.size();
799 retval.resize(retval.size()+can_read);
800 size_t did_read =
read1(&retval[n], va, desired, req_perms);
801 assert(did_read==can_read);
814 unsigned char buf[4096];
815 size_t nread =
read1(buf, va, desired, req_perms);
818 for (
size_t i=0; i<nread; ++i) {
819 if (buf[i]==
'\0' || (NULL!=valid_char && !valid_char(buf[i])) || (NULL!=invalid_char && invalid_char(buf[i])))
840 if ((segment.get_mapperms() & req_perms) != req_perms || !segment.check(range))
843 if (segment.is_cow()) {
844 BufferPtr old_buf = segment.get_buffer();
847 if (si->second.get_buffer()==old_buf) {
848 si->second.set_buffer(new_buf);
849 si->second.clear_cow();
852 assert(segment.get_buffer()==new_buf);
853 assert(!segment.is_cow());
856 rose_addr_t buffer_offset = segment.get_buffer_offset(range, start_va);
857 return segment.get_buffer()->write(src_buf, buffer_offset, desired);
863 size_t total_copied = 0;
864 while (total_copied < desired) {
865 uint8_t *ptr = src_buf ? (uint8_t*)src_buf + total_copied : NULL;
866 size_t n =
write1(ptr, start_va+total_copied, desired-total_copied, req_perms);
883 while (!range.
empty() && !done) {
887 if (found==
p_segments.
end() || found->first.right_of(range)) {
892 if (found->first.begins_after(range)) {
895 range =
Extent::inin(found->first.first(), range.last());
900 done = segment_range.
last() >= range.
last();
902 if (found->second.get_mapperms()!=perms) {
903 if (range.
contains(segment_range)) {
932 if (buffer->is_zero()) {
935 for (
size_t i=0; i<extent.
size(); ) {
937 size_t nread =
read(page, extent.
first()+i,
sizeof page);
940 for (
size_t j=0; j<nread; ) {
943 while (j+k<nread && 0==page[j+k]) ++k;
962 std::ostringstream ss;
964 fputs(ss.str().c_str(), f);
971 out <<prefix <<
"empty\n";
980 std::string basename = segment.
get_buffer()->get_name();
994 std::ofstream index((basename+
".index").c_str());
1010 std::string indexname = basename +
".index";
1011 FILE *f = fopen(indexname.c_str(),
"r");
1012 if (!f)
return false;
1015 size_t line_nalloc = 0;
1018 std::map<std::string, BufferPtr> buffers;
1020 while (0<(nread=rose_getline(&line, &line_nalloc, f))) {
1021 char *rest, *s=line;
1025 while (isspace(*s)) s++;
1026 if (!*s ||
'#'==*s)
continue;
1029 if (!strncmp(s,
"va ", 3)) s += 3;
1035 ROSE_ASSERT(!
"lacking Windows support");
1037 if (rest==s || errno)
1038 throw SyntaxError(
"starting virtual address expected",
this, indexname, nlines, s-line);
1042 while (isspace(*s)) s++;
1043 if (
'+'==*s ||
','==*s) s++;
1044 while (isspace(*s)) s++;
1050 ROSE_ASSERT(!
"lacking Windows support");
1052 if (rest==s || errno)
1053 throw SyntaxError(
"virtual size expected",
this, indexname, nlines, s-line);
1057 while (isspace(*s)) s++;
1062 (void)strtoull(s, &rest, 0);
1064 ROSE_ASSERT(!
"lacking Windows support");
1066 if (rest==s || errno)
1067 throw SyntaxError(
"ending virtual address expected after '='",
this, indexname, nlines, s-line);
1073 while (isspace(*s)) s++;
1075 while (isspace(*s)) s++;
1077 while (strchr(
"rwxp-", *s)) {
1089 while (isspace(*s)) s++;
1091 while (isspace(*s)) s++;
1092 if (!strncmp(s,
"at", 2) && isspace(s[2])) s+= 3;
1093 while (isspace(*s)) s++;
1094 int buffer_name_col = s-line;
1095 std::string buffer_name;
1096 while (*s &&
','!=*s && 0!=strncmp(s,
"0x", 2))
1097 buffer_name += *s++;
1098 size_t bnsz = buffer_name.size();
1099 while (bnsz>0 && isspace(buffer_name[bnsz-1])) --bnsz;
1100 buffer_name = buffer_name.substr(0, bnsz);
1101 if (buffer_name.empty())
1102 throw SyntaxError(
"file/buffer name expected",
this, indexname, nlines, buffer_name_col);
1105 while (isspace(*s)) s++;
1106 if (
','==*s ||
'+'==*s) s++;
1107 while (isspace(*s)) s++;
1113 ROSE_ASSERT(!
"lacking Windows support");
1115 if (rest==s || errno)
1116 throw SyntaxError(
"file/buffer offset expected",
this, indexname, nlines, s-line);
1120 while (isspace(*s)) s++;
1122 while (isspace(*s)) s++;
1123 char *end = s + strlen(s);
1124 while (end>s && isspace(end[-1])) --end;
1125 std::string comment(s, end-s);
1129 std::map<std::string, BufferPtr>::iterator bi = buffers.find(buffer_name);
1131 buffer = bi->second;
1132 }
else if (0==access(buffer_name.c_str(), F_OK)) {
1134 buffers.insert(std::make_pair(buffer_name, buffer));
1136 ROSE_ASSERT(!
"not implemented yet");
1139 Extent range(segment_va, segment_sz);
1145 if (line) free(line);