/*inline*/ Bool Seg__is_freed(Seg* seg) { if (!is_known_segment(seg)) return False; else return seg->nextfree != (Seg*)1; }
void pc_pp_Error ( Error* err ) { const Bool xml = VG_(clo_xml); /* a shorthand, that's all */ XError *xe = (XError*)VG_(get_error_extra)(err); tl_assert(xe); switch (VG_(get_error_kind)(err)) { //---------------------------------------------------------- case XE_SorG: if (xml) { emit( " <kind>SorG</kind>\n"); emit( " <what>Invalid %s of size %ld</what>\n", xe->XE.SorG.sszB < 0 ? "write" : "read", Word__abs(xe->XE.SorG.sszB) ); VG_(pp_ExeContext)( VG_(get_error_where)(err) ); emit( " <auxwhat>Address %#lx expected vs actual:</auxwhat>\n", xe->XE.SorG.addr ); emiN( " <auxwhat>Expected: %t</auxwhat>\n", &xe->XE.SorG.expect[0] ); emiN( " <auxwhat>Actual: %t</auxwhat>\n", &xe->XE.SorG.actual[0] ); } else { emit( "Invalid %s of size %ld\n", xe->XE.SorG.sszB < 0 ? "write" : "read", Word__abs(xe->XE.SorG.sszB) ); VG_(pp_ExeContext)( VG_(get_error_where)(err) ); emit( " Address %#lx expected vs actual:\n", xe->XE.SorG.addr ); emit( " Expected: %s\n", &xe->XE.SorG.expect[0] ); emit( " Actual: %s\n", &xe->XE.SorG.actual[0] ); } break; //---------------------------------------------------------- case XE_Heap: { Char *place, *legit, *how_invalid; Addr a = xe->XE.Heap.addr; Seg* vseg = xe->XE.Heap.vseg; tl_assert(is_known_segment(vseg) || NONPTR == vseg); if (NONPTR == vseg) { // Access via a non-pointer if (xml) { emit( " <kind>Heap</kind>\n"); emit( " <what>Invalid %s of size %ld</what>\n", readwrite(xe->XE.Heap.sszB), Word__abs(xe->XE.Heap.sszB) ); VG_(pp_ExeContext)( VG_(get_error_where)(err) ); emit( " <auxwhat>Address %#lx is not derived from " "any known block</auxwhat>\n", a ); } else { emit( "Invalid %s of size %ld\n", readwrite(xe->XE.Heap.sszB), Word__abs(xe->XE.Heap.sszB) ); VG_(pp_ExeContext)( VG_(get_error_where)(err) ); emit( " Address %#lx is not derived from " "any known block\n", a ); } } else { // Access via a pointer, but outside its range. Int cmp; UWord miss_size; Seg__cmp(vseg, a, &cmp, &miss_size); if (cmp < 0) place = "before"; else if (cmp == 0) place = "inside"; else place = "after"; how_invalid = ( ( Seg__is_freed(vseg) && 0 != cmp ) ? "Doubly-invalid" : "Invalid" ); legit = ( Seg__is_freed(vseg) ? "once-" : "" ); if (xml) { emit( " <kind>Heap</kind>\n"); emit( " <what>%s %s of size %ld</what>\n", how_invalid, readwrite(xe->XE.Heap.sszB), Word__abs(xe->XE.Heap.sszB) ); VG_(pp_ExeContext)( VG_(get_error_where)(err) ); emit( " <auxwhat>Address %#lx is %lu bytes %s " "the accessing pointer's</auxwhat>\n", a, miss_size, place ); emit( " <auxwhat>%slegitimate range, " "a block of size %lu %s</auxwhat>\n", legit, Seg__size(vseg), Seg__is_freed(vseg) ? "free'd" : "alloc'd" ); VG_(pp_ExeContext)(Seg__where(vseg)); } else { emit( "%s %s of size %ld\n", how_invalid, readwrite(xe->XE.Heap.sszB), Word__abs(xe->XE.Heap.sszB) ); VG_(pp_ExeContext)( VG_(get_error_where)(err) ); emit( " Address %#lx is %lu bytes %s the accessing pointer's\n", a, miss_size, place ); emit( " %slegitimate range, a block of size %lu %s\n", legit, Seg__size(vseg), Seg__is_freed(vseg) ? "free'd" : "alloc'd" ); VG_(pp_ExeContext)(Seg__where(vseg)); } } /* If we have a better description of the address, show it. Note that in XML mode, it will already by nicely wrapped up in tags, either <auxwhat> or <xauxwhat>, so we can just emit it verbatim. */ if (xml) { if (xe->XE.Heap.descr1) emiN( " %t\n", (HChar*)VG_(indexXA)( xe->XE.Heap.descr1, 0 ) ); if (xe->XE.Heap.descr2) emiN( " %t\n", (HChar*)VG_(indexXA)( xe->XE.Heap.descr2, 0 ) ); if (xe->XE.Heap.datasym[0] != 0) emiN( " <auxwhat>Address 0x%llx is %llu bytes " "inside data symbol \"%t\"</auxwhat>\n", (ULong)xe->XE.Heap.addr, (ULong)xe->XE.Heap.datasymoff, xe->XE.Heap.datasym ); } else { if (xe->XE.Heap.descr1) emit( " %s\n", (HChar*)VG_(indexXA)( xe->XE.Heap.descr1, 0 ) ); if (xe->XE.Heap.descr2) emit( " %s\n", (HChar*)VG_(indexXA)( xe->XE.Heap.descr2, 0 ) ); if (xe->XE.Heap.datasym[0] != 0) emit( " Address 0x%llx is %llu bytes " "inside data symbol \"%s\"\n", (ULong)xe->XE.Heap.addr, (ULong)xe->XE.Heap.datasymoff, xe->XE.Heap.datasym ); } break; } //---------------------------------------------------------- case XE_Arith: { Seg* seg1 = xe->XE.Arith.seg1; Seg* seg2 = xe->XE.Arith.seg2; Char* which; tl_assert(BOTTOM != seg1); tl_assert(BOTTOM != seg2 && UNKNOWN != seg2); if (xml) { emit( " <kind>Arith</kind>\n"); emit( " <what>Invalid arguments to %s</what>\n", xe->XE.Arith.opname ); VG_(pp_ExeContext)( VG_(get_error_where)(err) ); if (seg1 != seg2) { if (NONPTR == seg1) { emit( " <auxwhat>First arg not a pointer</auxwhat>\n" ); } else if (UNKNOWN == seg1) { emit( " <auxwhat>First arg may be a pointer</auxwhat>\n" ); } else { emit( " <auxwhat>First arg derived from address %#lx of " "%lu-byte block alloc'd</auxwhat>\n", Seg__addr(seg1), Seg__size(seg1) ); VG_(pp_ExeContext)(Seg__where(seg1)); } which = "Second arg"; } else { which = "Both args"; } if (NONPTR == seg2) { emit( " <auxwhat>%s not a pointer</auxwhat>\n", which ); } else { emit( " <auxwhat>%s derived from address %#lx of " "%lu-byte block alloc'd</auxwhat>\n", which, Seg__addr(seg2), Seg__size(seg2) ); VG_(pp_ExeContext)(Seg__where(seg2)); } } else { emit( "Invalid arguments to %s\n", xe->XE.Arith.opname ); VG_(pp_ExeContext)( VG_(get_error_where)(err) ); if (seg1 != seg2) { if (NONPTR == seg1) { emit( " First arg not a pointer\n" ); } else if (UNKNOWN == seg1) { emit( " First arg may be a pointer\n" ); } else { emit( " First arg derived from address %#lx of " "%lu-byte block alloc'd\n", Seg__addr(seg1), Seg__size(seg1) ); VG_(pp_ExeContext)(Seg__where(seg1)); } which = "Second arg"; } else { which = "Both args"; } if (NONPTR == seg2) { emit( " %s not a pointer\n", which ); } else { emit( " %s derived from address %#lx of " "%lu-byte block alloc'd\n", which, Seg__addr(seg2), Seg__size(seg2) ); VG_(pp_ExeContext)(Seg__where(seg2)); } } break; } //---------------------------------------------------------- case XE_SysParam: { Addr lo = xe->XE.SysParam.lo; Addr hi = xe->XE.SysParam.hi; Seg* seglo = xe->XE.SysParam.seglo; Seg* seghi = xe->XE.SysParam.seghi; Char* s = VG_(get_error_string) (err); Char* what; tl_assert(BOTTOM != seglo && BOTTOM != seghi); if (Vg_CoreSysCall == xe->XE.SysParam.part) what = "Syscall param "; else VG_(tool_panic)("bad CorePart"); if (seglo == seghi) { // freed block tl_assert(is_known_segment(seglo)); tl_assert(Seg__is_freed(seglo)); // XXX what if it's now recycled? if (xml) { emit( " <kind>SysParam</kind>\n"); emit( " <what>%s%s contains unaddressable byte(s)</what>\n", what, s ); VG_(pp_ExeContext)( VG_(get_error_where)(err) ); emit( " <auxwhat>Address %#lx is %ld bytes inside a " "%ld-byte block free'd</auxwhat>\n", lo, lo-Seg__addr(seglo), Seg__size(seglo) ); VG_(pp_ExeContext)(Seg__where(seglo)); } else { emit( " %s%s contains unaddressable byte(s)\n", what, s ); VG_(pp_ExeContext)( VG_(get_error_where)(err) ); emit( " Address %#lx is %ld bytes inside a " "%ld-byte block free'd\n", lo, lo-Seg__addr(seglo), Seg__size(seglo) ); VG_(pp_ExeContext)(Seg__where(seglo)); } } else { // mismatch if (xml) { emit( " <kind>SysParam</kind>\n"); emit( " <what>%s%s is non-contiguous</what>\n", what, s ); VG_(pp_ExeContext)( VG_(get_error_where)(err) ); if (UNKNOWN == seglo) { emit( " <auxwhat>First byte is " "not inside a known block</auxwhat>\n" ); } else { emit( " <auxwhat>First byte (%#lx) is %ld bytes inside a " "%ld-byte block alloc'd</auxwhat>\n", lo, lo-Seg__addr(seglo), Seg__size(seglo) ); VG_(pp_ExeContext)(Seg__where(seglo)); } if (UNKNOWN == seghi) { emit( " <auxwhat>Last byte is " "not inside a known block</auxwhat>\n" ); } else { emit( " <auxwhat>Last byte (%#lx) is %ld bytes inside a " "%ld-byte block alloc'd</auxwhat>\n", hi, hi-Seg__addr(seghi), Seg__size(seghi) ); VG_(pp_ExeContext)(Seg__where(seghi)); } } else { emit( "%s%s is non-contiguous\n", what, s ); VG_(pp_ExeContext)( VG_(get_error_where)(err) ); if (UNKNOWN == seglo) { emit( " First byte is not inside a known block\n" ); } else { emit( " First byte (%#lx) is %ld bytes inside a " "%ld-byte block alloc'd\n", lo, lo-Seg__addr(seglo), Seg__size(seglo) ); VG_(pp_ExeContext)(Seg__where(seglo)); } if (UNKNOWN == seghi) { emit( " Last byte is not inside a known block\n" ); } else { emit( " Last byte (%#lx) is %ld bytes inside a " "%ld-byte block alloc'd\n", hi, hi-Seg__addr(seghi), Seg__size(seghi) ); VG_(pp_ExeContext)(Seg__where(seghi)); } } } break; } default: VG_(tool_panic)("pp_Error: unrecognised error kind"); } }
Addr Seg__addr(Seg* seg) { tl_assert(is_known_segment(seg)); return seg->addr; }
SizeT Seg__size(Seg* seg) { tl_assert(is_known_segment(seg)); return seg->szB; }
ExeContext* Seg__where(Seg* seg) { tl_assert(is_known_segment(seg)); return seg->ec; }
void pc_pp_Error ( Error* err ) { XError *xe = (XError*)VG_(get_error_extra)(err); tl_assert(xe); switch (VG_(get_error_kind)(err)) { //---------------------------------------------------------- case XE_SorG: tl_assert(xe); VG_(message)(Vg_UserMsg, "Invalid %s of size %ld", xe->XE.SorG.sszB < 0 ? "write" : "read", Word__abs(xe->XE.SorG.sszB) ); VG_(pp_ExeContext)( VG_(get_error_where)(err) ); VG_(message)(Vg_UserMsg, " Address %#lx expected vs actual:", xe->XE.SorG.addr); VG_(message)(Vg_UserMsg, " Expected: %s", &xe->XE.SorG.expect[0] ); VG_(message)(Vg_UserMsg, " Actual: %s", &xe->XE.SorG.actual[0] ); break; //---------------------------------------------------------- case XE_Heap: { Char *place, *legit, *how_invalid; Addr a = xe->XE.Heap.addr; Seg* vseg = xe->XE.Heap.vseg; tl_assert(is_known_segment(vseg) || NONPTR == vseg); if (NONPTR == vseg) { // Access via a non-pointer VG_(message)(Vg_UserMsg, "Invalid %s of size %ld", readwrite(xe->XE.Heap.sszB), Word__abs(xe->XE.Heap.sszB)); VG_(pp_ExeContext)( VG_(get_error_where)(err) ); VG_(message)(Vg_UserMsg, " Address %#lx is not derived from any known block", a); } else { // Access via a pointer, but outside its range. Int cmp; UWord miss_size; Seg__cmp(vseg, a, &cmp, &miss_size); if (cmp < 0) place = "before"; else if (cmp == 0) place = "inside"; else place = "after"; how_invalid = ( ( Seg__is_freed(vseg) && 0 != cmp ) ? "Doubly-invalid" : "Invalid" ); legit = ( Seg__is_freed(vseg) ? "once-" : "" ); VG_(message)(Vg_UserMsg, "%s %s of size %ld", how_invalid, readwrite(xe->XE.Heap.sszB), Word__abs(xe->XE.Heap.sszB)); VG_(pp_ExeContext)( VG_(get_error_where)(err) ); VG_(message)(Vg_UserMsg, " Address %#lx is %lu bytes %s the accessing pointer's", a, miss_size, place); VG_(message)(Vg_UserMsg, " %slegitimate range, a block of size %lu %s", legit, Seg__size(vseg), Seg__is_freed(vseg) ? "free'd" : "alloc'd" ); VG_(pp_ExeContext)(Seg__where(vseg)); } if (xe->XE.Heap.descr1[0] != 0) VG_(message)(Vg_UserMsg, " %s", xe->XE.Heap.descr1); if (xe->XE.Heap.descr2[0] != 0) VG_(message)(Vg_UserMsg, " %s", xe->XE.Heap.descr2); if (xe->XE.Heap.datasym[0] != 0) VG_(message)(Vg_UserMsg, " Address 0x%llx is %llu bytes " "inside data symbol \"%s\"", (ULong)xe->XE.Heap.addr, (ULong)xe->XE.Heap.datasymoff, xe->XE.Heap.datasym); break; } //---------------------------------------------------------- case XE_Arith: { Seg* seg1 = xe->XE.Arith.seg1; Seg* seg2 = xe->XE.Arith.seg2; Char* which; tl_assert(BOTTOM != seg1); tl_assert(BOTTOM != seg2 && UNKNOWN != seg2); VG_(message)(Vg_UserMsg, "Invalid arguments to %s", xe->XE.Arith.opname); VG_(pp_ExeContext)( VG_(get_error_where)(err) ); if (seg1 != seg2) { if (NONPTR == seg1) { VG_(message)(Vg_UserMsg, " First arg not a pointer"); } else if (UNKNOWN == seg1) { VG_(message)(Vg_UserMsg, " First arg may be a pointer"); } else { VG_(message)(Vg_UserMsg, " First arg derived from address %#lx of " "%lu-byte block alloc'd", Seg__addr(seg1), Seg__size(seg1) ); VG_(pp_ExeContext)(Seg__where(seg1)); } which = "Second arg"; } else { which = "Both args"; } if (NONPTR == seg2) { VG_(message)(Vg_UserMsg, " %s not a pointer", which); } else { VG_(message)(Vg_UserMsg, " %s derived from address %#lx of " "%lu-byte block alloc'd", which, Seg__addr(seg2), Seg__size(seg2) ); VG_(pp_ExeContext)(Seg__where(seg2)); } break; } //---------------------------------------------------------- case XE_SysParam: { Addr lo = xe->XE.SysParam.lo; Addr hi = xe->XE.SysParam.hi; Seg* seglo = xe->XE.SysParam.seglo; Seg* seghi = xe->XE.SysParam.seghi; Char* s = VG_(get_error_string) (err); Char* what; tl_assert(BOTTOM != seglo && BOTTOM != seghi); if (Vg_CoreSysCall == xe->XE.SysParam.part) what = "Syscall param "; else VG_(tool_panic)("bad CorePart"); if (seglo == seghi) { // freed block tl_assert(is_known_segment(seglo)); tl_assert(Seg__is_freed(seglo)); // XXX what if it's now recycled? VG_(message)(Vg_UserMsg, "%s%s contains unaddressable byte(s)", what, s); VG_(pp_ExeContext)( VG_(get_error_where)(err) ); VG_(message)(Vg_UserMsg, " Address %#lx is %ld bytes inside a " "%ld-byte block free'd", lo, lo-Seg__addr(seglo), Seg__size(seglo) ); VG_(pp_ExeContext)(Seg__where(seglo)); } else { // mismatch VG_(message)(Vg_UserMsg, "%s%s is non-contiguous", what, s); VG_(pp_ExeContext)( VG_(get_error_where)(err) ); if (UNKNOWN == seglo) { VG_(message)(Vg_UserMsg, " First byte is not inside a known block"); } else { VG_(message)(Vg_UserMsg, " First byte (%#lx) is %ld bytes inside a " "%ld-byte block alloc'd", lo, lo-Seg__addr(seglo), Seg__size(seglo) ); VG_(pp_ExeContext)(Seg__where(seglo)); } if (UNKNOWN == seghi) { VG_(message)(Vg_UserMsg, " Last byte is not inside a known block"); } else { VG_(message)(Vg_UserMsg, " Last byte (%#lx) is %ld bytes inside a " "%ld-byte block alloc'd", hi, hi-Seg__addr(seghi), Seg__size(seghi) ); VG_(pp_ExeContext)(Seg__where(seghi)); } } break; } default: VG_(tool_panic)("pp_Error: unrecognised error kind"); } }